diff --git a/apier/v1/api_interfaces.go b/apier/v1/api_interfaces.go index e296aed44..8a0d277f7 100644 --- a/apier/v1/api_interfaces.go +++ b/apier/v1/api_interfaces.go @@ -182,15 +182,6 @@ type CoreSv1Interface interface { Sleep(arg *utils.DurationArgs, reply *string) error } -type RateSv1Interface interface { - Ping(ign *utils.CGREvent, reply *string) error - CostForEvent(args *utils.ArgsCostForEvent, rpCost *utils.RateProfileCost) error -} - -type RateProfileSv1Interface interface { - Ping(ign *utils.CGREvent, reply *string) error -} - type ReplicatorSv1Interface interface { Ping(ign *utils.CGREvent, reply *string) error GetAccount(args *utils.StringWithAPIOpts, reply *engine.Account) error @@ -216,7 +207,6 @@ type ReplicatorSv1Interface interface { GetAttributeProfile(tntID *utils.TenantIDWithAPIOpts, reply *engine.AttributeProfile) error GetChargerProfile(tntID *utils.TenantIDWithAPIOpts, reply *engine.ChargerProfile) error GetDispatcherProfile(tntID *utils.TenantIDWithAPIOpts, reply *engine.DispatcherProfile) error - GetRateProfile(tntID *utils.TenantIDWithAPIOpts, reply *utils.RateProfile) error GetDispatcherHost(tntID *utils.TenantIDWithAPIOpts, reply *engine.DispatcherHost) error GetItemLoadIDs(itemID *utils.StringWithAPIOpts, reply *map[string]int64) error SetThresholdProfile(th *engine.ThresholdProfileWithAPIOpts, reply *string) error @@ -239,7 +229,6 @@ type ReplicatorSv1Interface interface { SetAttributeProfile(ap *engine.AttributeProfileWithAPIOpts, reply *string) error SetChargerProfile(cp *engine.ChargerProfileWithAPIOpts, reply *string) error SetDispatcherProfile(dpp *engine.DispatcherProfileWithAPIOpts, reply *string) error - SetRateProfile(dpp *utils.RateProfileWithAPIOpts, reply *string) error SetActionPlan(args *engine.SetActionPlanArgWithAPIOpts, reply *string) error SetAccountActionPlans(args *engine.SetAccountActionPlansArgWithAPIOpts, reply *string) error SetDispatcherHost(dpp *engine.DispatcherHostWithAPIOpts, reply *string) error @@ -266,7 +255,6 @@ type ReplicatorSv1Interface interface { RemoveChargerProfile(args *utils.TenantIDWithAPIOpts, reply *string) error RemoveDispatcherProfile(args *utils.TenantIDWithAPIOpts, reply *string) error RemoveDispatcherHost(args *utils.TenantIDWithAPIOpts, reply *string) error - RemoveRateProfile(args *utils.TenantIDWithAPIOpts, reply *string) error GetIndexes(args *utils.GetIndexesArg, reply *map[string]utils.StringSet) error SetIndexes(args *utils.SetIndexesArg, reply *string) error diff --git a/apier/v1/api_interfaces_test.go b/apier/v1/api_interfaces_test.go index 2fac17dc0..1a0b6b740 100644 --- a/apier/v1/api_interfaces_test.go +++ b/apier/v1/api_interfaces_test.go @@ -64,11 +64,6 @@ func TestResponderInterface(t *testing.T) { _ = ResponderInterface(&engine.Responder{}) } -func TestRateProfileInterface(t *testing.T) { - _ = RateProfileSv1Interface(NewDispatcherRateSv1(nil)) - _ = RateProfileSv1Interface(NewRateSv1(nil)) -} - func TestCacheSv1Interface(t *testing.T) { _ = CacheSv1Interface(NewDispatcherCacheSv1(nil)) _ = CacheSv1Interface(NewCacheSv1(nil)) @@ -113,13 +108,3 @@ func TestReplicatorSv1Interface(t *testing.T) { _ = ReplicatorSv1Interface(NewDispatcherReplicatorSv1(nil)) _ = ReplicatorSv1Interface(NewReplicatorSv1(nil, nil)) } - -func TestRateSv1Interface(t *testing.T) { - _ = RateSv1Interface(NewDispatcherRateSv1(nil)) - _ = RateSv1Interface(NewRateSv1(nil)) -} - -func TestActionSv1Interface(t *testing.T) { - _ = ActionSv1Interface(NewDispatcherActionSv1(nil)) - _ = ActionSv1Interface(NewActionSv1(nil)) -} diff --git a/apier/v1/apier.go b/apier/v1/apier.go index d3472224c..f28a77103 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -1537,7 +1537,7 @@ func (apierSv1 *APIerSv1) ExportToFolder(arg *utils.ArgExportToFolder, reply *st if len(arg.Items) == 0 { arg.Items = []string{utils.MetaAttributes, utils.MetaChargers, utils.MetaDispatchers, utils.MetaDispatcherHosts, utils.MetaFilters, utils.MetaResources, utils.MetaStats, - utils.MetaRoutes, utils.MetaThresholds, utils.MetaRateProfiles, utils.MetaActionProfiles} + utils.MetaRoutes, utils.MetaThresholds} } if _, err := os.Stat(arg.Path); os.IsNotExist(err) { os.Mkdir(arg.Path, os.ModeDir) @@ -1884,44 +1884,6 @@ func (apierSv1 *APIerSv1) ExportToFolder(arg *utils.ArgExportToFolder, reply *st } } csvWriter.Flush() - case utils.MetaRateProfiles: - prfx := utils.RateProfilePrefix - keys, err := apierSv1.DataManager.DataDB().GetKeysForPrefix(prfx) - if err != nil { - return err - } - if len(keys) == 0 { // if we don't find items we skip - continue - } - f, err := os.Create(path.Join(arg.Path, utils.RateProfilesCsv)) - if err != nil { - return err - } - defer f.Close() - - csvWriter := csv.NewWriter(f) - csvWriter.Comma = utils.CSVSep - //write the header of the file - if err := csvWriter.Write(engine.RateProfileMdls{}.CSVHeader()); err != nil { - return err - } - for _, key := range keys { - tntID := strings.SplitN(key[len(prfx):], utils.InInFieldSep, 2) - rPrf, err := apierSv1.DataManager.GetRateProfile(tntID[0], tntID[1], - true, false, utils.NonTransactional) - if err != nil { - return err - } - for _, model := range engine.APItoModelTPRateProfile(engine.RateProfileToAPI(rPrf)) { - if record, err := engine.CsvDump(model); err != nil { - return err - } else if err := csvWriter.Write(record); err != nil { - return err - } - } - } - csvWriter.Flush() - case utils.MetaActionProfiles: prfx := utils.ActionProfilePrefix keys, err := apierSv1.DataManager.DataDB().GetKeysForPrefix(prfx) diff --git a/apier/v1/cache_replication_it_test.go b/apier/v1/cache_replication_it_test.go index 4ccd6d2e2..ac1e4f471 100644 --- a/apier/v1/cache_replication_it_test.go +++ b/apier/v1/cache_replication_it_test.go @@ -50,7 +50,6 @@ var ( testCacheSReplicateRpcConn, testCacheSReplicateLoadTariffPlanFromFolder, testCacheSReplicateProcessAttributes, - testCacheSReplicateProcessRateProfile, testCacheSReplicateStopEngine, } ) @@ -172,71 +171,6 @@ func testCacheSReplicateProcessAttributes(t *testing.T) { } } -func testCacheSReplicateProcessRateProfile(t *testing.T) { - var rply *utils.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.AccountField: "1002", - }, - }, - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &utils.Rate{ - ID: "RT_ALWAYS", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(1, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - exp := &utils.RateProfileCost{ - ID: "RT_SPECIAL_1002", - Cost: 0.01, - RateSIntervals: []*utils.RateSInterval{{ - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{{ - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 60, - }}, - CompressFactor: 1, - }}, - } - if err := engine1RPC.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - } - if err := engine2RPC.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - - } -} - func testCacheSReplicateStopEngine(t *testing.T) { if err := engine.KillEngine(300); err != nil { t.Error(err) diff --git a/apier/v1/cost_bench_it_test.go b/apier/v1/cost_bench_it_test.go index 167aacbc3..52333ca91 100644 --- a/apier/v1/cost_bench_it_test.go +++ b/apier/v1/cost_bench_it_test.go @@ -94,94 +94,6 @@ func testCostBenchLoadFromFolder2(b *testing.B) { time.Sleep(500 * time.Millisecond) } -func testCostBenchSetRateProfile(b *testing.B) { - rPrf := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - ID: "DefaultRate", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";10", - Rates: map[string]*utils.APIRate{ - "RATE1": &utils.APIRate{ - ID: "RATE1", - Weights: ";0", - ActivationTimes: "* * * * *", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - FixedFee: utils.Float64Pointer(0.4), - RecurrentFee: utils.Float64Pointer(0.2), - Unit: utils.Float64Pointer(60000000000), - Increment: utils.Float64Pointer(60000000000), - }, - { - IntervalStart: "1m", - RecurrentFee: utils.Float64Pointer(0.1), - Unit: utils.Float64Pointer(60000000000), - Increment: utils.Float64Pointer(1000000000), - }, - }, - }, - }, - }, - } - var reply string - if err := costBenchRPC.Call(utils.APIerSv1SetRateProfile, rPrf, &reply); err != nil { - b.Error(err) - } else if reply != utils.OK { - b.Error("Unexpected reply returned", reply) - } -} - -func testCostBenchSetRateProfile2(b *testing.B) { - rate1 := &utils.APIRate{ - ID: "RATE1", - Weights: ";0", - ActivationTimes: "* * * * *", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - RecurrentFee: utils.Float64Pointer(0.2), - Unit: utils.Float64Pointer(60000000000), - Increment: utils.Float64Pointer(60000000000), - }, - { - IntervalStart: "1m", - RecurrentFee: utils.Float64Pointer(0.1), - Unit: utils.Float64Pointer(60000000000), - Increment: utils.Float64Pointer(1000000000), - }, - }, - } - rtChristmas := &utils.APIRate{ - ID: "RT_CHRISTMAS", - Weights: ";30", - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.APIIntervalRate{{ - IntervalStart: "0", - RecurrentFee: utils.Float64Pointer(0.6), - Unit: utils.Float64Pointer(60000000000), - Increment: utils.Float64Pointer(1000000000), - }}, - } - rPrf := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - ID: "RateChristmas", - FilterIDs: []string{"*string:~*req.Subject:1010"}, - Weights: ";50", - Rates: map[string]*utils.APIRate{ - "RATE1": rate1, - "RATE_CHRISTMAS": rtChristmas, - }, - }, - } - var reply string - if err := costBenchRPC.Call(utils.APIerSv1SetRateProfile, rPrf, &reply); err != nil { - b.Error(err) - } else if reply != utils.OK { - b.Error("Unexpected reply returned", reply) - } -} - // go test -run=^$ -tags=integration -v -bench=BenchmarkCostWithRALs -benchtime=5s func BenchmarkCostWithRALs(b *testing.B) { costBenchConfigDIR = "tutinternal" diff --git a/apier/v1/dispatcher.go b/apier/v1/dispatcher.go index f0d8290c9..aaaf0a9c3 100755 --- a/apier/v1/dispatcher.go +++ b/apier/v1/dispatcher.go @@ -1019,11 +1019,6 @@ func (dS *DispatcherReplicatorSv1) GetDispatcherProfile(tntID *utils.TenantIDWit return dS.dS.ReplicatorSv1GetDispatcherProfile(tntID, reply) } -// GetRateProfile -func (dS *DispatcherReplicatorSv1) GetRateProfile(tntID *utils.TenantIDWithAPIOpts, reply *utils.RateProfile) error { - return dS.dS.ReplicatorSv1GetRateProfile(tntID, reply) -} - // GetDispatcherHost func (dS *DispatcherReplicatorSv1) GetDispatcherHost(tntID *utils.TenantIDWithAPIOpts, reply *engine.DispatcherHost) error { return dS.dS.ReplicatorSv1GetDispatcherHost(tntID, reply) @@ -1136,11 +1131,6 @@ func (dS *DispatcherReplicatorSv1) SetDispatcherProfile(args *engine.DispatcherP return dS.dS.ReplicatorSv1SetDispatcherProfile(args, reply) } -// SetRateProfile -func (dS *DispatcherReplicatorSv1) SetRateProfile(args *utils.RateProfileWithAPIOpts, reply *string) error { - return dS.dS.ReplicatorSv1SetRateProfile(args, reply) -} - // SetActionPlan func (dS *DispatcherReplicatorSv1) SetActionPlan(args *engine.SetActionPlanArgWithAPIOpts, reply *string) error { return dS.dS.ReplicatorSv1SetActionPlan(args, reply) @@ -1271,11 +1261,6 @@ func (dS *DispatcherReplicatorSv1) RemoveDispatcherHost(args *utils.TenantIDWith return dS.dS.ReplicatorSv1RemoveDispatcherHost(args, reply) } -// RemoveRateProfile -func (dS *DispatcherReplicatorSv1) RemoveRateProfile(args *utils.TenantIDWithAPIOpts, reply *string) error { - return dS.dS.ReplicatorSv1RemoveRateProfile(args, reply) -} - // GetIndexes . func (dS *DispatcherReplicatorSv1) GetIndexes(args *utils.GetIndexesArg, reply *map[string]utils.StringSet) error { return dS.dS.ReplicatorSv1GetIndexes(args, reply) diff --git a/apier/v1/filter_indexes.go b/apier/v1/filter_indexes.go index 711da7443..e73db799a 100644 --- a/apier/v1/filter_indexes.go +++ b/apier/v1/filter_indexes.go @@ -63,14 +63,6 @@ func (apierSv1 *APIerSv1) RemoveFilterIndexes(arg *AttrRemFilterIndexes, reply * arg.ItemType = utils.CacheChargerFilterIndexes case utils.MetaActionProfiles: arg.ItemType = utils.CacheActionProfilesFilterIndexes - case utils.MetaRateProfiles: - arg.ItemType = utils.CacheRateProfilesFilterIndexes - case utils.MetaRateProfileRates: - if missing := utils.MissingStructFields(arg, []string{"Context"}); len(missing) != 0 { //Params missing - return utils.NewErrMandatoryIeMissing(missing...) - } - arg.ItemType = utils.CacheRateFilterIndexes - tntCtx = utils.ConcatenatedKey(tnt, arg.Context) case utils.MetaDispatchers: if missing := utils.MissingStructFields(arg, []string{"Context"}); len(missing) != 0 { //Params missing return utils.NewErrMandatoryIeMissing(missing...) @@ -116,14 +108,6 @@ func (apierSv1 *APIerSv1) GetFilterIndexes(arg *AttrGetFilterIndexes, reply *[]s arg.ItemType = utils.CacheChargerFilterIndexes case utils.MetaActionProfiles: arg.ItemType = utils.CacheActionProfilesFilterIndexes - case utils.MetaRateProfiles: - arg.ItemType = utils.CacheRateProfilesFilterIndexes - case utils.MetaRateProfileRates: - if missing := utils.MissingStructFields(arg, []string{"Context"}); len(missing) != 0 { //Params missing - return utils.NewErrMandatoryIeMissing(missing...) - } - arg.ItemType = utils.CacheRateFilterIndexes - tntCtx = utils.ConcatenatedKey(tnt, arg.Context) case utils.MetaDispatchers: if missing := utils.MissingStructFields(arg, []string{"Context"}); len(missing) != 0 { //Params missing return utils.NewErrMandatoryIeMissing(missing...) @@ -340,43 +324,6 @@ func (apierSv1 *APIerSv1) ComputeFilterIndexes(args *utils.ArgsComputeFilterInde return utils.APIErrorHandler(err) } } - var ratePrf []string - //RateProfile Indexes - if args.RateS { - if args.RateS, err = engine.ComputeIndexes(apierSv1.DataManager, tnt, args.Context, utils.CacheRateProfilesFilterIndexes, - nil, transactionID, func(tnt, id, ctx string) (*[]string, error) { - rpr, e := apierSv1.DataManager.GetRateProfile(tnt, id, true, false, utils.NonTransactional) - if e != nil { - return nil, e - } - ratePrf = append(ratePrf, utils.ConcatenatedKey(tnt, id)) - fltrIDs := make([]string, len(rpr.FilterIDs)) - for i, fltrID := range rpr.FilterIDs { - fltrIDs[i] = fltrID - } - - rtIds := make([]string, 0, len(rpr.Rates)) - - for key := range rpr.Rates { - rtIds = append(rtIds, key) - } - - _, e = engine.ComputeIndexes(apierSv1.DataManager, tnt, id, utils.CacheRateFilterIndexes, - &rtIds, transactionID, func(_, id, _ string) (*[]string, error) { - rateFilters := make([]string, len(rpr.Rates[id].FilterIDs)) - for i, fltrID := range rpr.Rates[id].FilterIDs { - rateFilters[i] = fltrID - } - return &rateFilters, nil - }) - if e != nil { - return nil, e - } - return &fltrIDs, nil - }); err != nil && err != utils.ErrNotFound { - return utils.APIErrorHandler(err) - } - } //ChargerProfile Indexes if args.ChargerS { if args.ChargerS, err = engine.ComputeIndexes(apierSv1.DataManager, tnt, args.Context, utils.CacheChargerFilterIndexes, @@ -450,17 +397,7 @@ func (apierSv1 *APIerSv1) ComputeFilterIndexes(args *utils.ArgsComputeFilterInde return } } - //RateProfile Indexes - if args.RateS { - if err = apierSv1.DataManager.SetIndexes(utils.CacheRateProfilesFilterIndexes, tnt, nil, true, transactionID); err != nil { - return - } - for _, val := range ratePrf { - if err = apierSv1.DataManager.SetIndexes(utils.CacheRateFilterIndexes, val, nil, true, transactionID); err != nil { - return - } - } - } + //AttributeProfile Indexes if args.AttributeS { if err = apierSv1.DataManager.SetIndexes(utils.CacheAttributeFilterIndexes, tntCtx, nil, true, transactionID); err != nil { @@ -565,38 +502,7 @@ func (apierSv1 *APIerSv1) ComputeFilterIndexIDs(args *utils.ArgsComputeFilterInd }); err != nil && err != utils.ErrNotFound { return utils.APIErrorHandler(err) } - //RateProfile Indexes - if _, err = engine.ComputeIndexes(apierSv1.DataManager, tnt, args.Context, utils.CacheRateProfilesFilterIndexes, - &args.RateProfileIDs, transactionID, func(tnt, id, ctx string) (*[]string, error) { - rpr, e := apierSv1.DataManager.GetRateProfile(tnt, id, true, false, utils.NonTransactional) - if e != nil { - return nil, e - } - fltrIDs := make([]string, len(rpr.FilterIDs)) - for i, fltrID := range rpr.FilterIDs { - fltrIDs[i] = fltrID - } - rtIds := make([]string, 0, len(rpr.Rates)) - - for key := range rpr.Rates { - rtIds = append(rtIds, key) - } - _, e = engine.ComputeIndexes(apierSv1.DataManager, tnt, id, utils.CacheRateFilterIndexes, - &rtIds, transactionID, func(_, id, _ string) (*[]string, error) { - rateFilters := make([]string, len(rpr.Rates[id].FilterIDs)) - for i, fltrID := range rpr.Rates[id].FilterIDs { - rateFilters[i] = fltrID - } - return &rateFilters, nil - }) - if e != nil { - return nil, e - } - return &fltrIDs, nil - }); err != nil && err != utils.ErrNotFound { - return utils.APIErrorHandler(err) - } //AttributeProfile Indexes if _, err = engine.ComputeIndexes(apierSv1.DataManager, tnt, args.Context, utils.CacheAttributeFilterIndexes, &args.AttributeIDs, transactionID, func(tnt, id, ctx string) (*[]string, error) { diff --git a/apier/v1/filter_indexes_it_test.go b/apier/v1/filter_indexes_it_test.go index 864683832..153a22f21 100644 --- a/apier/v1/filter_indexes_it_test.go +++ b/apier/v1/filter_indexes_it_test.go @@ -80,21 +80,6 @@ var ( testV1FIRemoveActionProfile, testV1FIdxdxInitDataDb, - testV1FISetRateProfileRatesIndexes, - testV1FIComputeRateProfileRatesIndexes, - testV1FISetSecondRateProfileRate, - testVF1ComputeIDsRateProfileRateIndexes, - testVF1RemoveRateProfileRates, - testV1FIdxdxInitDataDb, - testV1IndexClearCache, - - testV1FISetRateProfileIndexes, - testV1FIComputeRateProfileIndexes, - testV1FISetSecondRateProfile, - testV1FIComputeIDsRateProfileIndexes, - testVF1RemoveRateProfile, - testV1FIdxdxInitDataDb, - testV1FIdxSetAttributeProfileIndexes, testV1FIdxComputeAttributeProfileIndexes, testV1FIdxSetSecondAttributeProfileIndexes, @@ -1513,795 +1498,6 @@ func testV1FIRemoveActionProfile(t *testing.T) { } } -//RateProfileRate Indexes -func testV1FISetRateProfileRatesIndexes(t *testing.T) { - //set a filter for our rates - filter = &engine.FilterWithAPIOpts{ - Filter: &engine.Filter{ - Tenant: tenant, - ID: "RATE_FLTR1", - Rules: []*engine.FilterRule{{ - Type: utils.MetaString, - Element: "~*req.Destination", - Values: []string{"234"}, - }}, - }, - } - var result string - if err := tFIdxRpc.Call(utils.APIerSv1SetFilter, filter, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - //there are not any rates in db - var reply *utils.RateProfile - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP1"}}, &reply); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } - - //set in db a ratePrf with double populated rates with our filter - ratePrfRates := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Usage:10m"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - FilterIDs: []string{"RATE_FLTR1", "*suffix:~*req.Account:1009"}, - ActivationTimes: "* * * * 1-5", - }, - "RT_MONTH": { - ID: "RT_MONTH", - FilterIDs: []string{"RATE_FLTR1"}, - ActivationTimes: "* * * * *", - }, - }, - }, - } - if err := tFIdxRpc.Call(utils.APIerSv1SetRateProfile, ratePrfRates, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - expRtPrf, err := ratePrfRates.AsRateProfile() - if err != nil { - t.Error(err) - } - - //get it from db and compare - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP1"}}, - &reply); err != nil { - t.Error(err) - } else { - expRtPrf.Compile() - reply.Compile() - if !reflect.DeepEqual(reply, expRtPrf) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRtPrf), utils.ToJSON(reply)) - } - } - - //get indexes to verify if these are indexed well - var indexes []string - expectedIDx := []string{"*suffix:*req.Account:1009:RT_WEEK", "*string:*req.Destination:234:RT_WEEK", - "*string:*req.Destination:234:RT_MONTH"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } - - //get indexes only with Type *string - expectedIDx = []string{"*string:*req.Destination:234:RT_WEEK", "*string:*req.Destination:234:RT_MONTH"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, Tenant: tenant, - FilterType: utils.MetaString, Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } - - //get indexes only with Field Destination - expectedIDx = []string{"*string:*req.Destination:234:RT_WEEK", "*string:*req.Destination:234:RT_MONTH"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, Tenant: tenant, - FilterField: "*req.Destination", Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } - - //get indexes only with 1009 Destination - expectedIDx = []string{"*suffix:*req.Account:1009:RT_WEEK"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, Tenant: tenant, - FilterValue: "1009", Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testV1FIComputeRateProfileRatesIndexes(t *testing.T) { - //remove indexes from db - var result string - if err := tFIdxRpc.Call(utils.APIerSv1RemoveFilterIndexes, - &AttrRemFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected result returned", result) - } - - //nothing to get from db - var indexes []string - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) - } - - //compute them, to put indexes again in db for the right subsystem - if err := tFIdxRpc.Call(utils.APIerSv1ComputeFilterIndexes, - &utils.ArgsComputeFilterIndexes{ - Tenant: tenant, - RateS: true, - }, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - expectedIDx := []string{"*string:*req.Destination:234:RT_WEEK", - "*string:*req.Destination:234:RT_MONTH", "*suffix:*req.Account:1009:RT_WEEK"} - //as we compute them, next we will try to get them again from db - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testV1FISetSecondRateProfileRate(t *testing.T) { - //second filter for a new rate in the same rate profile - filter = &engine.FilterWithAPIOpts{ - Filter: &engine.Filter{ - Tenant: tenant, - ID: "RTPRF_FLTR3", - Rules: []*engine.FilterRule{ - { - Type: utils.MetaString, - Element: "~*req.Usage", - Values: []string{"10m", "40m", "~*opts.Usage"}, - }, - }, - }, - } - var result string - if err := tFIdxRpc.Call(utils.APIerSv1SetFilter, filter, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - //append a new rate in the same rate profile - ratePrfRates := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Usage:10m"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_YEAR": { - ID: "RT_YEAR", - FilterIDs: []string{"RTPRF_FLTR3"}, - ActivationTimes: "* * * * *", - }, - }, - }, - } - expRatePrf := utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Usage:10m"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - FilterIDs: []string{"RATE_FLTR1", "*suffix:~*req.Account:1009"}, - ActivationTimes: "* * * * 1-5", - }, - "RT_MONTH": { - ID: "RT_MONTH", - FilterIDs: []string{"RATE_FLTR1"}, - ActivationTimes: "* * * * *", - }, - "RT_YEAR": { - ID: "RT_YEAR", - FilterIDs: []string{"RTPRF_FLTR3"}, - ActivationTimes: "* * * * *", - }, - }, - } - if err := tFIdxRpc.Call(utils.APIerSv1SetRateProfileRates, ratePrfRates, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Errorf("unexpected reply returned") - } - - //get it from db and compare - var reply utils.RateProfile - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP1"}}, - &reply); err != nil { - t.Error(err) - } else { - expRatePrf.Compile() - reply.Compile() - if !reflect.DeepEqual(reply, expRatePrf) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRatePrf), utils.ToJSON(reply)) - } - } - - var indexes []string - expectedIDx := []string{"*string:*req.Destination:234:RT_WEEK", - "*string:*req.Destination:234:RT_MONTH", "*suffix:*req.Account:1009:RT_WEEK", - "*string:*req.Usage:10m:RT_YEAR", "*string:*req.Usage:40m:RT_YEAR"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testVF1ComputeIDsRateProfileRateIndexes(t *testing.T) { - //remove indexes - var result string - if err := tFIdxRpc.Call(utils.APIerSv1RemoveFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - var indexes []string - //nothing to get from db, as we removed them, - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } - - //compute indexes for all three rates by ids - if err := tFIdxRpc.Call(utils.APIerSv1ComputeFilterIndexIDs, - &utils.ArgsComputeFilterIndexIDs{ - Tenant: tenant, - RateProfileIDs: []string{"RP1"}, - }, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - expectedIDx := []string{"*string:*req.Destination:234:RT_WEEK", - "*string:*req.Destination:234:RT_MONTH", "*suffix:*req.Account:1009:RT_WEEK", - "*string:*req.Usage:10m:RT_YEAR", "*string:*req.Usage:40m:RT_YEAR"} - //as we compute them, next we will try to get them again from db - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testVF1RemoveRateProfileRates(t *testing.T) { - //removing rates from db will delete the indexes from db - var result string - if err := tFIdxRpc.Call(utils.APIerSv1RemoveRateProfileRates, - &RemoveRPrfRatesWithAPIOpts{ID: "RP1", - Tenant: tenant, RateIDs: []string{"RT_WEEK", "RT_YEAR"}}, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected result returned", result) - } - - expRatePrf := utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Usage:10m"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_MONTH": { - ID: "RT_MONTH", - FilterIDs: []string{"RATE_FLTR1"}, - ActivationTimes: "* * * * *", - }, - }, - } - - var reply utils.RateProfile - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP1"}}, - &reply); err != nil { - t.Error(err) - } else { - expRatePrf.Compile() - reply.Compile() - if !reflect.DeepEqual(reply, expRatePrf) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRatePrf), utils.ToJSON(reply)) - } - } - - //compute the indexes only for the left rate - if err := tFIdxRpc.Call(utils.APIerSv1ComputeFilterIndexIDs, - &utils.ArgsComputeFilterIndexIDs{ - Tenant: tenant, - RateProfileIDs: []string{"RP1"}, - }, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - expectedIDx := []string{"*string:*req.Destination:234:RT_MONTH"} - //as we compute them, next we will try to get them again from db - var indexes []string - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } - - //no we will remove the left rate and the profile - if err := tFIdxRpc.Call(utils.APIerSv1RemoveRateProfileRates, - &RemoveRPrfRatesWithAPIOpts{ID: "RP1", - Tenant: tenant, RateIDs: []string{"RT_MONTH"}}, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected result returned", result) - } - - //no indexes in db - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfileRates, - Tenant: tenant, Context: "RP1"}, - &indexes); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } - -} - -//RateProfile Indexes -func testV1FISetRateProfileIndexes(t *testing.T) { - //set a filter for our rates - filter = &engine.FilterWithAPIOpts{ - Filter: &engine.Filter{ - Tenant: tenant, - ID: "RATEFLTR_FLTR1", - Rules: []*engine.FilterRule{ - { - Type: utils.MetaString, - Element: "~*req.OriginID", - Values: []string{"~*opts.Account", "ID1"}, - }, - { - Type: utils.MetaPrefix, - Element: "~*req.Destination", - Values: []string{"~*opts.Account", "123"}, - }, - }, - }, - } - var result string - if err := tFIdxRpc.Call(utils.APIerSv1SetFilter, filter, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - //there are not any rates in db - var reply *utils.RateProfile - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP2"}}, &reply); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } - //set in db a ratePrf with with our filterS - ratePrfRates := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: "RP2", - FilterIDs: []string{"*string:~*req.Usage:10m", "RATEFLTR_FLTR1"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - FilterIDs: []string{"*suffix:~*req.Account:1009"}, - ActivationTimes: "* * * * 1-5", - }, - }, - }, - } - if err := tFIdxRpc.Call(utils.APIerSv1SetRateProfile, ratePrfRates, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - expRtPrf, err := ratePrfRates.AsRateProfile() - if err != nil { - t.Error(err) - } - - //get it from db and compare - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP2"}}, - &reply); err != nil { - t.Error(err) - } else { - expRtPrf.Compile() - reply.Compile() - if !reflect.DeepEqual(reply, expRtPrf) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRtPrf), utils.ToJSON(reply)) - } - } - - //get indexes to verify if these are indexed well - var indexes []string - expectedIDx := []string{"*string:*req.OriginID:ID1:RP2", "*prefix:*req.Destination:123:RP2", - "*string:*req.Usage:10m:RP2"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } - - //get indexes only with Type *string - expectedIDx = []string{"*string:*req.OriginID:ID1:RP2", - "*string:*req.Usage:10m:RP2"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, Tenant: tenant, - FilterType: utils.MetaString}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } - - //get indexes only with Field OriginID - expectedIDx = []string{"*string:*req.OriginID:ID1:RP2"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, Tenant: tenant, - FilterField: "*req.OriginID"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } - - //get indexes only with 10m - expectedIDx = []string{"*string:*req.Usage:10m:RP2"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, Tenant: tenant, - FilterValue: "10m"}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testV1FIComputeRateProfileIndexes(t *testing.T) { - //remove indexes from db - var result string - if err := tFIdxRpc.Call(utils.APIerSv1RemoveFilterIndexes, - &AttrRemFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected result returned", result) - } - - //nothing to get from db - var indexes []string - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &indexes); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) - } - - //compute them, to put indexes again in db for the right subsystem - if err := tFIdxRpc.Call(utils.APIerSv1ComputeFilterIndexes, - &utils.ArgsComputeFilterIndexes{ - Tenant: tenant, - RateS: true, - }, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - expectedIDx := []string{"*string:*req.OriginID:ID1:RP2", "*prefix:*req.Destination:123:RP2", - "*string:*req.Usage:10m:RP2"} - //as we compute them, next we will try to get them again from db - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testV1FISetSecondRateProfile(t *testing.T) { - //second filter for a new rate profile - filter = &engine.FilterWithAPIOpts{ - Filter: &engine.Filter{ - Tenant: tenant, - ID: "RTPRF_FLTR6", - Rules: []*engine.FilterRule{ - { - Type: utils.MetaString, - Element: "~*req.ToR", - Values: []string{"*sms", "~*opts.Usage"}, - }, - }, - }, - } - var result string - if err := tFIdxRpc.Call(utils.APIerSv1SetFilter, filter, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - //another rate profile - ratePrfRates := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: "RP3", - FilterIDs: []string{"RTPRF_FLTR6"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - FilterIDs: []string{"*suffix:~*req.Account:1019"}, - ActivationTimes: "* * * * 1-5", - }, - }, - }, - } - if err := tFIdxRpc.Call(utils.APIerSv1SetRateProfile, ratePrfRates, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Errorf("unexpected reply returned") - } - expRatePrf := utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP3", - FilterIDs: []string{"RTPRF_FLTR6"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - FilterIDs: []string{"*suffix:~*req.Account:1019"}, - ActivationTimes: "* * * * 1-5", - }, - }, - } - //get it from db and compare - var reply utils.RateProfile - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP3"}}, - &reply); err != nil { - t.Error(err) - } else { - expRatePrf.Compile() - reply.Compile() - if !reflect.DeepEqual(reply, expRatePrf) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expRatePrf), utils.ToJSON(reply)) - } - } - - var indexes []string - expectedIDx := []string{"*string:*req.OriginID:ID1:RP2", "*prefix:*req.Destination:123:RP2", - "*string:*req.Usage:10m:RP2", "*string:*req.ToR:*sms:RP3"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testV1FIComputeIDsRateProfileIndexes(t *testing.T) { - //remove indexes from db - var result string - if err := tFIdxRpc.Call(utils.APIerSv1RemoveFilterIndexes, - &AttrRemFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected result returned", result) - } - - //nothing to get from db - var indexes []string - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &indexes); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) - } - - //compute them, to put indexes again in db for the right subsystem - if err := tFIdxRpc.Call(utils.APIerSv1ComputeFilterIndexIDs, - &utils.ArgsComputeFilterIndexIDs{ - Tenant: tenant, - RateProfileIDs: []string{"RP3", "RP2"}, - }, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - - expectedIDx := []string{"*string:*req.OriginID:ID1:RP2", "*prefix:*req.Destination:123:RP2", - "*string:*req.Usage:10m:RP2", "*string:*req.ToR:*sms:RP3"} - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, - &AttrGetFilterIndexes{ItemType: utils.MetaRateProfiles, - Tenant: tenant}, - &indexes); err != nil { - t.Error(err) - } else { - sort.Strings(expectedIDx) - sort.Strings(indexes) - if !reflect.DeepEqual(indexes, expectedIDx) { - t.Errorf("Expected %+v, received %+v", expectedIDx, indexes) - } - } -} - -func testVF1RemoveRateProfile(t *testing.T) { - //removing rate profile from db will delete the indexes from db - var result string - if err := tFIdxRpc.Call(utils.APIerSv1RemoveRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{ - ID: "RP2", - Tenant: tenant}, - }, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected result returned", result) - } - - if err := tFIdxRpc.Call(utils.APIerSv1RemoveRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{ - ID: "RP3", - Tenant: tenant}}, - &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected result returned", result) - } - - //nothing to get from db - var reply utils.RateProfile - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP2"}}, - &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } - - if err := tFIdxRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tenant, ID: "RP3"}}, - &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } - - //as we removed our profiles, the indexes are removed as well - var indexes []string - if err := tFIdxRpc.Call(utils.APIerSv1GetFilterIndexes, &AttrGetFilterIndexes{ - ItemType: utils.MetaRateProfiles, Tenant: tenant}, - &indexes); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } -} - //AttributeProfile Indexes func testV1FIdxSetAttributeProfileIndexes(t *testing.T) { var reply *engine.AttributeProfile diff --git a/apier/v1/rateprofiles.go b/apier/v1/rateprofiles.go deleted file mode 100644 index ed4dea0d2..000000000 --- a/apier/v1/rateprofiles.go +++ /dev/null @@ -1,221 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package v1 - -import ( - "time" - - "github.com/cgrates/cgrates/rates" - - "github.com/cgrates/cgrates/utils" -) - -// GetRateProfile returns an Rate Profile -func (apierSv1 *APIerSv1) GetRateProfile(arg *utils.TenantIDWithAPIOpts, reply *utils.RateProfile) error { - if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing - return utils.NewErrMandatoryIeMissing(missing...) - } - tnt := arg.Tenant - if tnt == utils.EmptyString { - tnt = apierSv1.Config.GeneralCfg().DefaultTenant - } - rPrf, err := apierSv1.DataManager.GetRateProfile(tnt, arg.ID, true, true, utils.NonTransactional) - if err != nil { - if err.Error() != utils.ErrNotFound.Error() { - err = utils.NewErrServerError(err) - } - return err - } - *reply = *rPrf - return nil -} - -// GetRateProfileIDs returns list of rate profile IDs registered for a tenant -func (apierSv1 *APIerSv1) GetRateProfileIDs(args *utils.PaginatorWithTenant, attrPrfIDs *[]string) error { - tnt := args.Tenant - if tnt == utils.EmptyString { - tnt = apierSv1.Config.GeneralCfg().DefaultTenant - } - prfx := utils.RateProfilePrefix + tnt + utils.ConcatenatedKeySep - keys, err := apierSv1.DataManager.DataDB().GetKeysForPrefix(prfx) - if err != nil { - return err - } - if len(keys) == 0 { - return utils.ErrNotFound - } - retIDs := make([]string, len(keys)) - for i, key := range keys { - retIDs[i] = key[len(prfx):] - } - *attrPrfIDs = args.PaginateStringSlice(retIDs) - return nil -} - -// GetRateProfileIDsCount sets in reply var the total number of RateProfileIDs registered for a tenant -// returns ErrNotFound in case of 0 RateProfileIDs -func (apierSv1 *APIerSv1) GetRateProfileIDsCount(args *utils.TenantWithAPIOpts, reply *int) (err error) { - tnt := args.Tenant - if tnt == utils.EmptyString { - tnt = apierSv1.Config.GeneralCfg().DefaultTenant - } - var keys []string - prfx := utils.RateProfilePrefix + tnt + utils.ConcatenatedKeySep - if keys, err = apierSv1.DataManager.DataDB().GetKeysForPrefix(prfx); err != nil { - return err - } - if len(keys) == 0 { - return utils.ErrNotFound - } - *reply = len(keys) - return -} - -//SetRateProfile add/update a new Rate Profile -func (apierSv1 *APIerSv1) SetRateProfile(ext *utils.APIRateProfileWithAPIOpts, reply *string) error { - if missing := utils.MissingStructFields(ext.APIRateProfile, []string{utils.ID, utils.Rates}); len(missing) != 0 { - return utils.NewErrMandatoryIeMissing(missing...) - } - if ext.Tenant == utils.EmptyString { - ext.Tenant = apierSv1.Config.GeneralCfg().DefaultTenant - } - rPrf, err := ext.AsRateProfile() - if err != nil { - return err - } - if err := apierSv1.DataManager.SetRateProfile(rPrf, true); err != nil { - return utils.APIErrorHandler(err) - } - //generate a loadID for CacheRateProfiles and store it in database - if err := apierSv1.DataManager.SetLoadIDs(map[string]int64{utils.CacheRateProfiles: time.Now().UnixNano()}); err != nil { - return utils.APIErrorHandler(err) - } - if err := apierSv1.CallCache(utils.IfaceAsString(ext.APIOpts[utils.CacheOpt]), rPrf.Tenant, utils.CacheRateProfiles, - rPrf.TenantID(), &rPrf.FilterIDs, nil, ext.APIOpts); err != nil { - return utils.APIErrorHandler(err) - } - *reply = utils.OK - return nil -} - -//SetRateProfileRates add/update Rates from existing RateProfiles -func (apierSv1 *APIerSv1) SetRateProfileRates(ext *utils.APIRateProfileWithAPIOpts, reply *string) (err error) { - if missing := utils.MissingStructFields(ext.APIRateProfile, []string{utils.ID, utils.Rates}); len(missing) != 0 { - return utils.NewErrMandatoryIeMissing(missing...) - } - if ext.Tenant == utils.EmptyString { - ext.Tenant = apierSv1.Config.GeneralCfg().DefaultTenant - } - rPrf, err := ext.AsRateProfile() - if err != nil { - return err - } - if err = apierSv1.DataManager.SetRateProfileRates(rPrf, true); err != nil { - return utils.APIErrorHandler(err) - } - //generate a loadID for CacheRateProfiles and store it in database - if err = apierSv1.DataManager.SetLoadIDs(map[string]int64{utils.CacheRateProfiles: time.Now().UnixNano()}); err != nil { - return utils.APIErrorHandler(err) - } - if err = apierSv1.CallCache(utils.IfaceAsString(ext.APIOpts[utils.CacheOpt]), rPrf.Tenant, utils.CacheRateProfiles, - rPrf.TenantID(), &rPrf.FilterIDs, nil, ext.APIOpts); err != nil { - return utils.APIErrorHandler(err) - } - *reply = utils.OK - return nil -} - -type RemoveRPrfRatesWithAPIOpts struct { - Tenant string - ID string - RateIDs []string - APIOpts map[string]interface{} -} - -func (apierSv1 *APIerSv1) RemoveRateProfileRates(args *RemoveRPrfRatesWithAPIOpts, reply *string) (err error) { - if missing := utils.MissingStructFields(args, []string{utils.ID}); len(missing) != 0 { - return utils.NewErrMandatoryIeMissing(missing...) - } - tnt := args.Tenant - if tnt == utils.EmptyString { - tnt = apierSv1.Config.GeneralCfg().DefaultTenant - } - if err := apierSv1.DataManager.RemoveRateProfileRates(tnt, args.ID, args.RateIDs, true); err != nil { - return utils.APIErrorHandler(err) - } - //generate a loadID for CacheRateProfiles and store it in database - if err := apierSv1.DataManager.SetLoadIDs(map[string]int64{utils.CacheRateProfiles: time.Now().UnixNano()}); err != nil { - return utils.APIErrorHandler(err) - } - if err := apierSv1.CallCache(utils.IfaceAsString(args.APIOpts[utils.CacheOpt]), tnt, utils.CacheRateProfiles, - utils.ConcatenatedKey(tnt, args.ID), nil, nil, args.APIOpts); err != nil { - return utils.APIErrorHandler(err) - } - *reply = utils.OK - return nil -} - -// RemoveRateProfile remove a specific Rate Profile -func (apierSv1 *APIerSv1) RemoveRateProfile(arg *utils.TenantIDWithAPIOpts, reply *string) error { - if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing - return utils.NewErrMandatoryIeMissing(missing...) - } - tnt := arg.Tenant - if tnt == utils.EmptyString { - tnt = apierSv1.Config.GeneralCfg().DefaultTenant - } - if err := apierSv1.DataManager.RemoveRateProfile(tnt, arg.ID, - utils.NonTransactional, true); err != nil { - return utils.APIErrorHandler(err) - } - //generate a loadID for CacheAttributeProfiles and store it in database - if err := apierSv1.DataManager.SetLoadIDs(map[string]int64{utils.CacheRateProfiles: time.Now().UnixNano()}); err != nil { - return utils.APIErrorHandler(err) - } - if err := apierSv1.CallCache(utils.IfaceAsString(arg.APIOpts[utils.CacheOpt]), tnt, utils.CacheRateProfiles, - utils.ConcatenatedKey(tnt, arg.ID), nil, nil, arg.APIOpts); err != nil { - return utils.APIErrorHandler(err) - } - *reply = utils.OK - return nil -} - -func NewRateSv1(rateS *rates.RateS) *RateSv1 { - return &RateSv1{rS: rateS} -} - -// Exports RPC from RLs -type RateSv1 struct { - rS *rates.RateS -} - -// Call implements rpcclient.ClientConnector interface for internal RPC -func (rSv1 *RateSv1) Call(serviceMethod string, - args interface{}, reply interface{}) error { - return utils.APIerRPCCall(rSv1, serviceMethod, args, reply) -} - -func (rSv1 *RateSv1) CostForEvent(args *utils.ArgsCostForEvent, rpCost *utils.RateProfileCost) (err error) { - return rSv1.rS.V1CostForEvent(args, rpCost) -} - -func (rSv1 *RateSv1) Ping(ign *utils.CGREvent, reply *string) error { - *reply = utils.Pong - return nil -} diff --git a/apier/v1/rateprofiles_it_test.go b/apier/v1/rateprofiles_it_test.go deleted file mode 100644 index 99f0cb2ed..000000000 --- a/apier/v1/rateprofiles_it_test.go +++ /dev/null @@ -1,1602 +0,0 @@ -// +build integration - -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package v1 - -import ( - "net/rpc" - "path" - "reflect" - "testing" - "time" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" -) - -var ( - ratePrfCfgPath string - ratePrfCfg *config.CGRConfig - ratePrfRpc *rpc.Client - ratePrfConfDIR string //run tests for specific configuration - - sTestsRatePrf = []func(t *testing.T){ - testV1RatePrfLoadConfig, - testV1RatePrfInitDataDb, - testV1RatePrfResetStorDb, - testV1RatePrfStartEngine, - testV1RatePrfRpcConn, - testV1RatePrfNotFound, - testV1RatePrfFromFolder, - testV1RatePrfGetRateProfileIDs, - testV1RatePrfGetRateProfileIDsCount, - testV1RatePrfVerifyRateProfile, - testV1RatePrfRemoveRateProfile, - testV1RatePrfNotFound, - testV1RatePrfSetRateProfileRates, - testV1RatePrfRemoveRateProfileRates, - testV1RatePing, - testV1RateGetRemoveRateProfileWithoutTenant, - testV1RatePrfRemoveRateProfileWithoutTenant, - testV1RatePrfGetRateProfileRatesWithoutTenant, - testV1RatePrfRemoveRateProfileRatesWithoutTenant, - testV1RateCostForEventWithDefault, - testV1RateCostForEventWithUsage, - testV1RateCostForEventWithWrongUsage, - testV1RateCostForEventWithStartTime, - testV1RateCostForEventWithWrongStartTime, - testV1RateCostForEventWithOpts, - //testV1RateCostForEventSpecial, - //testV1RateCostForEventThreeRates, - testV1RatePrfStopEngine, - } -) - -//Test start here -func TestRatePrfIT(t *testing.T) { - switch *dbType { - case utils.MetaInternal: - ratePrfConfDIR = "tutinternal" - case utils.MetaMySQL: - ratePrfConfDIR = "tutmysql" - case utils.MetaMongo: - ratePrfConfDIR = "tutmongo" - case utils.MetaPostgres: - t.SkipNow() - default: - t.Fatal("Unknown Database type") - } - for _, stest := range sTestsRatePrf { - t.Run(ratePrfConfDIR, stest) - } -} - -func testV1RatePrfLoadConfig(t *testing.T) { - var err error - ratePrfCfgPath = path.Join(*dataDir, "conf", "samples", ratePrfConfDIR) - if ratePrfCfg, err = config.NewCGRConfigFromPath(ratePrfCfgPath); err != nil { - t.Error(err) - } -} - -func testV1RatePrfInitDataDb(t *testing.T) { - if err := engine.InitDataDb(ratePrfCfg); err != nil { - t.Fatal(err) - } -} - -// Wipe out the cdr database -func testV1RatePrfResetStorDb(t *testing.T) { - if err := engine.InitStorDb(ratePrfCfg); err != nil { - t.Fatal(err) - } -} - -func testV1RatePrfStartEngine(t *testing.T) { - if _, err := engine.StopStartEngine(ratePrfCfgPath, *waitRater); err != nil { - t.Fatal(err) - } -} - -func testV1RatePrfRpcConn(t *testing.T) { - var err error - ratePrfRpc, err = newRPCClient(ratePrfCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed - if err != nil { - t.Fatal("Could not connect to rater: ", err.Error()) - } -} - -func testV1RatePrfNotFound(t *testing.T) { - var reply *utils.RateProfile - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RP1"}}, - &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } -} - -func testV1RatePrfFromFolder(t *testing.T) { - var reply string - attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutrates")} - if err := ratePrfRpc.Call(utils.APIerSv1LoadTariffPlanFromFolder, attrs, &reply); err != nil { - t.Error(err) - } - time.Sleep(100 * time.Millisecond) -} - -func testV1RatePrfVerifyRateProfile(t *testing.T) { - var reply *utils.RateProfile - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RP1"}}, &reply); err != nil { - t.Fatal(err) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - if !reflect.DeepEqual(rPrf, rPrf) { - t.Errorf("Expecting: %+v, received: %+v", - utils.ToJSON(rPrf), utils.ToJSON(rPrf)) - } -} - -func testV1RatePrfRemoveRateProfile(t *testing.T) { - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1RemoveRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RP1"}}, &reply); err != nil { - t.Fatal(err) - } else if reply != utils.OK { - t.Errorf("Expecting: %+v, received: %+v", utils.OK, reply) - } -} - -func testV1RatePrfSetRateProfileRates(t *testing.T) { - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*wrong:inline"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - if err := rPrf.Compile(); err != nil { - t.Fatal(err) - } - apiRPrf := &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*wrong:inline"}, - Weights: ";0", - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - }, - }, - }, - } - var reply string - expErr := "SERVER_ERROR: broken reference to filter: *wrong:inline for item with ID: cgrates.org:RP1" - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfile, - &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: apiRPrf, - }, &reply); err == nil || err.Error() != expErr { - t.Fatalf("Expected error: %q, received: %v", expErr, err) - } - apiRPrf.FilterIDs = []string{"*string:~*req.Subject:1001"} - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfile, - &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: apiRPrf, - }, &reply); err != nil { - t.Fatal(err) - } else if reply != utils.OK { - t.Errorf("Expecting: %+v, received: %+v", utils.OK, reply) - } - - apiRPrfRates := &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - { - IntervalStart: "1m", - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: ";10", - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: ";30", - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - }, - }, - }, - } - - apiRPrfRates.Rates["RT_WEEK"].FilterIDs = []string{"*wrong:inline"} - expErr = "SERVER_ERROR: broken reference to filter: *wrong:inline for rate with ID: RT_WEEK" - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfileRates, - &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: apiRPrfRates, - }, &reply); err == nil || err.Error() != expErr { - t.Fatalf("Expected error: %q, received: %v", expErr, err) - } - apiRPrfRates.Rates["RT_WEEK"].FilterIDs = nil - - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfileRates, - &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: apiRPrfRates, - }, &reply); err != nil { - t.Fatal(err) - } else if reply != utils.OK { - t.Errorf("Expecting: %+v, received: %+v", utils.OK, reply) - } - - rPrfUpdated := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - var rply *utils.RateProfile - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "RP1"}}, &rply); err != nil { - t.Fatal(err) - } else if !reflect.DeepEqual(rPrfUpdated, rply) { - t.Errorf("Expecting: %+v, \n received: %+v", - utils.ToJSON(rPrfUpdated), utils.ToJSON(rply)) - } -} - -func testV1RatePrfRemoveRateProfileRates(t *testing.T) { - apiRPrf := &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: "SpecialRate", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - { - IntervalStart: "1m", - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: ";10", - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: ";30", - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - }, - }, - }, - } - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfile, - &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: apiRPrf, - }, &reply); err != nil { - t.Fatal(err) - } else if reply != utils.OK { - t.Errorf("Expecting: %+v, received: %+v", utils.OK, reply) - } - - if err := ratePrfRpc.Call(utils.APIerSv1RemoveRateProfileRates, - &RemoveRPrfRatesWithAPIOpts{ - Tenant: "cgrates.org", - ID: "SpecialRate", - RateIDs: []string{"RT_WEEKEND"}, - }, &reply); err != nil { - t.Fatal(err) - } else if reply != utils.OK { - t.Errorf("Expecting: %+v, received: %+v", utils.OK, reply) - } - - rPrfUpdated := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "SpecialRate", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - var rply *utils.RateProfile - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "SpecialRate"}}, &rply); err != nil { - t.Fatal(err) - } else if !reflect.DeepEqual(rPrfUpdated, rply) { - t.Errorf("Expecting: %+v, \n received: %+v", - utils.ToJSON(rPrfUpdated), utils.ToJSON(rply)) - } - - if err := ratePrfRpc.Call(utils.APIerSv1RemoveRateProfileRates, - &RemoveRPrfRatesWithAPIOpts{ - Tenant: "cgrates.org", - ID: "SpecialRate", - }, &reply); err != nil { - t.Fatal(err) - } else if reply != utils.OK { - t.Errorf("Expecting: %+v, received: %+v", utils.OK, reply) - } - - rPrfUpdated2 := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "SpecialRate", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{}, - } - var rply2 *utils.RateProfile - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "SpecialRate"}}, &rply2); err != nil { - t.Fatal(err) - } else if !reflect.DeepEqual(rPrfUpdated2, rply2) { - t.Errorf("Expecting: %+v, \n received: %+v", - utils.ToJSON(rPrfUpdated2), utils.ToJSON(rply2)) - } -} - -func testV1RatePing(t *testing.T) { - var resp string - if err := ratePrfRpc.Call(utils.RateSv1Ping, new(utils.CGREvent), &resp); err != nil { - t.Error(err) - } else if resp != utils.Pong { - t.Error("Unexpected reply returned", resp) - } -} - -func testV1RatePrfStopEngine(t *testing.T) { - if err := engine.KillEngine(*waitRater); err != nil { - t.Error(err) - } -} - -func testV1RateGetRemoveRateProfileWithoutTenant(t *testing.T) { - rateProfile := &utils.RateProfile{ - ID: "RPWithoutTenant", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - if *encoding == utils.MetaGOB { - rateProfile.Rates["RT_WEEK"].FilterIDs = nil - } - apiRPrf := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - ID: "RPWithoutTenant", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - }, - }, - }, - }, - } - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfile, apiRPrf, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Error("Unexpected reply returned", reply) - } - var result *utils.RateProfile - rateProfile.Tenant = "cgrates.org" - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{ID: "RPWithoutTenant"}}, - &result); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(result, rateProfile) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(rateProfile), utils.ToJSON(result)) - } -} - -func testV1RatePrfRemoveRateProfileWithoutTenant(t *testing.T) { - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1RemoveRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{ID: "RPWithoutTenant"}}, - &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Error("Unexpected reply returned", reply) - } - var result *utils.RateProfile - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{ID: "RPWithoutTenant"}}, - &result); err == nil || err.Error() != utils.ErrNotFound.Error() { - t.Error(err) - } -} - -func testV1RatePrfGetRateProfileIDs(t *testing.T) { - var result []string - expected := []string{"RP1"} - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfileIDs, - &utils.PaginatorWithTenant{}, - &result); err != nil { - t.Error(err) - } else if len(result) != len(expected) { - t.Errorf("Expected %+v \n, received %+v", expected, result) - } - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfileIDs, - &utils.PaginatorWithTenant{Tenant: "cgrates.org"}, - &result); err != nil { - t.Error(err) - } else if len(result) != len(expected) { - t.Errorf("Expected %+v \n, received %+v", expected, result) - } -} - -func testV1RatePrfGetRateProfileIDsCount(t *testing.T) { - var reply int - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfileIDsCount, - &utils.TenantWithAPIOpts{}, - &reply); err != nil { - t.Error(err) - } else if reply != 1 { - t.Errorf("Expected 1, received %+v", reply) - } - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfileIDsCount, - &utils.TenantWithAPIOpts{Tenant: "cgrates.org"}, - &reply); err != nil { - t.Error(err) - } else if reply != 1 { - t.Errorf("Expected 1, received %+v", reply) - } -} - -func testV1RatePrfGetRateProfileRatesWithoutTenant(t *testing.T) { - rPrf := &utils.RateProfile{ - ID: "SpecialRate", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - }, - }, - } - apiRPrf := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - ID: "SpecialRate", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: ";10", - ActivationTimes: "* * * * 0,6", - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: ";30", - ActivationTimes: "* * 24 12 *", - }, - }, - }, - } - if *encoding == utils.MetaGOB { - rPrf.Rates["RT_WEEK"].FilterIDs = nil - rPrf.Rates["RT_WEEKEND"].FilterIDs = nil - rPrf.Rates["RT_CHRISTMAS"].FilterIDs = nil - } - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfileRates, apiRPrf, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Error("Unexpected reply returned", reply) - } - rPrf.Tenant = "cgrates.org" - var rply *utils.RateProfile - if err := ratePrfRpc.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{ID: "SpecialRate"}}, - &rply); err != nil { - t.Fatal(err) - } else if !reflect.DeepEqual(rPrf, rply) { - t.Errorf("Expecting: %+v, \n received: %+v", utils.ToJSON(rPrf), utils.ToJSON(rply)) - } -} - -func testV1RatePrfRemoveRateProfileRatesWithoutTenant(t *testing.T) { - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1RemoveRateProfileRates, - &RemoveRPrfRatesWithAPIOpts{ID: "SpecialRate"}, - &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Error("Unexpected reply returned", reply) - } -} - -func testV1RateCostForEventWithDefault(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &utils.Rate{ - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rPrf := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - ID: "DefaultRate", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";10", - Rates: map[string]*utils.APIRate{ - "RATE1": &utils.APIRate{ - ID: "RATE1", - Weights: ";0", - ActivationTimes: "* * * * *", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - RecurrentFee: utils.Float64Pointer(0.12), - Unit: utils.Float64Pointer(60000000000), - Increment: utils.Float64Pointer(60000000000), - }, - { - IntervalStart: "1m", - RecurrentFee: utils.Float64Pointer(0.06), - Unit: utils.Float64Pointer(60000000000), - Increment: utils.Float64Pointer(1000000000), - }, - }, - }, - }, - }, - } - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfile, rPrf, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Error("Unexpected reply returned", reply) - } - - var rply *utils.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - }, - } - exp := &utils.RateProfileCost{ - ID: "DefaultRate", - Cost: 0.12, - RateSIntervals: []*utils.RateSInterval{{ - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{{ - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }}, - CompressFactor: 1, - }}, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - } -} - -func testV1RateCostForEventWithUsage(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - var rply *utils.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesUsage: "2m10s", - }, - }, - } - rate1 := &utils.Rate{ - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - exp := &utils.RateProfileCost{ - ID: "DefaultRate", - Cost: 0.19, - RateSIntervals: []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Usage: utils.NewDecimal(int64(time.Minute+10*time.Second), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 70, - }, - }, - CompressFactor: 1, - }, - }, - } - - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - } - - argsRt2 := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesUsage: "4h10m15s", - }, - }, - } - exp2 := &utils.RateProfileCost{ - ID: "DefaultRate", - Cost: 15.075, - RateSIntervals: []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Usage: utils.NewDecimal(int64(4*time.Hour+9*time.Minute+15*time.Second), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 14955, - }, - }, - CompressFactor: 1, - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt2, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp2, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp2), utils.ToJSON(rply)) - } -} - -func testV1RateCostForEventWithWrongUsage(t *testing.T) { - var rply *utils.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesUsage: "wrongUsage", - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err == nil || - err.Error() != "SERVER_ERROR: can't convert to decimal" { - t.Errorf("Expected %+v \n, received %+v", "SERVER_ERROR: time: invalid duration \"wrongUsage\"", err) - } -} - -func testV1RateCostForEventWithStartTime(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &utils.Rate{ - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - var rply *utils.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), - }, - }, - } - exp := &utils.RateProfileCost{ - ID: "DefaultRate", - Cost: 0.12, - RateSIntervals: []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - }, - CompressFactor: 1, - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - } - - argsRt2 := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC).String(), - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt2, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - } -} - -func testV1RateCostForEventWithWrongStartTime(t *testing.T) { - var rply *utils.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: "wrongTime", - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err == nil || - err.Error() != "SERVER_ERROR: Unsupported time format" { - t.Errorf("Expected %+v \n, received %+v", "SERVER_ERROR: Unsupported time format", err) - } -} - -func testV1RateCostForEventWithOpts(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - var rply *utils.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), - utils.OptsRatesUsage: "2m10s", - }, - }, - } - rate1 := &utils.Rate{ - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - exp := &utils.RateProfileCost{ - ID: "DefaultRate", - Cost: 0.19, - RateSIntervals: []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Usage: utils.NewDecimal(int64(time.Minute+10*time.Second), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 70, - }, - }, - CompressFactor: 1, - }, - }, - } - - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - } - - argsRt2 := &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), - utils.OptsRatesUsage: "4h10m15s", - }, - }, - } - exp2 := &utils.RateProfileCost{ - ID: "DefaultRate", - Cost: 15.075, - RateSIntervals: []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Usage: utils.NewDecimal(int64(4*time.Hour+9*time.Minute+15*time.Second), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 14955, - }, - }, - CompressFactor: 1, - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt2, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp2, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp2), utils.ToJSON(rply)) - } -} - -/* -func testV1RateCostForEventSpecial(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &engine.Rate{ - ID: "RATE1", - Weight: 0, - ActivationTimes: "* * * * *", - IntervalRates: []*engine.IntervalRate{ - { - IntervalStart: 0, - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: time.Minute, - RecurrentFee: utils.NewDecimal(1, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rtChristmas := &engine.Rate{ - ID: "RT_CHRISTMAS", - Weight: 30, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*engine.IntervalRate{{ - IntervalStart: 0, - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }}, - } - rPrf := &engine.RateProfileWithOpts{ - RateProfileWithOpts: &engine.RateProfileWithOpts{ - RateProfile: &engine.RateProfile{ - ID: "RateChristmas", - FilterIDs: []string{"*string:~*req.Subject:1002"}, - Weight: 50, - Rates: map[string]*engine.Rate{ - "RATE1": rate1, - "RATE_CHRISTMAS": rtChristmas, - }, - }, - }, - } - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfile, rPrf, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Error("Unexpected reply returned", reply) - } - - var rply *engine.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREventWithOpts: &utils.CGREventWithOpts{ - Opts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2020, 12, 23, 23, 0, 0, 0, time.UTC), - utils.OptsRatesUsage: "25h12m15s", - }, - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1002", - }, - }, - }, - } - exp := &engine.RateProfileCost{ - ID: "RateChristmas", - Cost: 93.725, - RateSIntervals: []*engine.RateSInterval{ - { - UsageStart: 0, - Increments: []*engine.RateSIncrement{ - { - UsageStart: 0, - Usage: time.Minute, - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - UsageStart: 1 * time.Minute, - Usage: 59 * time.Minute, - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 3540, - }, - }, - CompressFactor: 1, - }, - { - UsageStart: time.Hour, - Increments: []*engine.RateSIncrement{ - { - UsageStart: time.Hour, - Usage: 24 * time.Hour, - Rate: rtChristmas, - IntervalRateIndex: 0, - CompressFactor: 86400, - }, - }, - CompressFactor: 1, - }, - { - UsageStart: 25 * time.Hour, - Increments: []*engine.RateSIncrement{ - { - UsageStart: 25 * time.Hour, - Usage: 735 * time.Second, - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 735, - }, - }, - CompressFactor: 1, - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - - } -} - -func testV1RateCostForEventThreeRates(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &engine.Rate{ - ID: "RATE1", - Weight: 0, - ActivationTimes: "* * * * *", - IntervalRates: []*engine.IntervalRate{ - { - IntervalStart: 0, - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: time.Minute, - RecurrentFee: utils.NewDecimal(1, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rtNewYear1 := &engine.Rate{ - ID: "NEW_YEAR1", - ActivationTimes: "* 12-23 31 12 *", - Weight: 20, - IntervalRates: []*engine.IntervalRate{ - { - IntervalStart: 0, - RecurrentFee: utils.NewDecimal(8, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rtNewYear2 := &engine.Rate{ - ID: "NEW_YEAR2", - ActivationTimes: "* 0-12 1 1 *", - Weight: 30, - IntervalRates: []*engine.IntervalRate{ - { - IntervalStart: 0, - RecurrentFee: utils.NewDecimal(5, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rPrf := &engine.RateProfileWithOpts{ - RateProfileWithOpts: &engine.RateProfileWithOpts{ - RateProfile: &engine.RateProfile{ - ID: "RateNewYear", - FilterIDs: []string{"*string:~*req.Subject:1003"}, - Weight: 50, - Rates: map[string]*engine.Rate{ - "RATE1": rate1, - "NEW_YEAR1": rtNewYear1, - "NEW_YEAR2": rtNewYear2, - }, - }, - }, - } - var reply string - if err := ratePrfRpc.Call(utils.APIerSv1SetRateProfile, rPrf, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Error("Unexpected reply returned", reply) - } - - var rply *engine.RateProfileCost - argsRt := &utils.ArgsCostForEvent{ - CGREventWithOpts: &utils.CGREventWithOpts{ - Opts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2020, 12, 31, 10, 0, 0, 0, time.UTC), - utils.OptsRatesUsage: "35h12m15s", - }, - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1003", - }, - }, - }, - } - exp := &engine.RateProfileCost{ - ID: "RateNewYear", - Cost: 157.925, - RateSIntervals: []*engine.RateSInterval{ - { - UsageStart: 0, - Increments: []*engine.RateSIncrement{ - { - UsageStart: 0, - Usage: time.Minute, - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - UsageStart: 1 * time.Minute, - Usage: 119 * time.Minute, - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 7140, - }, - }, - CompressFactor: 1, - }, - { - UsageStart: 2 * time.Hour, - Increments: []*engine.RateSIncrement{ - { - UsageStart: 2 * time.Hour, - Usage: 12 * time.Hour, - Rate: rtNewYear1, - IntervalRateIndex: 0, - CompressFactor: 43200, - }, - }, - CompressFactor: 1, - }, - { - UsageStart: 14 * time.Hour, - Increments: []*engine.RateSIncrement{ - { - UsageStart: 14 * time.Hour, - Usage: 46800 * time.Second, - Rate: rtNewYear2, - IntervalRateIndex: 0, - CompressFactor: 46800, - }, - }, - CompressFactor: 1, - }, - { - UsageStart: 27 * time.Hour, - Increments: []*engine.RateSIncrement{ - { - UsageStart: 27 * time.Hour, - Usage: 29535 * time.Second, - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 29535, - }, - }, - CompressFactor: 1, - }, - }, - } - if err := ratePrfRpc.Call(utils.RateSv1CostForEvent, &argsRt, &rply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(exp, rply) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rply)) - - } -} -*/ diff --git a/config/config.go b/config/config.go index cfa99ac9d..1bc9d506b 100644 --- a/config/config.go +++ b/config/config.go @@ -348,7 +348,7 @@ type CGRConfig struct { var posibleLoaderTypes = utils.NewStringSet([]string{utils.MetaAttributes, utils.MetaResources, utils.MetaFilters, utils.MetaStats, utils.MetaRoutes, utils.MetaThresholds, utils.MetaChargers, - utils.MetaDispatchers, utils.MetaDispatcherHosts, utils.MetaRateProfiles}) + utils.MetaDispatchers, utils.MetaDispatcherHosts}) var possibleReaderTypes = utils.NewStringSet([]string{utils.MetaFileCSV, utils.MetaKafkajsonMap, utils.MetaFileXML, utils.MetaSQL, utils.MetaFileFWV, diff --git a/console/rates_profile.go b/console/rates_profile.go deleted file mode 100644 index 615eca642..000000000 --- a/console/rates_profile.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import ( - "github.com/cgrates/cgrates/utils" -) - -func init() { - c := &CmdGetRateProfile{ - name: "rates_profile", - rpcMethod: utils.APIerSv1GetRateProfile, - rpcParams: &utils.TenantIDWithAPIOpts{}, - } - commands[c.Name()] = c - c.CommandExecuter = &CommandExecuter{c} -} - -// Commander implementation -type CmdGetRateProfile struct { - name string - rpcMethod string - rpcParams *utils.TenantIDWithAPIOpts - *CommandExecuter -} - -func (self *CmdGetRateProfile) Name() string { - return self.name -} - -func (self *CmdGetRateProfile) RpcMethod() string { - return self.rpcMethod -} - -func (self *CmdGetRateProfile) RpcParams(reset bool) interface{} { - if reset || self.rpcParams == nil { - self.rpcParams = &utils.TenantIDWithAPIOpts{} - } - return self.rpcParams -} - -func (self *CmdGetRateProfile) PostprocessRpcParams() error { - return nil -} - -func (self *CmdGetRateProfile) RpcResult() interface{} { - var atr utils.RateProfile - return &atr -} diff --git a/console/rates_profile_ids.go b/console/rates_profile_ids.go deleted file mode 100644 index d754c7d75..000000000 --- a/console/rates_profile_ids.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import ( - "github.com/cgrates/cgrates/utils" -) - -func init() { - c := &CmdRateProfileIDs{ - name: "rates_profile_ids", - rpcMethod: utils.APIerSv1GetRateProfileIDs, - rpcParams: &utils.PaginatorWithTenant{}, - } - commands[c.Name()] = c - c.CommandExecuter = &CommandExecuter{c} -} - -// Commander implementation -type CmdRateProfileIDs struct { - name string - rpcMethod string - rpcParams *utils.PaginatorWithTenant - *CommandExecuter -} - -func (self *CmdRateProfileIDs) Name() string { - return self.name -} - -func (self *CmdRateProfileIDs) RpcMethod() string { - return self.rpcMethod -} - -func (self *CmdRateProfileIDs) RpcParams(reset bool) interface{} { - if reset || self.rpcParams == nil { - self.rpcParams = &utils.PaginatorWithTenant{} - } - return self.rpcParams -} - -func (self *CmdRateProfileIDs) PostprocessRpcParams() error { - return nil -} - -func (self *CmdRateProfileIDs) RpcResult() interface{} { - var atr []string - return &atr -} diff --git a/console/rates_profile_ids_test.go b/console/rates_profile_ids_test.go deleted file mode 100644 index c337c84c7..000000000 --- a/console/rates_profile_ids_test.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import ( - "reflect" - "strings" - "testing" - - v1 "github.com/cgrates/cgrates/apier/v1" - - "github.com/cgrates/cgrates/utils" -) - -func TestCmdRatesProfileIDs(t *testing.T) { - // commands map is initiated in init function - command := commands["rates_profile_ids"] - // verify if ApierSv1 object has method on it - m, ok := reflect.TypeOf(new(v1.APIerSv1)).MethodByName(strings.Split(command.RpcMethod(), utils.NestingSep)[1]) - if !ok { - t.Fatal("method not found") - } - if m.Type.NumIn() != 3 { // ApierSv1 is consider and we expect 3 inputs - t.Fatalf("invalid number of input parameters ") - } - // verify the type of input parameter - if ok := m.Type.In(1).AssignableTo(reflect.TypeOf(command.RpcParams(true))); !ok { - t.Fatalf("cannot assign input parameter") - } - // verify the type of output parameter - if ok := m.Type.In(2).AssignableTo(reflect.TypeOf(command.RpcResult())); !ok { - t.Fatalf("cannot assign output parameter") - } - // for coverage purpose - if err := command.PostprocessRpcParams(); err != nil { - t.Fatal(err) - } -} diff --git a/console/rates_profile_remove.go b/console/rates_profile_remove.go deleted file mode 100644 index b56ae2e11..000000000 --- a/console/rates_profile_remove.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import "github.com/cgrates/cgrates/utils" - -func init() { - c := &CmdRemoveRateProfile{ - name: "rates_profile_remove", - rpcMethod: utils.APIerSv1RemoveRateProfile, - rpcParams: &utils.TenantIDWithAPIOpts{}, - } - commands[c.Name()] = c - c.CommandExecuter = &CommandExecuter{c} -} - -type CmdRemoveRateProfile struct { - name string - rpcMethod string - rpcParams *utils.TenantIDWithAPIOpts - *CommandExecuter -} - -func (self *CmdRemoveRateProfile) Name() string { - return self.name -} - -func (self *CmdRemoveRateProfile) RpcMethod() string { - return self.rpcMethod -} - -func (self *CmdRemoveRateProfile) RpcParams(reset bool) interface{} { - if reset || self.rpcParams == nil { - self.rpcParams = &utils.TenantIDWithAPIOpts{APIOpts: make(map[string]interface{})} - } - return self.rpcParams -} - -func (self *CmdRemoveRateProfile) PostprocessRpcParams() error { - return nil -} - -func (self *CmdRemoveRateProfile) RpcResult() interface{} { - var s string - return &s -} diff --git a/console/rates_profile_remove_test.go b/console/rates_profile_remove_test.go deleted file mode 100644 index 271660bc2..000000000 --- a/console/rates_profile_remove_test.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import ( - "reflect" - "strings" - "testing" - - v1 "github.com/cgrates/cgrates/apier/v1" - - "github.com/cgrates/cgrates/utils" -) - -func TestCmdRatesProfileRem(t *testing.T) { - // commands map is initiated in init function - command := commands["rates_profile_remove"] - // verify if ApierSv1 object has method on it - m, ok := reflect.TypeOf(new(v1.APIerSv1)).MethodByName(strings.Split(command.RpcMethod(), utils.NestingSep)[1]) - if !ok { - t.Fatal("method not found") - } - if m.Type.NumIn() != 3 { // ApierSv1 is consider and we expect 3 inputs - t.Fatalf("invalid number of input parameters ") - } - // verify the type of input parameter - if ok := m.Type.In(1).AssignableTo(reflect.TypeOf(command.RpcParams(true))); !ok { - t.Fatalf("cannot assign input parameter") - } - // verify the type of output parameter - if ok := m.Type.In(2).AssignableTo(reflect.TypeOf(command.RpcResult())); !ok { - t.Fatalf("cannot assign output parameter") - } - // for coverage purpose - if err := command.PostprocessRpcParams(); err != nil { - t.Fatal(err) - } -} diff --git a/console/rates_profile_set.go b/console/rates_profile_set.go deleted file mode 100644 index de43c1cd4..000000000 --- a/console/rates_profile_set.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import ( - "github.com/cgrates/cgrates/utils" -) - -func init() { - c := &CmdSetRateProfile{ - name: "rates_profile_set", - rpcMethod: utils.APIerSv1SetRateProfile, - rpcParams: &utils.APIRateProfileWithAPIOpts{}, - } - commands[c.Name()] = c - c.CommandExecuter = &CommandExecuter{c} -} - -type CmdSetRateProfile struct { - name string - rpcMethod string - rpcParams *utils.APIRateProfileWithAPIOpts - *CommandExecuter -} - -func (self *CmdSetRateProfile) Name() string { - return self.name -} - -func (self *CmdSetRateProfile) RpcMethod() string { - return self.rpcMethod -} - -func (self *CmdSetRateProfile) RpcParams(reset bool) interface{} { - if reset || self.rpcParams == nil { - self.rpcParams = &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: new(utils.APIRateProfile), - APIOpts: make(map[string]interface{}), - } - } - return self.rpcParams -} - -func (self *CmdSetRateProfile) PostprocessRpcParams() error { - return nil -} - -func (self *CmdSetRateProfile) RpcResult() interface{} { - var s string - return &s -} diff --git a/console/rates_profile_set_test.go b/console/rates_profile_set_test.go deleted file mode 100644 index c833aa725..000000000 --- a/console/rates_profile_set_test.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import ( - "reflect" - "strings" - "testing" - - v1 "github.com/cgrates/cgrates/apier/v1" - - "github.com/cgrates/cgrates/utils" -) - -func TestCmdRatesProfileSet(t *testing.T) { - // commands map is initiated in init function - command := commands["rates_profile_set"] - // verify if ApierSv1 object has method on it - m, ok := reflect.TypeOf(new(v1.APIerSv1)).MethodByName(strings.Split(command.RpcMethod(), utils.NestingSep)[1]) - if !ok { - t.Fatal("method not found") - } - if m.Type.NumIn() != 3 { // ApierSv1 is consider and we expect 3 inputs - t.Fatalf("invalid number of input parameters ") - } - // verify the type of input parameter - if ok := m.Type.In(1).AssignableTo(reflect.TypeOf(command.RpcParams(true))); !ok { - t.Fatalf("cannot assign input parameter") - } - // verify the type of output parameter - if ok := m.Type.In(2).AssignableTo(reflect.TypeOf(command.RpcResult())); !ok { - t.Fatalf("cannot assign output parameter") - } - // for coverage purpose - if err := command.PostprocessRpcParams(); err != nil { - t.Fatal(err) - } -} diff --git a/console/rates_profile_test.go b/console/rates_profile_test.go deleted file mode 100644 index 97827011b..000000000 --- a/console/rates_profile_test.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package console - -import ( - "reflect" - "strings" - "testing" - - v1 "github.com/cgrates/cgrates/apier/v1" - - "github.com/cgrates/cgrates/utils" -) - -func TestCmdRatesProfile(t *testing.T) { - // commands map is initiated in init function - command := commands["rates_profile"] - // verify if ApierSv1 object has method on it - m, ok := reflect.TypeOf(new(v1.APIerSv1)).MethodByName(strings.Split(command.RpcMethod(), utils.NestingSep)[1]) - if !ok { - t.Fatal("method not found") - } - if m.Type.NumIn() != 3 { // ApierSv1 is consider and we expect 3 inputs - t.Fatalf("invalid number of input parameters ") - } - // verify the type of input parameter - if ok := m.Type.In(1).AssignableTo(reflect.TypeOf(command.RpcParams(true))); !ok { - t.Fatalf("cannot assign input parameter") - } - // verify the type of output parameter - if ok := m.Type.In(2).AssignableTo(reflect.TypeOf(command.RpcResult())); !ok { - t.Fatalf("cannot assign output parameter") - } - // for coverage purpose - if err := command.PostprocessRpcParams(); err != nil { - t.Fatal(err) - } -} diff --git a/dispatchers/caches_it_test.go b/dispatchers/caches_it_test.go index e3d395696..c62f2cbd7 100644 --- a/dispatchers/caches_it_test.go +++ b/dispatchers/caches_it_test.go @@ -166,56 +166,51 @@ func testDspChcLoadAfterFolder(t *testing.T) { func testDspChcPrecacheStatus(t *testing.T) { var reply map[string]string expected := map[string]string{ - utils.CacheDestinations: utils.MetaReady, - utils.CacheReverseDestinations: utils.MetaReady, - utils.CacheRatingPlans: utils.MetaReady, - utils.CacheRatingProfiles: utils.MetaReady, - utils.CacheActions: utils.MetaReady, - utils.CacheActionPlans: utils.MetaReady, - utils.CacheAccountActionPlans: utils.MetaReady, - utils.CacheActionTriggers: utils.MetaReady, - utils.CacheSharedGroups: utils.MetaReady, - utils.CacheResourceProfiles: utils.MetaReady, - utils.CacheResources: utils.MetaReady, - utils.CacheTimings: utils.MetaReady, - utils.CacheStatQueueProfiles: utils.MetaReady, - utils.CacheStatQueues: utils.MetaReady, - utils.CacheThresholdProfiles: utils.MetaReady, - utils.CacheThresholds: utils.MetaReady, - utils.CacheFilters: utils.MetaReady, - utils.CacheRouteProfiles: utils.MetaReady, - utils.CacheAttributeProfiles: utils.MetaReady, - utils.CacheChargerProfiles: utils.MetaReady, - utils.CacheDispatcherProfiles: utils.MetaReady, - utils.CacheDispatcherHosts: utils.MetaReady, - utils.CacheDiameterMessages: utils.MetaReady, - utils.CacheAttributeFilterIndexes: utils.MetaReady, - utils.CacheResourceFilterIndexes: utils.MetaReady, - utils.CacheStatFilterIndexes: utils.MetaReady, - utils.CacheThresholdFilterIndexes: utils.MetaReady, - utils.CacheRouteFilterIndexes: utils.MetaReady, - utils.CacheChargerFilterIndexes: utils.MetaReady, - utils.CacheDispatcherFilterIndexes: utils.MetaReady, - utils.CacheRateProfilesFilterIndexes: utils.MetaReady, - utils.CacheRateFilterIndexes: utils.MetaReady, - utils.CacheRateProfiles: utils.MetaReady, - utils.CacheLoadIDs: utils.MetaReady, - utils.CacheCDRIDs: utils.MetaReady, - utils.CacheClosedSessions: utils.MetaReady, - utils.CacheDispatcherRoutes: utils.MetaReady, - utils.CacheEventResources: utils.MetaReady, - utils.CacheRPCConnections: utils.MetaReady, - utils.CacheRPCResponses: utils.MetaReady, - utils.CacheRatingProfilesTmp: utils.MetaReady, - utils.CacheUCH: utils.MetaReady, - utils.CacheSTIR: utils.MetaReady, - utils.CacheDispatcherLoads: utils.MetaReady, - utils.CacheDispatchers: utils.MetaReady, - utils.CacheEventCharges: utils.MetaReady, - utils.CacheReverseFilterIndexes: utils.MetaReady, - utils.CacheCapsEvents: utils.MetaReady, - utils.CacheActionProfiles: utils.MetaReady, - utils.CacheActionProfilesFilterIndexes: utils.MetaReady, + utils.CacheDestinations: utils.MetaReady, + utils.CacheReverseDestinations: utils.MetaReady, + utils.CacheRatingPlans: utils.MetaReady, + utils.CacheRatingProfiles: utils.MetaReady, + utils.CacheActions: utils.MetaReady, + utils.CacheActionPlans: utils.MetaReady, + utils.CacheAccountActionPlans: utils.MetaReady, + utils.CacheActionTriggers: utils.MetaReady, + utils.CacheSharedGroups: utils.MetaReady, + utils.CacheResourceProfiles: utils.MetaReady, + utils.CacheResources: utils.MetaReady, + utils.CacheTimings: utils.MetaReady, + utils.CacheStatQueueProfiles: utils.MetaReady, + utils.CacheStatQueues: utils.MetaReady, + utils.CacheThresholdProfiles: utils.MetaReady, + utils.CacheThresholds: utils.MetaReady, + utils.CacheFilters: utils.MetaReady, + utils.CacheRouteProfiles: utils.MetaReady, + utils.CacheAttributeProfiles: utils.MetaReady, + utils.CacheChargerProfiles: utils.MetaReady, + utils.CacheDispatcherProfiles: utils.MetaReady, + utils.CacheDispatcherHosts: utils.MetaReady, + utils.CacheDiameterMessages: utils.MetaReady, + utils.CacheAttributeFilterIndexes: utils.MetaReady, + utils.CacheResourceFilterIndexes: utils.MetaReady, + utils.CacheStatFilterIndexes: utils.MetaReady, + utils.CacheThresholdFilterIndexes: utils.MetaReady, + utils.CacheRouteFilterIndexes: utils.MetaReady, + utils.CacheChargerFilterIndexes: utils.MetaReady, + utils.CacheDispatcherFilterIndexes: utils.MetaReady, + utils.CacheLoadIDs: utils.MetaReady, + utils.CacheCDRIDs: utils.MetaReady, + utils.CacheClosedSessions: utils.MetaReady, + utils.CacheDispatcherRoutes: utils.MetaReady, + utils.CacheEventResources: utils.MetaReady, + utils.CacheRPCConnections: utils.MetaReady, + utils.CacheRPCResponses: utils.MetaReady, + utils.CacheRatingProfilesTmp: utils.MetaReady, + utils.CacheUCH: utils.MetaReady, + utils.CacheSTIR: utils.MetaReady, + utils.CacheDispatcherLoads: utils.MetaReady, + utils.CacheDispatchers: utils.MetaReady, + utils.CacheEventCharges: utils.MetaReady, + utils.CacheReverseFilterIndexes: utils.MetaReady, + utils.CacheCapsEvents: utils.MetaReady, utils.CacheAccounts: utils.MetaReady, utils.CacheVersions: utils.MetaReady, @@ -241,7 +236,6 @@ func testDspChcPrecacheStatus(t *testing.T) { utils.CacheTBLTPChargers: utils.MetaReady, utils.CacheTBLTPDispatchers: utils.MetaReady, utils.CacheTBLTPDispatcherHosts: utils.MetaReady, - utils.CacheTBLTPRateProfiles: utils.MetaReady, utils.MetaAPIBan: utils.MetaReady, utils.CacheTBLTPActionProfiles: utils.MetaReady, utils.CacheReplicationHosts: utils.MetaReady, diff --git a/dispatchers/rates.go b/dispatchers/rates.go deleted file mode 100644 index fedb79834..000000000 --- a/dispatchers/rates.go +++ /dev/null @@ -1,51 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package dispatchers - -import ( - "github.com/cgrates/cgrates/utils" -) - -func (dS *DispatcherService) RateSv1Ping(args *utils.CGREvent, rpl *string) (err error) { - if args == nil { - args = new(utils.CGREvent) - } - args.Tenant = utils.FirstNonEmpty(args.Tenant, dS.cfg.GeneralCfg().DefaultTenant) - if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { - if err = dS.authorize(utils.RateSv1Ping, args.Tenant, - utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), args.Time); err != nil { - return - } - } - return dS.Dispatch(args, utils.RateS, utils.RateSv1Ping, args, rpl) -} - -func (dS *DispatcherService) RateSv1CostForEvent(args *utils.ArgsCostForEvent, rpCost *utils.RateProfileCost) (err error) { - if args == nil { - args = new(utils.ArgsCostForEvent) - } - args.CGREvent.Tenant = utils.FirstNonEmpty(args.CGREvent.Tenant, dS.cfg.GeneralCfg().DefaultTenant) - if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { - if err = dS.authorize(utils.RateSv1CostForEvent, args.CGREvent.Tenant, - utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), args.CGREvent.Time); err != nil { - return - } - } - return dS.Dispatch(args.CGREvent, utils.RateS, utils.RateSv1CostForEvent, args, rpCost) -} diff --git a/dispatchers/rates_it_test.go b/dispatchers/rates_it_test.go deleted file mode 100644 index 3493975fb..000000000 --- a/dispatchers/rates_it_test.go +++ /dev/null @@ -1,227 +0,0 @@ -// +build integration - -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package dispatchers - -import ( - "reflect" - "testing" - "time" - - "github.com/cgrates/cgrates/utils" -) - -var sTestsDspRPrf = []func(t *testing.T){ - testDspRPrfPing, - testDspRPrfCostForEvent, - testDspRPrfCostForEventWithoutFilters, -} - -//Test start here -func TestDspRateSIT(t *testing.T) { - var config1, config2, config3 string - switch *dbType { - case utils.MetaInternal: - t.SkipNow() - case utils.MetaMySQL: - config1 = "all_mysql" - config2 = "all2_mysql" - config3 = "dispatchers_mysql" - case utils.MetaMongo: - config1 = "all_mongo" - config2 = "all2_mongo" - config3 = "dispatchers_mongo" - case utils.MetaPostgres: - t.SkipNow() - default: - t.Fatal("Unknown Database type") - } - - dispDIR := "dispatchers" - if *encoding == utils.MetaGOB { - dispDIR += "_gob" - } - testDsp(t, sTestsDspRPrf, "TestDspRateSIT", config1, config2, config3, "tutorial", "oldtutorial", dispDIR) -} - -func testDspRPrfPing(t *testing.T) { - var reply string - if err := allEngine.RPC.Call(utils.RateSv1Ping, new(utils.CGREvent), &reply); err != nil { - t.Error(err) - } else if reply != utils.Pong { - t.Errorf("Received: %s", reply) - } - if err := dispEngine.RPC.Call(utils.RateSv1Ping, utils.CGREvent{ - Tenant: "cgrates.org", - APIOpts: map[string]interface{}{ - utils.OptsAPIKey: "rPrf12345", - }, - }, &reply); err != nil { - t.Error(err) - } else if reply != utils.Pong { - t.Errorf("Received: %s", reply) - } -} - -func testDspRPrfCostForEvent(t *testing.T) { - rPrf := &utils.APIRateProfile{ - ID: "DefaultRate", - Tenant: "cgrates.org", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";10", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * *", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - RecurrentFee: utils.Float64Pointer(0.12), - Unit: utils.Float64Pointer(float64(time.Minute)), - Increment: utils.Float64Pointer(float64(time.Minute)), - }, - }, - }, - }, - } - var reply string - if err := allEngine.RPC.Call(utils.APIerSv1SetRateProfile, rPrf, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Errorf("Expected OK, received %+v", reply) - } - var rply *utils.RateProfile - if err := allEngine.RPC.Call(utils.APIerSv1GetRateProfile, &utils.TenantID{ - Tenant: "cgrates.org", - ID: "DefaultRate", - }, &rply); err != nil { - t.Error(err) - } - rtWeek, err := rPrf.Rates["RT_WEEK"].AsRate() - if err != nil { - t.Fatal(err) - } - exp := &utils.RateProfileCost{ - ID: "DefaultRate", - Cost: 0.12, - RateSIntervals: []*utils.RateSInterval{{ - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{{ - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rtWeek, - IntervalRateIndex: 0, - CompressFactor: 1, - }}, - CompressFactor: 1, - }}, - } - - var rpCost *utils.RateProfileCost - if err := dispEngine.RPC.Call(utils.RateSv1CostForEvent, &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "DefaultRate", - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - - APIOpts: map[string]interface{}{ - utils.OptsAPIKey: "rPrf12345", - }}}, &rpCost); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rpCost, exp) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(exp), utils.ToJSON(rpCost)) - } -} - -func testDspRPrfCostForEventWithoutFilters(t *testing.T) { - rPrf := &utils.APIRateProfile{ - ID: "ID_RP", - Tenant: "cgrates.org", - Weights: ";10", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * *", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - RecurrentFee: utils.Float64Pointer(0.25), - Unit: utils.Float64Pointer(float64(time.Minute)), - Increment: utils.Float64Pointer(float64(time.Second)), - }, - }, - }, - }, - } - var reply string - if err := allEngine.RPC.Call(utils.APIerSv1SetRateProfile, rPrf, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Errorf("Expected OK, received %+v", reply) - } - var rply *utils.RateProfile - if err := allEngine.RPC.Call(utils.APIerSv1GetRateProfile, &utils.TenantID{ - Tenant: "cgrates.org", - ID: "ID_RP", - }, &rply); err != nil { - t.Error(err) - } - rtWeek, err := rPrf.Rates["RT_WEEK"].AsRate() - if err != nil { - t.Fatal(err) - } - exp := &utils.RateProfileCost{ - ID: "ID_RP", - Cost: 0.25, - RateSIntervals: []*utils.RateSInterval{{ - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{{ - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rtWeek, - IntervalRateIndex: 0, - CompressFactor: 60, - }}, - CompressFactor: 1, - }}, - } - - var rpCost *utils.RateProfileCost - if err := dispEngine.RPC.Call(utils.RateSv1CostForEvent, &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - - Tenant: "cgrates.org", - ID: "EVENT_RATE", - Event: map[string]interface{}{ - utils.Subject: "1002", - }, - - APIOpts: map[string]interface{}{ - utils.OptsAPIKey: "rPrf12345", - }}}, &rpCost); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rpCost, exp) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(exp), utils.ToJSON(rpCost)) - } -} diff --git a/dispatchers/replicator.go b/dispatchers/replicator.go index d67f0002e..44a9aadc2 100644 --- a/dispatchers/replicator.go +++ b/dispatchers/replicator.go @@ -459,24 +459,6 @@ func (dS *DispatcherService) ReplicatorSv1GetDispatcherHost(args *utils.TenantID }, utils.MetaReplicator, utils.ReplicatorSv1GetDispatcherHost, args, reply) } -func (dS *DispatcherService) ReplicatorSv1GetRateProfile(args *utils.TenantIDWithAPIOpts, reply *utils.RateProfile) (err error) { - tnt := dS.cfg.GeneralCfg().DefaultTenant - if args.TenantID != nil && args.TenantID.Tenant != utils.EmptyString { - tnt = args.TenantID.Tenant - } - if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { - if err = dS.authorize(utils.ReplicatorSv1GetRateProfile, tnt, - utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil { - return - } - } - return dS.Dispatch(&utils.CGREvent{ - Tenant: tnt, - ID: args.ID, - APIOpts: args.APIOpts, - }, utils.MetaReplicator, utils.ReplicatorSv1GetRateProfile, args, reply) -} - func (dS *DispatcherService) ReplicatorSv1GetActionProfile(args *utils.TenantIDWithAPIOpts, reply *engine.ActionProfile) (err error) { tnt := dS.cfg.GeneralCfg().DefaultTenant if args.TenantID != nil && args.TenantID.Tenant != utils.EmptyString { @@ -852,23 +834,6 @@ func (dS *DispatcherService) ReplicatorSv1SetDispatcherProfile(args *engine.Disp }, utils.MetaReplicator, utils.ReplicatorSv1SetDispatcherProfile, args, rpl) } -func (dS *DispatcherService) ReplicatorSv1SetRateProfile(args *utils.RateProfileWithAPIOpts, rpl *string) (err error) { - if args == nil { - args = &utils.RateProfileWithAPIOpts{} - } - args.Tenant = utils.FirstNonEmpty(args.Tenant, dS.cfg.GeneralCfg().DefaultTenant) - if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { - if err = dS.authorize(utils.ReplicatorSv1SetRateProfile, args.Tenant, - utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil { - return - } - } - return dS.Dispatch(&utils.CGREvent{ - Tenant: args.Tenant, - APIOpts: args.APIOpts, - }, utils.MetaReplicator, utils.ReplicatorSv1SetRateProfile, args, rpl) -} - func (dS *DispatcherService) ReplicatorSv1SetActionProfile(args *engine.ActionProfileWithAPIOpts, rpl *string) (err error) { if args == nil { args = &engine.ActionProfileWithAPIOpts{} @@ -1328,23 +1293,6 @@ func (dS *DispatcherService) ReplicatorSv1RemoveDispatcherHost(args *utils.Tenan }, utils.MetaReplicator, utils.ReplicatorSv1RemoveDispatcherHost, args, rpl) } -func (dS *DispatcherService) ReplicatorSv1RemoveRateProfile(args *utils.TenantIDWithAPIOpts, rpl *string) (err error) { - if args == nil { - args = &utils.TenantIDWithAPIOpts{} - } - args.Tenant = utils.FirstNonEmpty(args.Tenant, dS.cfg.GeneralCfg().DefaultTenant) - if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { - if err = dS.authorize(utils.ReplicatorSv1RemoveRateProfile, args.Tenant, - utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil { - return - } - } - return dS.Dispatch(&utils.CGREvent{ - Tenant: args.Tenant, - APIOpts: args.APIOpts, - }, utils.MetaReplicator, utils.ReplicatorSv1RemoveRateProfile, args, rpl) -} - func (dS *DispatcherService) ReplicatorSv1RemoveActionProfile(args *utils.TenantIDWithAPIOpts, rpl *string) (err error) { if args == nil { args = &utils.TenantIDWithAPIOpts{} diff --git a/dispatchers/replicator_it_test.go b/dispatchers/replicator_it_test.go index 6a05ec5f4..fadd6cd36 100644 --- a/dispatchers/replicator_it_test.go +++ b/dispatchers/replicator_it_test.go @@ -53,7 +53,6 @@ var sTestsDspRpl = []func(t *testing.T){ testDspRplRatingPlan, testDspRplRatingProfile, testDspRplDestination, - testDspRplRateProfile, testDspRplActionProfile, } @@ -1469,94 +1468,6 @@ func testDspRplLoadIDs(t *testing.T) { allEngine.startEngine(t) } -func testDspRplRateProfile(t *testing.T) { - // Set RateProfile - var replyStr string - rPrf := &utils.RateProfileWithAPIOpts{ - RateProfile: &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001", "*string:~*req.Subject:1002"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "FIRST_GI": { - ID: "FIRST_GI", - FilterIDs: []string{"*gi:~*req.Usage:0"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - Blocker: false, - }, - "SECOND_GI": { - ID: "SECOND_GI", - FilterIDs: []string{"*gi:~*req.Usage:1m"}, - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - Blocker: false, - }, - }, - }, - APIOpts: map[string]interface{}{ - utils.OptsAPIKey: "repl12345", - }, - } - if err := dispEngine.RPC.Call(utils.ReplicatorSv1SetRateProfile, rPrf, &replyStr); err != nil { - t.Error("Unexpected error when calling ReplicatorSv1.SetRateProfile: ", err) - } else if replyStr != utils.OK { - t.Error("Unexpected reply returned", replyStr) - } - // Get RateProfile - var reply *utils.RateProfile - args := &utils.TenantIDWithAPIOpts{ - TenantID: &utils.TenantID{ - Tenant: "cgrates.org", - ID: "RP1", - }, - APIOpts: map[string]interface{}{ - utils.OptsAPIKey: "repl12345", - }, - } - if err := dispEngine.RPC.Call(utils.ReplicatorSv1GetRateProfile, args, &reply); err != nil { - t.Error("Unexpected error when calling ReplicatorSv1.GetRateProfile: ", err) - } else if !reflect.DeepEqual(rPrf.RateProfile, reply) { - t.Errorf("Expecting: %+v, received: %+v, ", rPrf.RateProfile, reply) - } - // Stop engine 1 - allEngine.stopEngine(t) - - // Get RateProfile - if err := dispEngine.RPC.Call(utils.ReplicatorSv1GetRateProfile, args, &reply); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Errorf("Expecting: %+v, received: %+v, ", utils.ErrNotFound, err) - } - - // Start engine 1 - allEngine.startEngine(t) - - // Remove RateProfile - if err := dispEngine.RPC.Call(utils.ReplicatorSv1RemoveRateProfile, args, &replyStr); err != nil { - t.Error(err) - } else if replyStr != utils.OK { - t.Error("Unexpected reply returned", replyStr) - } - - // Get RateProfile - if err := dispEngine.RPC.Call(utils.ReplicatorSv1GetRateProfile, args, &reply); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Errorf("Expecting: %+v, received: %+v, ", utils.ErrNotFound, err) - } -} - func testDspRplActionProfile(t *testing.T) { // Set RateProfile var replyStr string diff --git a/engine/caches.go b/engine/caches.go index a7e6a7b35..be591ef54 100644 --- a/engine/caches.go +++ b/engine/caches.go @@ -64,9 +64,6 @@ func init() { gob.Register(new(DispatcherHost)) gob.Register(new(DispatcherHostProfile)) gob.Register(new(DispatcherHostWithAPIOpts)) - // RateProfiles - gob.Register(new(utils.RateProfile)) - gob.Register(new(utils.RateProfileWithAPIOpts)) // ActionProfiles gob.Register(new(ActionProfile)) gob.Register(new(ActionProfileWithAPIOpts)) diff --git a/engine/datadbmock.go b/engine/datadbmock.go index b31565a90..9ab998c38 100644 --- a/engine/datadbmock.go +++ b/engine/datadbmock.go @@ -382,18 +382,6 @@ func (dbM *DataDBMock) RemoveDispatcherHostDrv(string, string) error { return utils.ErrNotImplemented } -func (dbM *DataDBMock) GetRateProfileDrv(string, string) (*utils.RateProfile, error) { - return nil, utils.ErrNotImplemented -} - -func (dbM *DataDBMock) SetRateProfileDrv(*utils.RateProfile) error { - return utils.ErrNotImplemented -} - -func (dbM *DataDBMock) RemoveRateProfileDrv(string, string) error { - return utils.ErrNotImplemented -} - func (dbM *DataDBMock) GetActionProfileDrv(string, string) (*ActionProfile, error) { return nil, utils.ErrNotImplemented } diff --git a/engine/datamanager.go b/engine/datamanager.go index 3a7b5fd12..687f3b06b 100644 --- a/engine/datamanager.go +++ b/engine/datamanager.go @@ -35,9 +35,7 @@ var ( utils.RouteFilterIndexes: {}, utils.ChargerFilterIndexes: {}, utils.DispatcherFilterIndexes: {}, - utils.RateProfilesFilterIndexPrfx: {}, utils.ActionProfilesFilterIndexPrfx: {}, - utils.RateFilterIndexPrfx: {}, utils.ActionPlanIndexes: {}, utils.FilterIndexPrfx: {}, } @@ -64,7 +62,6 @@ var ( utils.ChargerProfilePrefix: {}, utils.DispatcherProfilePrefix: {}, utils.DispatcherHostPrefix: {}, - utils.RateProfilePrefix: {}, utils.ActionProfilePrefix: {}, utils.AttributeFilterIndexes: {}, utils.ResourceFilterIndexes: {}, @@ -73,9 +70,7 @@ var ( utils.RouteFilterIndexes: {}, utils.ChargerFilterIndexes: {}, utils.DispatcherFilterIndexes: {}, - utils.RateProfilesFilterIndexPrfx: {}, utils.ActionProfilesFilterIndexPrfx: {}, - utils.RateFilterIndexPrfx: {}, utils.FilterIndexPrfx: {}, utils.MetaAPIBan: {}, // not realy a prefix as this is not stored in DB } @@ -222,9 +217,6 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b case utils.DispatcherHostPrefix: tntID := utils.NewTenantID(dataID) _, err = dm.GetDispatcherHost(tntID.Tenant, tntID.ID, false, true, utils.NonTransactional) - case utils.RateProfilePrefix: - tntID := utils.NewTenantID(dataID) - _, err = dm.GetRateProfile(tntID.Tenant, tntID.ID, false, true, utils.NonTransactional) case utils.ActionProfilePrefix: tntID := utils.NewTenantID(dataID) _, err = dm.GetActionProfile(tntID.Tenant, tntID.ID, false, true, utils.NonTransactional) @@ -270,18 +262,6 @@ func (dm *DataManager) CacheDataFromDB(prfx string, ids []string, mustBeCached b return } _, err = dm.GetIndexes(utils.CacheDispatcherFilterIndexes, tntCtx, idxKey, false, true) - case utils.RateProfilesFilterIndexPrfx: - var tntCtx, idxKey string - if tntCtx, idxKey, err = splitFilterIndex(dataID); err != nil { - return - } - _, err = dm.GetIndexes(utils.CacheRateProfilesFilterIndexes, tntCtx, idxKey, false, true) - case utils.RateFilterIndexPrfx: - var tntCtx, idxKey string - if tntCtx, idxKey, err = splitFilterIndex(dataID); err != nil { - return - } - _, err = dm.GetIndexes(utils.CacheRateFilterIndexes, tntCtx, idxKey, false, true) case utils.ActionProfilesFilterIndexPrfx: var tntCtx, idxKey string if tntCtx, idxKey, err = splitFilterIndex(dataID); err != nil { @@ -3029,276 +3009,6 @@ func (dm *DataManager) SetLoadIDs(loadIDs map[string]int64) (err error) { return } -func (dm *DataManager) GetRateProfile(tenant, id string, cacheRead, cacheWrite bool, - transactionID string) (rpp *utils.RateProfile, err error) { - tntID := utils.ConcatenatedKey(tenant, id) - if cacheRead { - if x, ok := Cache.Get(utils.CacheRateProfiles, tntID); ok { - if x == nil { - return nil, utils.ErrNotFound - } - return x.(*utils.RateProfile), nil - } - } - if dm == nil { - err = utils.ErrNoDatabaseConn - return - } - rpp, err = dm.dataDB.GetRateProfileDrv(tenant, id) - if err != nil { - if itm := config.CgrConfig().DataDbCfg().Items[utils.MetaRateProfiles]; err == utils.ErrNotFound && itm.Remote { - if err = dm.connMgr.Call(config.CgrConfig().DataDbCfg().RmtConns, nil, - utils.ReplicatorSv1GetRateProfile, - &utils.TenantIDWithAPIOpts{ - TenantID: &utils.TenantID{Tenant: tenant, ID: id}, - APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID, utils.EmptyString, - utils.FirstNonEmpty(config.CgrConfig().DataDbCfg().RmtConnID, - config.CgrConfig().GeneralCfg().NodeID)), - }, &rpp); err == nil { - rpp.Sort() - err = dm.dataDB.SetRateProfileDrv(rpp) - } - } - if err != nil { - err = utils.CastRPCErr(err) - if err == utils.ErrNotFound && cacheWrite { - if errCh := Cache.Set(utils.CacheRateProfiles, tntID, nil, nil, - cacheCommit(transactionID), transactionID); errCh != nil { - return nil, errCh - } - - } - return nil, err - } - } - if err = rpp.Compile(); err != nil { - return nil, err - } - if cacheWrite { - if errCh := Cache.Set(utils.CacheRateProfiles, tntID, rpp, nil, - cacheCommit(transactionID), transactionID); errCh != nil { - return nil, errCh - } - } - return -} - -func (dm *DataManager) SetRateProfile(rpp *utils.RateProfile, withIndex bool) (err error) { - if dm == nil { - return utils.ErrNoDatabaseConn - } - if withIndex { - if brokenReference := dm.checkFilters(rpp.Tenant, rpp.FilterIDs); len(brokenReference) != 0 { - // if we get a broken filter do not set the profile - return fmt.Errorf("broken reference to filter: %+v for item with ID: %+v", - brokenReference, rpp.TenantID()) - } - for _, rate := range rpp.Rates { - if brokenReference := dm.checkFilters(rpp.Tenant, rate.FilterIDs); len(brokenReference) != 0 { - // if we get a broken filter do not update the rates - return fmt.Errorf("broken reference to filter: %+v for rate with ID: %+v", - brokenReference, rate.ID) - } - } - } - oldRpp, err := dm.GetRateProfile(rpp.Tenant, rpp.ID, true, false, utils.NonTransactional) - if err != nil && err != utils.ErrNotFound { - return err - } - rpp.Sort() - if err = dm.DataDB().SetRateProfileDrv(rpp); err != nil { - return err - } - if withIndex { - var oldFiltersIDs *[]string - if oldRpp != nil { - oldFiltersIDs = &oldRpp.FilterIDs - } - if err := updatedIndexes(dm, utils.CacheRateProfilesFilterIndexes, rpp.Tenant, - utils.EmptyString, rpp.ID, oldFiltersIDs, rpp.FilterIDs, false); err != nil { - return err - } - // remove indexes for old rates - if oldRpp != nil { - for key, rate := range oldRpp.Rates { - if _, has := rpp.Rates[key]; has { - continue - } - if err = removeItemFromFilterIndex(dm, utils.CacheRateFilterIndexes, - rpp.Tenant, rpp.ID, key, rate.FilterIDs); err != nil { - return - } - } - } - // create index for each rate - for key, rate := range rpp.Rates { - var oldRateFiltersIDs *[]string - if oldRpp != nil { - if oldRate, has := oldRpp.Rates[key]; has { - oldRateFiltersIDs = &oldRate.FilterIDs - } - } - // when we create the indexes for rates we use RateProfile ID as context - if err := updatedIndexes(dm, utils.CacheRateFilterIndexes, rpp.Tenant, - rpp.ID, key, oldRateFiltersIDs, rate.FilterIDs, true); err != nil { - return err - } - } - - } - if itm := config.CgrConfig().DataDbCfg().Items[utils.MetaRateProfiles]; itm.Replicate { - err = replicate(dm.connMgr, config.CgrConfig().DataDbCfg().RplConns, - config.CgrConfig().DataDbCfg().RplFiltered, - utils.RateProfilePrefix, rpp.TenantID(), // this are used to get the host IDs from cache - utils.ReplicatorSv1SetRateProfile, - &utils.RateProfileWithAPIOpts{ - RateProfile: rpp, - APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID, - config.CgrConfig().DataDbCfg().RplCache, utils.EmptyString)}) - } - return -} - -func (dm *DataManager) RemoveRateProfile(tenant, id string, - transactionID string, withIndex bool) (err error) { - if dm == nil { - return utils.ErrNoDatabaseConn - } - oldRpp, err := dm.GetRateProfile(tenant, id, true, false, utils.NonTransactional) - if err != nil && err != utils.ErrNotFound { - return err - } - if err = dm.DataDB().RemoveRateProfileDrv(tenant, id); err != nil { - return - } - if oldRpp == nil { - return utils.ErrNotFound - } - if withIndex { - for key, rate := range oldRpp.Rates { - if err = removeItemFromFilterIndex(dm, utils.CacheRateFilterIndexes, - oldRpp.Tenant, oldRpp.ID, key, rate.FilterIDs); err != nil { - return - } - } - if err = removeItemFromFilterIndex(dm, utils.CacheRateProfilesFilterIndexes, - tenant, utils.EmptyString, id, oldRpp.FilterIDs); err != nil { - return - } - } - if itm := config.CgrConfig().DataDbCfg().Items[utils.MetaRateProfiles]; itm.Replicate { - replicate(dm.connMgr, config.CgrConfig().DataDbCfg().RplConns, - config.CgrConfig().DataDbCfg().RplFiltered, - utils.RateProfilePrefix, utils.ConcatenatedKey(tenant, id), // this are used to get the host IDs from cache - utils.ReplicatorSv1RemoveRateProfile, - &utils.TenantIDWithAPIOpts{ - TenantID: &utils.TenantID{Tenant: tenant, ID: id}, - APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID, - config.CgrConfig().DataDbCfg().RplCache, utils.EmptyString)}) - } - return -} - -func (dm *DataManager) RemoveRateProfileRates(tenant, id string, rateIDs []string, withIndex bool) (err error) { - if dm == nil { - return utils.ErrNoDatabaseConn - } - oldRpp, err := dm.GetRateProfile(tenant, id, true, false, utils.NonTransactional) - if err != nil { - return err - } - if len(rateIDs) == 0 { - if withIndex { - for key, rate := range oldRpp.Rates { - if err = removeItemFromFilterIndex(dm, utils.CacheRateFilterIndexes, - tenant, id, key, rate.FilterIDs); err != nil { - return - } - } - } - oldRpp.Rates = map[string]*utils.Rate{} - } else { - for _, rateID := range rateIDs { - if _, has := oldRpp.Rates[rateID]; !has { - continue - } - if withIndex { - - if err = removeItemFromFilterIndex(dm, utils.CacheRateFilterIndexes, - tenant, id, rateID, oldRpp.Rates[rateID].FilterIDs); err != nil { - return - } - } - delete(oldRpp.Rates, rateID) - } - } - if err = dm.DataDB().SetRateProfileDrv(oldRpp); err != nil { - return err - } - - if itm := config.CgrConfig().DataDbCfg().Items[utils.MetaRateProfiles]; itm.Replicate { - err = replicate(dm.connMgr, config.CgrConfig().DataDbCfg().RplConns, - config.CgrConfig().DataDbCfg().RplFiltered, - utils.RateProfilePrefix, oldRpp.TenantID(), // this are used to get the host IDs from cache - utils.ReplicatorSv1SetRateProfile, - &utils.RateProfileWithAPIOpts{ - RateProfile: oldRpp, - APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID, - config.CgrConfig().DataDbCfg().RplCache, utils.EmptyString)}) - } - return -} - -func (dm *DataManager) SetRateProfileRates(rpp *utils.RateProfile, withIndex bool) (err error) { - if dm == nil { - return utils.ErrNoDatabaseConn - } - if withIndex { - for _, rate := range rpp.Rates { - if brokenReference := dm.checkFilters(rpp.Tenant, rate.FilterIDs); len(brokenReference) != 0 { - // if we get a broken filter do not update the rates - return fmt.Errorf("broken reference to filter: %+v for rate with ID: %+v", - brokenReference, rate.ID) - } - } - } - oldRpp, err := dm.GetRateProfile(rpp.Tenant, rpp.ID, true, false, utils.NonTransactional) - if err != nil { - return err - } - // create index for each rate - for key, rate := range rpp.Rates { - if withIndex { - var oldRateFiltersIDs *[]string - if oldRate, has := oldRpp.Rates[key]; has { - oldRateFiltersIDs = &oldRate.FilterIDs - } - // when we create the indexes for rates we use RateProfile ID as context - if err := updatedIndexes(dm, utils.CacheRateFilterIndexes, rpp.Tenant, - rpp.ID, key, oldRateFiltersIDs, rate.FilterIDs, true); err != nil { - return err - } - } - oldRpp.Rates[key] = rate - } - - if err = dm.DataDB().SetRateProfileDrv(oldRpp); err != nil { - return err - } - - if itm := config.CgrConfig().DataDbCfg().Items[utils.MetaRateProfiles]; itm.Replicate { - err = replicate(dm.connMgr, config.CgrConfig().DataDbCfg().RplConns, - config.CgrConfig().DataDbCfg().RplFiltered, - utils.RateProfilePrefix, oldRpp.TenantID(), // this are used to get the host IDs from cache - utils.ReplicatorSv1SetRateProfile, - &utils.RateProfileWithAPIOpts{ - RateProfile: oldRpp, - APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID, - config.CgrConfig().DataDbCfg().RplCache, utils.EmptyString)}) - } - return -} - func (dm *DataManager) GetActionProfile(tenant, id string, cacheRead, cacheWrite bool, transactionID string) (ap *ActionProfile, err error) { tntID := utils.ConcatenatedKey(tenant, id) diff --git a/engine/libindex.go b/engine/libindex.go index f90ffec5a..ca6e3baf8 100644 --- a/engine/libindex.go +++ b/engine/libindex.go @@ -19,7 +19,6 @@ along with this program. If not, see package engine import ( - "errors" "fmt" "strings" @@ -179,8 +178,6 @@ func removeItemFromFilterIndex(dm *DataManager, idxItmType, tnt, ctx, itemID str // itemID - the object id // oldFilterIds - the filtersIDs that the old object had; this is optional if the object did not exist // newFilterIDs - the filtersIDs for the object that will be set -// useCtx - in case of subindexes(e.g. Rate from RateProfiles) need to add the ctx to the itemID when reverse filter indexes are set -// used when updating the filters func updatedIndexes(dm *DataManager, idxItmType, tnt, ctx, itemID string, oldFilterIds *[]string, newFilterIDs []string, useCtx bool) (err error) { itmCtx := itemID if useCtx { @@ -713,73 +710,6 @@ func UpdateFilterIndex(dm *DataManager, oldFlt, newFlt *Filter) (err error) { }); err != nil && err != utils.ErrNotFound { return utils.APIErrorHandler(err) } - case utils.CacheRateProfilesFilterIndexes: - if err = removeFilterIndexesForFilter(dm, idxItmType, newFlt.Tenant, //remove the indexes for the filter - removeIndexKeys, indx); err != nil { - return - } - idxSlice := indx.AsSlice() - if _, err = ComputeIndexes(dm, newFlt.Tenant, utils.EmptyString, idxItmType, // compute all the indexes for afected items - &idxSlice, utils.NonTransactional, func(tnt, id, ctx string) (*[]string, error) { - rp, e := dm.GetRateProfile(tnt, id, true, false, utils.NonTransactional) - if e != nil { - return nil, e - } - fltrIDs := make([]string, len(rp.FilterIDs)) - for i, fltrID := range rp.FilterIDs { - fltrIDs[i] = fltrID - } - return &fltrIDs, nil - }); err != nil && err != utils.ErrNotFound { - return utils.APIErrorHandler(err) - } - - case utils.CacheRateFilterIndexes: - itemIDs := make(map[string]utils.StringSet) - for itemID := range indx { - idSplit := strings.SplitN(itemID, utils.ConcatenatedKeySep, 2) - if len(idSplit) < 2 { - return errors.New("Expected to be 2 values") - } - if itemIDs[idSplit[1]] == nil { - itemIDs[idSplit[1]] = make(utils.StringSet) - } - itemIDs[idSplit[1]].Add(idSplit[0]) - } - for rpID, ids := range itemIDs { - tntCtx := utils.ConcatenatedKey(newFlt.Tenant, rpID) - if err = removeFilterIndexesForFilter(dm, idxItmType, tntCtx, - removeIndexKeys, ids); err != nil { - return - } - var rp *utils.RateProfile - if rp, err = dm.GetRateProfile(newFlt.Tenant, rpID, true, false, utils.NonTransactional); err != nil { - return - } - for itemID := range ids { - rate, has := rp.Rates[itemID] - if !has { - return utils.ErrNotFound - } - refID := guardian.Guardian.GuardIDs(utils.EmptyString, - config.CgrConfig().GeneralCfg().LockingTimeout, idxItmType+tntCtx) - var updIdx map[string]utils.StringSet - if updIdx, err = newFilterIndex(dm, idxItmType, - newFlt.Tenant, rpID, itemID, rate.FilterIDs); err != nil { - guardian.Guardian.UnguardIDs(refID) - return - } - for _, idx := range updIdx { - idx.Add(itemID) - } - if err = dm.SetIndexes(idxItmType, tntCtx, - updIdx, false, utils.NonTransactional); err != nil { - guardian.Guardian.UnguardIDs(refID) - return - } - guardian.Guardian.UnguardIDs(refID) - } - } case utils.CacheAttributeFilterIndexes: for itemID := range indx { var ap *AttributeProfile diff --git a/engine/libtest.go b/engine/libtest.go index d6e19adc7..a6c6c2fe4 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -280,22 +280,6 @@ cgrates.org,D1,,,,*first,,C2,*lt:~*req.Usage:10,10,false,192.168.56.204, DispatcherHostCSVContent = ` #Tenant[0],ID[1],Address[2],Transport[3],TLS[4] cgrates.org,ALL1,127.0.0.1:2012,*json,true -` - RateProfileCSVContent = ` -#Tenant,ID,FilterIDs,ActivationInterval,Weights,MinCost,MaxCost,MaxCostStrategy,RateID,RateFilterIDs,RateActivationStart,RateWeights,RateBlocker,RateIntervalStart,RateFixedFee,RateRecurrentFee,RateUnit,RateIncrement -cgrates.org,RP1,*string:~*req.Subject:1001,,;0,0.1,0.6,*free,RT_WEEK,,"* * * * 1-5",;0,false,0s,0,0.12,1m,1m -cgrates.org,RP1,,,,,,,RT_WEEK,,,,,1m,1.234,0.06,1m,1s -cgrates.org,RP1,,,,,,,RT_WEEKEND,,"* * * * 0,6",;10,false,0s,0.089,0.06,1m,1s -cgrates.org,RP1,,,,,,,RT_CHRISTMAS,,* * 24 12 *,;30,false,0s,0.0564,0.06,1m,1s -` - ActionProfileCSVContent = ` -#Tenant,ID,FilterIDs,ActivationInterval,Weight,Schedule,TargetType,TargetIDs,ActionID,ActionFilterIDs,ActionBlocker,ActionTTL,ActionType,ActionOpts,ActionPath,ActionValue -cgrates.org,ONE_TIME_ACT,,,10,*asap,*accounts,1001;1002,TOPUP,,false,0s,*add_balance,,*balance.TestBalance.Value,10 -cgrates.org,ONE_TIME_ACT,,,,,,,SET_BALANCE_TEST_DATA,,false,0s,*set_balance,,*balance.TestDataBalance.Type,*data -cgrates.org,ONE_TIME_ACT,,,,,,,TOPUP_TEST_DATA,,false,0s,*add_balance,,*balance.TestDataBalance.Value,1024 -cgrates.org,ONE_TIME_ACT,,,,,,,SET_BALANCE_TEST_VOICE,,false,0s,*set_balance,,*balance.TestVoiceBalance.Type,*voice -cgrates.org,ONE_TIME_ACT,,,,,,,TOPUP_TEST_VOICE,,false,0s,*add_balance,,*balance.TestVoiceBalance.Value,15m15s -cgrates.org,ONE_TIME_ACT,,,,,,,TOPUP_TEST_VOICE,,false,0s,*add_balance,,*balance.TestVoiceBalance2.Value,15m15s ` ) @@ -502,59 +486,54 @@ func CallScript(scriptPath string, subcommand string, waitMs int) error { func GetDefaultEmptyCacheStats() map[string]*ltcache.CacheStats { return map[string]*ltcache.CacheStats{ - utils.MetaDefault: {}, - utils.CacheAccountActionPlans: {}, - utils.CacheActionPlans: {}, - utils.CacheActionTriggers: {}, - utils.CacheActions: {}, - utils.CacheAttributeFilterIndexes: {}, - utils.CacheAttributeProfiles: {}, - utils.CacheChargerFilterIndexes: {}, - utils.CacheChargerProfiles: {}, - utils.CacheDispatcherFilterIndexes: {}, - utils.CacheDispatcherProfiles: {}, - utils.CacheDispatcherHosts: {}, - utils.CacheDispatcherRoutes: {}, - utils.CacheDispatcherLoads: {}, - utils.CacheDispatchers: {}, - utils.CacheDestinations: {}, - utils.CacheEventResources: {}, - utils.CacheFilters: {}, - utils.CacheRatingPlans: {}, - utils.CacheRatingProfiles: {}, - utils.CacheResourceFilterIndexes: {}, - utils.CacheResourceProfiles: {}, - utils.CacheResources: {}, - utils.CacheReverseDestinations: {}, - utils.CacheRPCResponses: {}, - utils.CacheSharedGroups: {}, - utils.CacheStatFilterIndexes: {}, - utils.CacheStatQueueProfiles: {}, - utils.CacheStatQueues: {}, - utils.CacheSTIR: {}, - utils.CacheRouteFilterIndexes: {}, - utils.CacheRouteProfiles: {}, - utils.CacheThresholdFilterIndexes: {}, - utils.CacheThresholdProfiles: {}, - utils.CacheThresholds: {}, - utils.CacheRateProfiles: {}, - utils.CacheRateProfilesFilterIndexes: {}, - utils.CacheRateFilterIndexes: {}, - utils.CacheTimings: {}, - utils.CacheDiameterMessages: {}, - utils.CacheClosedSessions: {}, - utils.CacheLoadIDs: {}, - utils.CacheRPCConnections: {}, - utils.CacheCDRIDs: {}, - utils.CacheRatingProfilesTmp: {}, - utils.CacheUCH: {}, - utils.CacheEventCharges: {}, - utils.CacheReverseFilterIndexes: {}, - utils.MetaAPIBan: {}, - utils.CacheCapsEvents: {}, - utils.CacheActionProfiles: {}, - utils.CacheActionProfilesFilterIndexes: {}, - utils.CacheReplicationHosts: {}, + utils.MetaDefault: {}, + utils.CacheAccountActionPlans: {}, + utils.CacheActionPlans: {}, + utils.CacheActionTriggers: {}, + utils.CacheActions: {}, + utils.CacheAttributeFilterIndexes: {}, + utils.CacheAttributeProfiles: {}, + utils.CacheChargerFilterIndexes: {}, + utils.CacheChargerProfiles: {}, + utils.CacheDispatcherFilterIndexes: {}, + utils.CacheDispatcherProfiles: {}, + utils.CacheDispatcherHosts: {}, + utils.CacheDispatcherRoutes: {}, + utils.CacheDispatcherLoads: {}, + utils.CacheDispatchers: {}, + utils.CacheDestinations: {}, + utils.CacheEventResources: {}, + utils.CacheFilters: {}, + utils.CacheRatingPlans: {}, + utils.CacheRatingProfiles: {}, + utils.CacheResourceFilterIndexes: {}, + utils.CacheResourceProfiles: {}, + utils.CacheResources: {}, + utils.CacheReverseDestinations: {}, + utils.CacheRPCResponses: {}, + utils.CacheSharedGroups: {}, + utils.CacheStatFilterIndexes: {}, + utils.CacheStatQueueProfiles: {}, + utils.CacheStatQueues: {}, + utils.CacheSTIR: {}, + utils.CacheRouteFilterIndexes: {}, + utils.CacheRouteProfiles: {}, + utils.CacheThresholdFilterIndexes: {}, + utils.CacheThresholdProfiles: {}, + utils.CacheThresholds: {}, + utils.CacheTimings: {}, + utils.CacheDiameterMessages: {}, + utils.CacheClosedSessions: {}, + utils.CacheLoadIDs: {}, + utils.CacheRPCConnections: {}, + utils.CacheCDRIDs: {}, + utils.CacheRatingProfilesTmp: {}, + utils.CacheUCH: {}, + utils.CacheEventCharges: {}, + utils.CacheReverseFilterIndexes: {}, + utils.MetaAPIBan: {}, + utils.CacheCapsEvents: {}, + utils.CacheReplicationHosts: {}, utils.CacheAccounts: {}, utils.CacheVersions: {}, @@ -580,7 +559,6 @@ func GetDefaultEmptyCacheStats() map[string]*ltcache.CacheStats { utils.CacheTBLTPChargers: {}, utils.CacheTBLTPDispatchers: {}, utils.CacheTBLTPDispatcherHosts: {}, - utils.CacheTBLTPRateProfiles: {}, utils.CacheTBLTPActionProfiles: {}, } } @@ -608,7 +586,6 @@ func GetDefaultEmptyArgCachePrefix() map[string][]string { utils.ChargerProfilePrefix: nil, utils.DispatcherProfilePrefix: nil, utils.DispatcherHostPrefix: nil, - utils.RateProfilePrefix: nil, utils.ActionProfilePrefix: nil, utils.TimingsPrefix: nil, utils.AttributeFilterIndexes: nil, @@ -618,8 +595,6 @@ func GetDefaultEmptyArgCachePrefix() map[string][]string { utils.RouteFilterIndexes: nil, utils.ChargerFilterIndexes: nil, utils.DispatcherFilterIndexes: nil, - utils.RateProfilesFilterIndexPrfx: nil, - utils.RateFilterIndexPrfx: nil, utils.ActionProfilesFilterIndexPrfx: nil, utils.FilterIndexPrfx: nil, } diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index cfaddb447..146dee532 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -42,7 +42,7 @@ func init() { ActionsCSVContent, ActionPlansCSVContent, ActionTriggersCSVContent, AccountActionsCSVContent, ResourcesCSVContent, StatsCSVContent, ThresholdsCSVContent, FiltersCSVContent, RoutesCSVContent, AttributesCSVContent, ChargersCSVContent, DispatcherCSVContent, - DispatcherHostCSVContent, RateProfileCSVContent, ActionProfileCSVContent), testTPID, "", nil, nil, false) + DispatcherHostCSVContent), testTPID, "", nil, nil, false) if err != nil { log.Print("error when creating TpReader:", err) } @@ -106,9 +106,6 @@ func init() { if err := csvr.LoadDispatcherHosts(); err != nil { log.Print("error in LoadDispatcherHosts:", err) } - if err := csvr.LoadRateProfiles(); err != nil { - log.Print("error in LoadRateProfiles:", err) - } if err := csvr.LoadActionProfiles(); err != nil { log.Print("error in LoadActionProfiles: ", err) } @@ -1398,81 +1395,6 @@ func TestLoadDispatcherProfiles(t *testing.T) { } } -func TestLoadRateProfiles(t *testing.T) { - eRatePrf := &utils.TPRateProfile{ - TPid: testTPID, - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - RecurrentFee: 0.12, - Unit: "1m", - Increment: "1m", - }, - { - IntervalStart: "1m", - FixedFee: 1.234, - RecurrentFee: 0.06, - Unit: "1m", - Increment: "1s", - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: ";10", - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - FixedFee: 0.089, - RecurrentFee: 0.06, - Unit: "1m", - Increment: "1s", - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: ";30", - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - FixedFee: 0.0564, - RecurrentFee: 0.06, - Unit: "1m", - Increment: "1s", - }, - }, - }, - }, - } - if len(csvr.rateProfiles) != 1 { - t.Errorf("Failed to load rateProfiles: %s", utils.ToIJSON(csvr.rateProfiles)) - } - dppKey := utils.TenantID{Tenant: "cgrates.org", ID: "RP1"} - sort.Slice(csvr.rateProfiles[dppKey].Rates["RT_WEEK"].IntervalRates, func(i, j int) bool { - return csvr.rateProfiles[dppKey].Rates["RT_WEEK"].IntervalRates[i].IntervalStart < csvr.rateProfiles[dppKey].Rates["RT_WEEK"].IntervalRates[j].IntervalStart - }) - - if !reflect.DeepEqual(eRatePrf, csvr.rateProfiles[dppKey]) { - t.Errorf("Expecting: %+v,\n received: %+v", - utils.ToJSON(eRatePrf), utils.ToJSON(csvr.rateProfiles[dppKey])) - } -} - func TestLoadActionProfiles(t *testing.T) { expected := &utils.TPActionProfile{ TPid: testTPID, diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 95332534a..6899d19d9 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -1819,7 +1819,7 @@ type RouteMdls []*RouteMdl func (tps RouteMdls) CSVHeader() (result []string) { return []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, utils.ActivationIntervalString, utils.Sorting, utils.SortingParameters, utils.RouteID, utils.RouteFilterIDs, - utils.RouteAccountIDs, utils.RouteRatingplanIDs, utils.RouteRateProfileIDs, utils.RouteResourceIDs, + utils.RouteAccountIDs, utils.RouteRatingplanIDs, utils.RouteResourceIDs, utils.RouteStatIDs, utils.RouteWeight, utils.RouteBlocker, utils.RouteParameters, utils.Weight, } @@ -2867,300 +2867,6 @@ func DispatcherHostToAPI(dph *DispatcherHost) (tpDPH *utils.TPDispatcherHost) { } } -// RateProfileMdls is used -type RateProfileMdls []*RateProfileMdl - -// CSVHeader return the header for csv fields as a slice of string -func (tps RateProfileMdls) CSVHeader() (result []string) { - return []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, - utils.ActivationIntervalString, utils.Weight, utils.ConnectFee, utils.MinCost, - utils.MaxCost, utils.MaxCostStrategy, utils.RateID, - utils.RateFilterIDs, utils.RateActivationStart, utils.RateWeight, utils.RateBlocker, - utils.RateIntervalStart, utils.RateFixedFee, utils.RateRecurrentFee, utils.RateUnit, utils.RateIncrement, - } -} - -func (tps RateProfileMdls) AsTPRateProfile() (result []*utils.TPRateProfile) { - filterMap := make(map[string]utils.StringSet) - mst := make(map[string]*utils.TPRateProfile) - rateMap := make(map[string]map[string]*utils.TPRate) - for _, tp := range tps { - tenID := (&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID() - rPrf, found := mst[tenID] - if !found { - rPrf = &utils.TPRateProfile{ - TPid: tp.Tpid, - Tenant: tp.Tenant, - ID: tp.ID, - } - } - if tp.RateID != utils.EmptyString { - if _, has := rateMap[tenID]; !has { - rateMap[tenID] = make(map[string]*utils.TPRate) - } - rate, found := rateMap[tenID][tp.RateID] - if !found { - rate = &utils.TPRate{ - ID: tp.RateID, - IntervalRates: make([]*utils.TPIntervalRate, 0), - Blocker: tp.RateBlocker, - } - } - if tp.RateFilterIDs != utils.EmptyString { - rateFilterSplit := strings.Split(tp.RateFilterIDs, utils.InfieldSep) - rate.FilterIDs = append(rate.FilterIDs, rateFilterSplit...) - } - if tp.RateActivationTimes != utils.EmptyString { - rate.ActivationTimes = tp.RateActivationTimes - } - if tp.RateWeights != utils.EmptyString { - rate.Weights = tp.RateWeights - } - // create new interval rate and append to the slice - intervalRate := new(utils.TPIntervalRate) - if tp.RateIntervalStart != utils.EmptyString { - intervalRate.IntervalStart = tp.RateIntervalStart - } - if tp.RateFixedFee != 0 { - intervalRate.FixedFee = tp.RateFixedFee - } - if tp.RateRecurrentFee != 0 { - intervalRate.RecurrentFee = tp.RateRecurrentFee - } - if tp.RateIncrement != utils.EmptyString { - intervalRate.Increment = tp.RateIncrement - } - if tp.RateUnit != utils.EmptyString { - intervalRate.Unit = tp.RateUnit - } - rate.IntervalRates = append(rate.IntervalRates, intervalRate) - rateMap[tenID][tp.RateID] = rate - } - - if tp.Weights != utils.EmptyString { - rPrf.Weights = tp.Weights - } - if tp.MinCost != 0 { - rPrf.MinCost = tp.MinCost - } - if tp.MaxCost != 0 { - rPrf.MaxCost = tp.MaxCost - } - if tp.MaxCostStrategy != utils.EmptyString { - rPrf.MaxCostStrategy = tp.MaxCostStrategy - } - if tp.ActivationInterval != utils.EmptyString { - rPrf.ActivationInterval = new(utils.TPActivationInterval) - aiSplt := strings.Split(tp.ActivationInterval, utils.InfieldSep) - if len(aiSplt) == 2 { - rPrf.ActivationInterval.ActivationTime = aiSplt[0] - rPrf.ActivationInterval.ExpiryTime = aiSplt[1] - } else if len(aiSplt) == 1 { - rPrf.ActivationInterval.ActivationTime = aiSplt[0] - } - } - if tp.FilterIDs != utils.EmptyString { - if _, has := filterMap[tenID]; !has { - filterMap[tenID] = make(utils.StringSet) - } - filterMap[tenID].AddSlice(strings.Split(tp.FilterIDs, utils.InfieldSep)) - } - mst[tenID] = rPrf - } - result = make([]*utils.TPRateProfile, len(mst)) - i := 0 - for tntID, th := range mst { - result[i] = th - result[i].Rates = rateMap[tntID] - result[i].FilterIDs = filterMap[tntID].AsSlice() - i++ - } - return -} - -func APItoModelTPRateProfile(tPrf *utils.TPRateProfile) (mdls RateProfileMdls) { - if len(tPrf.Rates) == 0 { - return - } - i := 0 - for _, rate := range tPrf.Rates { - for j, intervalRate := range rate.IntervalRates { - mdl := &RateProfileMdl{ - Tenant: tPrf.Tenant, - Tpid: tPrf.TPid, - ID: tPrf.ID, - } - if i == 0 { - for i, val := range tPrf.FilterIDs { - if i != 0 { - mdl.FilterIDs += utils.InfieldSep - } - mdl.FilterIDs += val - } - - if tPrf.ActivationInterval != nil { - if tPrf.ActivationInterval.ActivationTime != utils.EmptyString { - mdl.ActivationInterval = tPrf.ActivationInterval.ActivationTime - } - if tPrf.ActivationInterval.ExpiryTime != utils.EmptyString { - mdl.ActivationInterval += utils.InfieldSep + tPrf.ActivationInterval.ExpiryTime - } - } - mdl.Weights = tPrf.Weights - mdl.MinCost = tPrf.MinCost - mdl.MaxCost = tPrf.MaxCost - mdl.MaxCostStrategy = tPrf.MaxCostStrategy - } - mdl.RateID = rate.ID - if j == 0 { - for i, val := range rate.FilterIDs { - if i != 0 { - mdl.RateFilterIDs += utils.InfieldSep - } - mdl.RateFilterIDs += val - } - mdl.RateWeights = rate.Weights - mdl.RateActivationTimes = rate.ActivationTimes - mdl.RateBlocker = rate.Blocker - - } - mdl.RateRecurrentFee = intervalRate.RecurrentFee - mdl.RateFixedFee = intervalRate.FixedFee - mdl.RateUnit = intervalRate.Unit - mdl.RateIncrement = intervalRate.Increment - mdl.RateIntervalStart = intervalRate.IntervalStart - mdls = append(mdls, mdl) - i++ - } - - } - return -} - -func APItoRateProfile(tpRp *utils.TPRateProfile, timezone string) (rp *utils.RateProfile, err error) { - rp = &utils.RateProfile{ - Tenant: tpRp.Tenant, - ID: tpRp.ID, - FilterIDs: make([]string, len(tpRp.FilterIDs)), - MaxCostStrategy: tpRp.MaxCostStrategy, - Rates: make(map[string]*utils.Rate), - MinCost: utils.NewDecimalFromFloat64(tpRp.MinCost), - MaxCost: utils.NewDecimalFromFloat64(tpRp.MaxCost), - } - if tpRp.Weights != utils.EmptyString { - weight, err := utils.NewDynamicWeightsFromString(tpRp.Weights, ";", "&") - if err != nil { - return nil, err - } - rp.Weights = weight - } - for i, stp := range tpRp.FilterIDs { - rp.FilterIDs[i] = stp - } - if tpRp.ActivationInterval != nil { - if rp.ActivationInterval, err = tpRp.ActivationInterval.AsActivationInterval(timezone); err != nil { - return nil, err - } - } - for key, rate := range tpRp.Rates { - rp.Rates[key] = &utils.Rate{ - ID: rate.ID, - Blocker: rate.Blocker, - FilterIDs: rate.FilterIDs, - ActivationTimes: rate.ActivationTimes, - IntervalRates: make([]*utils.IntervalRate, len(rate.IntervalRates)), - } - if rate.Weights != utils.EmptyString { - weight, err := utils.NewDynamicWeightsFromString(rate.Weights, ";", "&") - if err != nil { - return nil, err - } - rp.Rates[key].Weights = weight - } - for i, iRate := range rate.IntervalRates { - rp.Rates[key].IntervalRates[i] = new(utils.IntervalRate) - if rp.Rates[key].IntervalRates[i].IntervalStart, err = utils.NewDecimalFromUsage(iRate.IntervalStart); err != nil { - return nil, err - } - rp.Rates[key].IntervalRates[i].FixedFee = utils.NewDecimalFromFloat64(iRate.FixedFee) - rp.Rates[key].IntervalRates[i].RecurrentFee = utils.NewDecimalFromFloat64(iRate.RecurrentFee) - if rp.Rates[key].IntervalRates[i].Unit, err = utils.NewDecimalFromUsage(iRate.Unit); err != nil { - return nil, err - } - if rp.Rates[key].IntervalRates[i].Increment, err = utils.NewDecimalFromUsage(iRate.Increment); err != nil { - return nil, err - } - } - } - return rp, nil -} - -func RateProfileToAPI(rp *utils.RateProfile) (tpRp *utils.TPRateProfile) { - tpRp = &utils.TPRateProfile{ - Tenant: rp.Tenant, - ID: rp.ID, - FilterIDs: make([]string, len(rp.FilterIDs)), - ActivationInterval: new(utils.TPActivationInterval), - Weights: rp.Weights.String(";", "&"), - MaxCostStrategy: rp.MaxCostStrategy, - Rates: make(map[string]*utils.TPRate), - } - if rp.MinCost != nil { - //there should not be an invalid value of converting from Decimal into float64 - minCostF, _ := rp.MinCost.Float64() - tpRp.MinCost = minCostF - } - if rp.MaxCost != nil { - //there should not be an invalid value of converting from Decimal into float64 - maxCostF, _ := rp.MaxCost.Float64() - tpRp.MaxCost = maxCostF - } - - for key, rate := range rp.Rates { - tpRp.Rates[key] = &utils.TPRate{ - ID: rate.ID, - Weights: rate.Weights.String(";", "&"), - Blocker: rate.Blocker, - FilterIDs: rate.FilterIDs, - ActivationTimes: rate.ActivationTimes, - IntervalRates: make([]*utils.TPIntervalRate, len(rate.IntervalRates)), - } - for i, iRate := range rate.IntervalRates { - tpRp.Rates[key].IntervalRates[i] = &utils.TPIntervalRate{ - IntervalStart: iRate.IntervalStart.String(), - } - if iRate.FixedFee != nil { - //there should not be an invalid value of converting from Decimal into float64 - fixedFeeF, _ := iRate.FixedFee.Float64() - tpRp.Rates[key].IntervalRates[i].FixedFee = fixedFeeF - } - if iRate.Unit != nil { - tpRp.Rates[key].IntervalRates[i].Unit = iRate.Unit.String() - } - if iRate.Increment != nil { - tpRp.Rates[key].IntervalRates[i].Increment = iRate.Increment.String() - } - if iRate.RecurrentFee != nil { - //there should not be an invalid value of converting from Decimal into float64 - recFeeF, _ := iRate.RecurrentFee.Float64() - tpRp.Rates[key].IntervalRates[i].RecurrentFee = recFeeF - } - } - } - for i, fli := range rp.FilterIDs { - tpRp.FilterIDs[i] = fli - } - if rp.ActivationInterval != nil { - if !rp.ActivationInterval.ActivationTime.IsZero() { - tpRp.ActivationInterval.ActivationTime = rp.ActivationInterval.ActivationTime.Format(time.RFC3339) - } - if !rp.ActivationInterval.ExpiryTime.IsZero() { - tpRp.ActivationInterval.ExpiryTime = rp.ActivationInterval.ExpiryTime.Format(time.RFC3339) - } - } - return -} - type ActionProfileMdls []*ActionProfileMdl // CSVHeader return the header for csv fields as a slice of string diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go index 335de7efe..99d81c2df 100644 --- a/engine/model_helpers_test.go +++ b/engine/model_helpers_test.go @@ -2829,7 +2829,7 @@ func TestCsvHeader(t *testing.T) { eOut := []string{ "#" + utils.Tenant, utils.ID, utils.FilterIDs, utils.ActivationIntervalString, utils.Sorting, utils.SortingParameters, utils.RouteID, utils.RouteFilterIDs, - utils.RouteAccountIDs, utils.RouteRatingplanIDs, utils.RouteRateProfileIDs, utils.RouteResourceIDs, + utils.RouteAccountIDs, utils.RouteRatingplanIDs, utils.RouteResourceIDs, utils.RouteStatIDs, utils.RouteWeight, utils.RouteBlocker, utils.RouteParameters, utils.Weight, } @@ -4289,597 +4289,6 @@ func TestTPRoutesAsTPRouteProfile2(t *testing.T) { } } -func TestRateProfileToAPI(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - FixedFee: utils.NewDecimal(234, 5), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - eTPRatePrf := &utils.TPRateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - ActivationInterval: &utils.TPActivationInterval{ - ActivationTime: "", - ExpiryTime: "", - }, - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0", - RecurrentFee: 0.12, - Unit: "60000000000", - Increment: "1000000000", - }, - { - IntervalStart: "60000000000", - FixedFee: 0.00234, - RecurrentFee: 0.06, - Unit: "60000000000", - Increment: "1000000000", - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: ";10", - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0", - RecurrentFee: 0.06, - Unit: "60000000000", - Increment: "1000000000", - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: ";30", - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0", - RecurrentFee: 0.06, - Unit: "60000000000", - Increment: "1000000000", - }, - }, - }, - }, - } - if rcv := RateProfileToAPI(rPrf); !reflect.DeepEqual(rcv, eTPRatePrf) { - t.Errorf("Expecting: %+v,\nReceived: %+v", utils.ToJSON(eTPRatePrf), utils.ToJSON(rcv)) - } -} - -func TestAPIToRateProfile(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - eRprf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(23451, 4), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - tpRprf := &utils.TPRateProfile{ - TPid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - FixedFee: 2.3451, - RecurrentFee: 0.12, - Unit: "1m0s", - Increment: "1m0s", - }, - { - IntervalStart: "1m0s", - RecurrentFee: 0.06, - Unit: "1m0s", - Increment: "1s", - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: ";10", - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - RecurrentFee: 0.06, - Unit: "1m0s", - Increment: "1s", - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: ";30", - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - RecurrentFee: 0.06, - Unit: "1m0s", - Increment: "1s", - }, - }, - }, - }, - } - if rcv, err := APItoRateProfile(tpRprf, utils.EmptyString); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcv, eRprf) { - t.Errorf("Expecting: %+v,\nReceived: %+v", utils.ToJSON(eRprf), utils.ToJSON(rcv)) - } -} - -func TestAPItoRateProfileError(t *testing.T) { - tpRprf := &utils.TPRateProfile{ - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: "0", - Rates: map[string]*utils.TPRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: "0", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - RecurrentFee: 0.06, - Unit: "1ss", - Increment: "1ss", - }, - }, - }, - }, - } - expectedErr := "invalid DynamicWeight format for string <0>" - if _, err := APItoRateProfile(tpRprf, utils.EmptyString); err == nil || err.Error() != expectedErr { - t.Error(err) - } - - tpRprf.Weights = ";0" - if _, err := APItoRateProfile(tpRprf, utils.EmptyString); err == nil || err.Error() != expectedErr { - t.Error(err) - } - - tpRprf.Rates["RT_WEEK"].Weights = ";0" - expectedErr = "time: unknown unit \"ss\" in duration \"1ss\"" - if _, err := APItoRateProfile(tpRprf, utils.EmptyString); err == nil || err.Error() != expectedErr { - t.Error(err) - } - - tpRprf.Rates["RT_WEEK"].IntervalRates[0].Unit = "1s" - if _, err := APItoRateProfile(tpRprf, utils.EmptyString); err == nil || err.Error() != expectedErr { - t.Error(err) - } -} - -func TestAPIToRateProfileError(t *testing.T) { - tpRprf := &utils.TPRateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - ActivationInterval: &utils.TPActivationInterval{ - ExpiryTime: "NOT_A_TIME", - }, - Rates: map[string]*utils.TPRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "NOT_A_TIME", - FixedFee: 2.3451, - RecurrentFee: 0.12, - }, - }, - }, - }, - } - expectedErr := "Unsupported time format" - if _, err := APItoRateProfile(tpRprf, "UTC"); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } - - expectedErr = "strconv.ParseInt: parsing \"NOT_A_TIME\": invalid syntax" - tpRprf.ActivationInterval = nil - if _, err := APItoRateProfile(tpRprf, "UTC"); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+q", expectedErr, err) - } -} - -func TestAPItoModelTPRateProfile(t *testing.T) { - tpRprf := &utils.TPRateProfile{ - TPid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - RecurrentFee: 0.12, - Unit: "1m0s", - Increment: "1m0s", - }, - { - IntervalStart: "1m", - RecurrentFee: 0.06, - Unit: "1m0s", - Increment: "1s", - }, - }, - }, - }, - } - - expModels := RateProfileMdls{ - &RateProfileMdl{ - PK: 0, - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "*string:~*req.Subject:1001", - ActivationInterval: "", - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - RateID: "RT_WEEK", - RateFilterIDs: "", - RateActivationTimes: "* * * * 1-5", - RateWeights: ";0", - RateBlocker: false, - RateIntervalStart: "1m", - RateRecurrentFee: 0.06, - RateUnit: "1m0s", - RateIncrement: "1s", - CreatedAt: time.Time{}, - }, - &RateProfileMdl{ - PK: 0, - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "", - ActivationInterval: "", - Weights: ";0", - MinCost: 0, - MaxCost: 0, - MaxCostStrategy: "", - RateID: "RT_WEEK", - RateFilterIDs: "", - RateActivationTimes: "", - RateWeights: ";0", - RateBlocker: false, - RateIntervalStart: "0s", - RateRecurrentFee: 0.12, - RateUnit: "1m0s", - RateIncrement: "1m0s", - CreatedAt: time.Time{}, - }, - } - expModelsRev := RateProfileMdls{ - &RateProfileMdl{ - PK: 0, - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "*string:~*req.Subject:1001", - ActivationInterval: "", - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - RateID: "RT_WEEK", - RateFilterIDs: "", - RateActivationTimes: "* * * * 1-5", - RateWeights: ";0", - RateBlocker: false, - RateIntervalStart: "0s", - RateRecurrentFee: 0.12, - RateUnit: "1m0s", - RateIncrement: "1m0s", - CreatedAt: time.Time{}, - }, - &RateProfileMdl{ - PK: 0, - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "", - ActivationInterval: "", - Weights: "", - MinCost: 0, - MaxCost: 0, - MaxCostStrategy: "", - RateID: "RT_WEEK", - RateFilterIDs: "", - RateActivationTimes: "", - RateWeights: "", - RateBlocker: false, - RateIntervalStart: "1m", - RateRecurrentFee: 0.06, - RateUnit: "1m0s", - RateIncrement: "1s", - CreatedAt: time.Time{}, - }, - } - rcv := APItoModelTPRateProfile(tpRprf) - if !reflect.DeepEqual(rcv, expModels) && !reflect.DeepEqual(rcv, expModelsRev) { - t.Errorf("Expecting: %+v or \n%+v,\nReceived: %+v", utils.ToJSON(expModels), utils.ToJSON(expModelsRev), utils.ToJSON(rcv)) - } -} - -func TestAsTPRateProfile(t *testing.T) { - rtMdl := RateProfileMdls{ - &RateProfileMdl{ - PK: 0, - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "*string:~*req.Subject:1001", - ActivationInterval: "", - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - RateID: "RT_WEEK", - RateFilterIDs: "", - RateActivationTimes: "* * * * 1-5", - RateWeights: ";0", - RateBlocker: false, - RateIntervalStart: "1m", - RateRecurrentFee: 0.06, - RateUnit: "1m", - RateIncrement: "1s", - CreatedAt: time.Time{}, - }, - &RateProfileMdl{ - PK: 0, - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "", - ActivationInterval: "", - Weights: ";0", - MinCost: 0, - MaxCost: 0, - MaxCostStrategy: "", - RateID: "RT_WEEK", - RateFilterIDs: "", - RateActivationTimes: "", - RateWeights: ";0", - RateBlocker: false, - RateIntervalStart: "0s", - RateRecurrentFee: 0.12, - RateUnit: "1m", - RateIncrement: "1m", - CreatedAt: time.Time{}, - }, - } - - eRprf := &utils.TPRateProfile{ - TPid: utils.EmptyString, - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "1m", - RecurrentFee: 0.06, - Unit: "1m", - Increment: "1s", - }, - { - IntervalStart: "0s", - RecurrentFee: 0.12, - Unit: "1m", - Increment: "1m", - }, - }, - }, - }, - } - rcv := rtMdl.AsTPRateProfile() - if len(rcv) != 1 { - t.Errorf("Expecting: %+v,\nReceived: %+v", 1, len(rcv)) - } else if !reflect.DeepEqual(rcv[0], eRprf) { - t.Errorf("Expecting: %+v,\nReceived: %+v", utils.ToJSON(eRprf), utils.ToJSON(rcv[0])) - } -} - func TestModelHelperCsvLoadError(t *testing.T) { type testStruct struct { Id int64 @@ -5193,111 +4602,6 @@ func TestRouteProfileToAPICase1(t *testing.T) { } -func TestRateProfileToAPIWithActInterval(t *testing.T) { - testProfile := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - ActivationInterval: &utils.ActivationInterval{ - ActivationTime: time.Date(2020, time.April, - 11, 21, 34, 01, 0, time.UTC), - ExpiryTime: time.Date(2020, time.April, - 12, 21, 34, 01, 0, time.UTC), - }, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{}, - } - - expStruct := &utils.TPRateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - ActivationInterval: &utils.TPActivationInterval{ - ActivationTime: "2020-04-11T21:34:01Z", - ExpiryTime: "2020-04-12T21:34:01Z", - }, - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{}, - } - if result := RateProfileToAPI(testProfile); !reflect.DeepEqual(expStruct, result) { - t.Errorf("\nExpecting <%+v>,\n Received <%+v>", utils.ToJSON(expStruct), utils.ToJSON(result)) - } -} - -func TestAPItoModelTPRateProfileNil(t *testing.T) { - testStruct := &utils.TPRateProfile{ - Rates: map[string]*utils.TPRate{}, - } - result := APItoModelTPRateProfile(testStruct) - if !reflect.DeepEqual(utils.ToJSON(result), "null") { - t.Errorf("\nExpecting ,\n Received <%+v>", utils.ToJSON(result)) - } -} - -func TestAPItoModelTPRateProfileCase2(t *testing.T) { - testStruct := &utils.TPRateProfile{ - FilterIDs: []string{"test_string1", "test_string2"}, - ActivationInterval: &utils.TPActivationInterval{ - ActivationTime: "2014-07-29T15:00:00Z", - ExpiryTime: "2014-08-29T15:00:00Z", - }, - Rates: map[string]*utils.TPRate{"RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - FilterIDs: []string{"test_string1", "test_string2"}, - Weights: ";30", - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "0s", - RecurrentFee: 0.06, - Unit: "1m0s", - Increment: "1s", - }, - }, - }, - }, - } - expStruct := RateProfileMdls{{ - FilterIDs: "test_string1;test_string2", - ActivationInterval: "2014-07-29T15:00:00Z;2014-08-29T15:00:00Z", - RateID: "RT_CHRISTMAS", - RateFilterIDs: "test_string1;test_string2", - RateWeights: ";30", - RateActivationTimes: "* * 24 12 *", - RateIntervalStart: "0s", - RateRecurrentFee: 0.06, - RateUnit: "1m0s", - RateIncrement: "1s", - }} - result := APItoModelTPRateProfile(testStruct) - if !reflect.DeepEqual(result, expStruct) { - t.Errorf("\nExpecting <%+v>>,\n Received <%+v>", utils.ToJSON(expStruct), utils.ToJSON(result)) - } -} - -func TestRateProfileMdlsCSVHeader(t *testing.T) { - testRPMdls := RateProfileMdls{} - result := testRPMdls.CSVHeader() - expected := []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, - utils.ActivationIntervalString, utils.Weight, utils.ConnectFee, utils.MinCost, - utils.MaxCost, utils.MaxCostStrategy, utils.RateID, - utils.RateFilterIDs, utils.RateActivationStart, utils.RateWeight, utils.RateBlocker, - utils.RateIntervalStart, utils.RateFixedFee, utils.RateRecurrentFee, utils.RateUnit, utils.RateIncrement} - if !reflect.DeepEqual(result, expected) { - t.Errorf("\nExpecting <%+v>,\n Received <%+v>", expected, result) - } -} - func TestDispatcherProfileToAPICase2(t *testing.T) { structTest := &DispatcherProfile{ Subsystems: []string{}, @@ -5507,113 +4811,6 @@ func TestChargerProfileToAPILastCase(t *testing.T) { } } -func TestRateProfileMdlsAsTPRateProfileCase2(t *testing.T) { - testRPMdls := RateProfileMdls{&RateProfileMdl{ - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "*string:~*req.Subject:1001", - ActivationInterval: "2014-07-29T15:00:00Z;2014-08-29T15:00:00Z", - Weights: ";1.2", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - RateID: "0", - RateFilterIDs: "test_filter_id", - RateWeights: ";2", - }, - } - expStruct := []*utils.TPRateProfile{ - {TPid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - ActivationInterval: &utils.TPActivationInterval{ - ActivationTime: "2014-07-29T15:00:00Z", - ExpiryTime: "2014-08-29T15:00:00Z", - }, - Weights: ";1.2", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "0": { - ID: "0", - FilterIDs: []string{"test_filter_id"}, - Weights: ";2", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "", - FixedFee: 0, - RecurrentFee: 0, - Unit: "", - Increment: "", - }, - }, - }, - }, - }, - } - result := testRPMdls.AsTPRateProfile() - if !reflect.DeepEqual(result, expStruct) { - t.Errorf("\nExpecting <%+v>,\n Received <%+v>", utils.ToJSON(expStruct), utils.ToJSON(result)) - } - -} - -func TestRateProfileMdlsAsTPRateProfileCase3(t *testing.T) { - testRPMdls := RateProfileMdls{&RateProfileMdl{ - Tpid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: "*string:~*req.Subject:1001", - ActivationInterval: "2014-07-29T15:00:00Z", - Weights: ";1.2", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - RateID: "0", - RateFilterIDs: "test_filter_id", - RateWeights: ";2", - }, - } - expStruct := []*utils.TPRateProfile{ - {TPid: "", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - ActivationInterval: &utils.TPActivationInterval{ - ActivationTime: "2014-07-29T15:00:00Z", - }, - Weights: ";1.2", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "0": { - ID: "0", - FilterIDs: []string{"test_filter_id"}, - Weights: ";2", - IntervalRates: []*utils.TPIntervalRate{ - { - IntervalStart: "", - FixedFee: 0, - RecurrentFee: 0, - Unit: "", - Increment: "", - }, - }, - }, - }, - }, - } - result := testRPMdls.AsTPRateProfile() - if !reflect.DeepEqual(result, expStruct) { - t.Errorf("\nExpecting <%+v>,\n Received <%+v>", utils.ToJSON(expStruct), utils.ToJSON(result)) - } - -} - func TestAPItoModelTPDispatcherProfileCase2(t *testing.T) { structTest := &utils.TPDispatcherProfile{ ActivationInterval: &utils.TPActivationInterval{ diff --git a/engine/models.go b/engine/models.go index 6bf406dcf..508fc3e6e 100644 --- a/engine/models.go +++ b/engine/models.go @@ -510,35 +510,6 @@ func (DispatcherHostMdl) TableName() string { return utils.TBLTPDispatcherHosts } -type RateProfileMdl struct { - PK uint `gorm:"primary_key"` - Tpid string - Tenant string `index:"0" re:""` - ID string `index:"1" re:""` - FilterIDs string `index:"2" re:""` - ActivationInterval string `index:"3" re:""` - Weights string `index:"4" re:""` - MinCost float64 `index:"5" re:"\d+\.?\d*""` - MaxCost float64 `index:"6" re:"\d+\.?\d*"` - MaxCostStrategy string `index:"7" re:""` - RateID string `index:"8" re:""` - RateFilterIDs string `index:"9" re:""` - RateActivationTimes string `index:"10" re:""` - RateWeights string `index:"11" re:""` - RateBlocker bool `index:"12" re:""` - RateIntervalStart string `index:"13" re:""` - RateFixedFee float64 `index:"14" re:"\d+\.?\d*"` - RateRecurrentFee float64 `index:"15" re:"\d+\.?\d*"` - RateUnit string `index:"16" re:""` - RateIncrement string `index:"17" re:""` - - CreatedAt time.Time -} - -func (RateProfileMdl) TableName() string { - return utils.TBLTPRateProfiles -} - type ActionProfileMdl struct { PK uint `gorm:"primary_key"` Tpid string diff --git a/engine/storage_csv.go b/engine/storage_csv.go index b4ab4d3c7..bcd5bafbf 100644 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -64,7 +64,6 @@ type CSVStorage struct { chargerProfilesFn []string dispatcherProfilesFn []string dispatcherHostsFn []string - rateProfilesFn []string actionProfilesFn []string } @@ -74,8 +73,7 @@ func NewCSVStorage(sep rune, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, resProfilesFn, statsFn, thresholdsFn, filterFn, routeProfilesFn, - attributeProfilesFn, chargerProfilesFn, dispatcherProfilesFn, dispatcherHostsFn, - rateProfilesFn, actionProfilesFn []string) *CSVStorage { + attributeProfilesFn, chargerProfilesFn, dispatcherProfilesFn, dispatcherHostsFn []string) *CSVStorage { return &CSVStorage{ sep: sep, generator: NewCsvFile, @@ -99,7 +97,6 @@ func NewCSVStorage(sep rune, chargerProfilesFn: chargerProfilesFn, dispatcherProfilesFn: dispatcherProfilesFn, dispatcherHostsFn: dispatcherHostsFn, - rateProfilesFn: rateProfilesFn, actionProfilesFn: actionProfilesFn, } } @@ -130,7 +127,6 @@ func NewFileCSVStorage(sep rune, dataPath string) *CSVStorage { chargersPaths := appendName(allFoldersPath, utils.ChargersCsv) dispatcherprofilesPaths := appendName(allFoldersPath, utils.DispatcherProfilesCsv) dispatcherhostsPaths := appendName(allFoldersPath, utils.DispatcherHostsCsv) - rateProfilesFn := appendName(allFoldersPath, utils.RateProfilesCsv) actionProfilesFn := appendName(allFoldersPath, utils.ActionProfilesCsv) return NewCSVStorage(sep, destinationsPaths, @@ -153,7 +149,6 @@ func NewFileCSVStorage(sep rune, dataPath string) *CSVStorage { chargersPaths, dispatcherprofilesPaths, dispatcherhostsPaths, - rateProfilesFn, actionProfilesFn, ) } @@ -164,16 +159,14 @@ func NewStringCSVStorage(sep rune, destinationratetimingsFn, ratingprofilesFn, sharedgroupsFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, resProfilesFn, statsFn, thresholdsFn, filterFn, routeProfilesFn, - attributeProfilesFn, chargerProfilesFn, dispatcherProfilesFn, dispatcherHostsFn, - rateProfilesFn, actionProfilesFn string) *CSVStorage { + attributeProfilesFn, chargerProfilesFn, dispatcherProfilesFn, dispatcherHostsFn string) *CSVStorage { c := NewCSVStorage(sep, []string{destinationsFn}, []string{timingsFn}, []string{ratesFn}, []string{destinationratesFn}, []string{destinationratetimingsFn}, []string{ratingprofilesFn}, []string{sharedgroupsFn}, []string{actionsFn}, []string{actiontimingsFn}, []string{actiontriggersFn}, []string{accountactionsFn}, []string{resProfilesFn}, []string{statsFn}, []string{thresholdsFn}, []string{filterFn}, []string{routeProfilesFn}, []string{attributeProfilesFn}, []string{chargerProfilesFn}, - []string{dispatcherProfilesFn}, []string{dispatcherHostsFn}, []string{rateProfilesFn}, - []string{actionProfilesFn}) + []string{dispatcherProfilesFn}, []string{dispatcherHostsFn}) c.generator = NewCsvString return c } @@ -215,8 +208,6 @@ func NewGoogleCSVStorage(sep rune, spreadsheetID string) (*CSVStorage, error) { getIfExist(utils.Chargers), getIfExist(utils.DispatcherProfiles), getIfExist(utils.DispatcherHosts), - getIfExist(utils.RateProfiles), - getIfExist(utils.ActionProfiles)) c.generator = func() csvReaderCloser { return &csvGoogle{ spreadsheetID: spreadsheetID, @@ -248,7 +239,6 @@ func NewURLCSVStorage(sep rune, dataPath string) *CSVStorage { var chargersPaths []string var dispatcherprofilesPaths []string var dispatcherhostsPaths []string - var rateProfilesPaths []string var actionProfilesPaths []string for _, baseURL := range strings.Split(dataPath, utils.InfieldSep) { @@ -273,7 +263,6 @@ func NewURLCSVStorage(sep rune, dataPath string) *CSVStorage { chargersPaths = append(chargersPaths, joinURL(baseURL, utils.ChargersCsv)) dispatcherprofilesPaths = append(dispatcherprofilesPaths, joinURL(baseURL, utils.DispatcherProfilesCsv)) dispatcherhostsPaths = append(dispatcherhostsPaths, joinURL(baseURL, utils.DispatcherHostsCsv)) - rateProfilesPaths = append(rateProfilesPaths, joinURL(baseURL, utils.RateProfilesCsv)) actionProfilesPaths = append(actionProfilesPaths, joinURL(baseURL, utils.ActionProfilesCsv)) continue } @@ -318,8 +307,6 @@ func NewURLCSVStorage(sep rune, dataPath string) *CSVStorage { dispatcherprofilesPaths = append(dispatcherprofilesPaths, baseURL) case strings.HasSuffix(baseURL, utils.DispatcherHostsCsv): dispatcherhostsPaths = append(dispatcherhostsPaths, baseURL) - case strings.HasSuffix(baseURL, utils.RateProfilesCsv): - rateProfilesPaths = append(rateProfilesPaths, baseURL) case strings.HasSuffix(baseURL, utils.ActionProfilesCsv): actionProfilesPaths = append(actionProfilesPaths, baseURL) @@ -347,7 +334,6 @@ func NewURLCSVStorage(sep rune, dataPath string) *CSVStorage { chargersPaths, dispatcherprofilesPaths, dispatcherhostsPaths, - rateProfilesPaths, actionProfilesPaths, ) c.generator = func() csvReaderCloser { @@ -663,18 +649,6 @@ func (csvs *CSVStorage) GetTPDispatcherHosts(tpid, tenant, id string) ([]*utils. return tpDDHs.AsTPDispatcherHosts(), nil } -func (csvs *CSVStorage) GetTPRateProfiles(tpid, tenant, id string) ([]*utils.TPRateProfile, error) { - var tpDPPs RateProfileMdls - if err := csvs.proccesData(RateProfileMdl{}, csvs.rateProfilesFn, func(tp interface{}) { - dpp := tp.(RateProfileMdl) - dpp.Tpid = tpid - tpDPPs = append(tpDPPs, &dpp) - }); err != nil { - return nil, err - } - return tpDPPs.AsTPRateProfile(), nil -} - func (csvs *CSVStorage) GetTPActionProfiles(tpid, tenant, id string) ([]*utils.TPActionProfile, error) { var tpDPPs ActionProfileMdls if err := csvs.proccesData(ActionProfileMdl{}, csvs.actionProfilesFn, func(tp interface{}) { diff --git a/engine/storage_interface.go b/engine/storage_interface.go index cfcc17942..d98349b92 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -129,9 +129,6 @@ type DataDB interface { GetDispatcherHostDrv(string, string) (*DispatcherHost, error) SetDispatcherHostDrv(*DispatcherHost) error RemoveDispatcherHostDrv(string, string) error - GetRateProfileDrv(string, string) (*utils.RateProfile, error) - SetRateProfileDrv(*utils.RateProfile) error - RemoveRateProfileDrv(string, string) error GetActionProfileDrv(string, string) (*ActionProfile, error) SetActionProfileDrv(*ActionProfile) error RemoveActionProfileDrv(string, string) error @@ -184,7 +181,6 @@ type LoadReader interface { GetTPChargers(string, string, string) ([]*utils.TPChargerProfile, error) GetTPDispatcherProfiles(string, string, string) ([]*utils.TPDispatcherProfile, error) GetTPDispatcherHosts(string, string, string) ([]*utils.TPDispatcherHost, error) - GetTPRateProfiles(string, string, string) ([]*utils.TPRateProfile, error) GetTPActionProfiles(string, string, string) ([]*utils.TPActionProfile, error) } @@ -210,7 +206,6 @@ type LoadWriter interface { SetTPChargers([]*utils.TPChargerProfile) error SetTPDispatcherProfiles([]*utils.TPDispatcherProfile) error SetTPDispatcherHosts([]*utils.TPDispatcherHost) error - SetTPRateProfiles([]*utils.TPRateProfile) error SetTPActionProfiles([]*utils.TPActionProfile) error } diff --git a/engine/storage_internal_datadb.go b/engine/storage_internal_datadb.go index 1348b7634..6e82d9fdd 100644 --- a/engine/storage_internal_datadb.go +++ b/engine/storage_internal_datadb.go @@ -819,29 +819,6 @@ func (iDB *InternalDB) RemoveDispatcherHostDrv(tenant, id string) (err error) { return } -func (iDB *InternalDB) GetRateProfileDrv(tenant, id string) (rpp *utils.RateProfile, err error) { - x, ok := Cache.Get(utils.CacheRateProfiles, utils.ConcatenatedKey(tenant, id)) - if !ok || x == nil { - return nil, utils.ErrNotFound - } - return x.(*utils.RateProfile), nil -} - -func (iDB *InternalDB) SetRateProfileDrv(rpp *utils.RateProfile) (err error) { - if err = rpp.Compile(); err != nil { - return - } - Cache.SetWithoutReplicate(utils.CacheRateProfiles, rpp.TenantID(), rpp, nil, - cacheCommit(utils.NonTransactional), utils.NonTransactional) - return -} - -func (iDB *InternalDB) RemoveRateProfileDrv(tenant, id string) (err error) { - Cache.RemoveWithoutReplicate(utils.CacheRateProfiles, utils.ConcatenatedKey(tenant, id), - cacheCommit(utils.NonTransactional), utils.NonTransactional) - return -} - func (iDB *InternalDB) GetActionProfileDrv(tenant, id string) (ap *ActionProfile, err error) { x, ok := Cache.Get(utils.CacheActionProfiles, utils.ConcatenatedKey(tenant, id)) if !ok || x == nil { diff --git a/engine/storage_internal_stordb.go b/engine/storage_internal_stordb.go index 8fe5a5de8..1597f25be 100644 --- a/engine/storage_internal_stordb.go +++ b/engine/storage_internal_stordb.go @@ -563,28 +563,6 @@ func (iDB *InternalDB) GetTPDispatcherHosts(tpid, tenant, id string) (dpps []*ut return } -func (iDB *InternalDB) GetTPRateProfiles(tpid, tenant, id string) (tpPrfs []*utils.TPRateProfile, err error) { - key := tpid - if tenant != utils.EmptyString { - key += utils.ConcatenatedKeySep + tenant - } - if id != utils.EmptyString { - key += utils.ConcatenatedKeySep + id - } - ids := Cache.GetItemIDs(utils.CacheTBLTPRateProfiles, key) - for _, id := range ids { - x, ok := Cache.Get(utils.CacheTBLTPRateProfiles, id) - if !ok || x == nil { - return nil, utils.ErrNotFound - } - tpPrfs = append(tpPrfs, x.(*utils.TPRateProfile)) - } - if len(tpPrfs) == 0 { - return nil, utils.ErrNotFound - } - return -} - func (iDB *InternalDB) GetTPActionProfiles(tpid, tenant, id string) (tpPrfs []*utils.TPActionProfile, err error) { key := tpid if tenant != utils.EmptyString { @@ -858,17 +836,6 @@ func (iDB *InternalDB) SetTPDispatcherHosts(dpps []*utils.TPDispatcherHost) (err return } -func (iDB *InternalDB) SetTPRateProfiles(tpPrfs []*utils.TPRateProfile) (err error) { - if len(tpPrfs) == 0 { - return nil - } - for _, tpPrf := range tpPrfs { - Cache.SetWithoutReplicate(utils.CacheTBLTPRateProfiles, utils.ConcatenatedKey(tpPrf.TPid, tpPrf.Tenant, tpPrf.ID), tpPrf, nil, - cacheCommit(utils.NonTransactional), utils.NonTransactional) - } - return -} - func (iDB *InternalDB) SetTPActionProfiles(tpPrfs []*utils.TPActionProfile) (err error) { if len(tpPrfs) == 0 { return nil diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index 09b0a007a..68b6aa28c 100644 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -637,8 +637,6 @@ func (ms *MongoStorage) GetKeysForPrefix(prefix string) (result []string, err er result, err = ms.getField2(sctx, ColCpp, utils.ChargerProfilePrefix, subject, tntID) case utils.DispatcherProfilePrefix: result, err = ms.getField2(sctx, ColDpp, utils.DispatcherProfilePrefix, subject, tntID) - case utils.RateProfilePrefix: - result, err = ms.getField2(sctx, ColRpp, utils.RateProfilePrefix, subject, tntID) case utils.ActionProfilePrefix: result, err = ms.getField2(sctx, ColApp, utils.ActionProfilePrefix, subject, tntID) case utils.DispatcherHostPrefix: @@ -659,12 +657,6 @@ func (ms *MongoStorage) GetKeysForPrefix(prefix string) (result []string, err er result, err = ms.getField3(sctx, ColIndx, utils.DispatcherFilterIndexes, "key") case utils.ActionPlanIndexes: result, err = ms.getField3(sctx, ColIndx, utils.ActionPlanIndexes, "key") - case utils.ActionProfilesFilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.ActionProfilesFilterIndexPrfx, "key") - case utils.RateProfilesFilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.RateProfilesFilterIndexPrfx, "key") - case utils.RateFilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.RateFilterIndexPrfx, "key") case utils.FilterIndexPrfx: result, err = ms.getField3(sctx, ColIndx, utils.FilterIndexPrfx, "key") default: @@ -715,8 +707,6 @@ func (ms *MongoStorage) HasDataDrv(category, subject, tenant string) (has bool, count, err = ms.getCol(ColDpp).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject}) case utils.DispatcherHostPrefix: count, err = ms.getCol(ColDph).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject}) - case utils.RateProfilePrefix: - count, err = ms.getCol(ColRpp).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject}) case utils.ActionProfilePrefix: count, err = ms.getCol(ColApp).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject}) default: @@ -2008,42 +1998,6 @@ func (ms *MongoStorage) RemoveLoadIDsDrv() (err error) { }) } -func (ms *MongoStorage) GetRateProfileDrv(tenant, id string) (rpp *utils.RateProfile, err error) { - rpp = new(utils.RateProfile) - err = ms.query(func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColRpp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(rpp); err != nil { - rpp = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err - } - return nil - }) - return -} - -func (ms *MongoStorage) SetRateProfileDrv(rpp *utils.RateProfile) (err error) { - return ms.query(func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColRpp).UpdateOne(sctx, bson.M{"tenant": rpp.Tenant, "id": rpp.ID}, - bson.M{"$set": rpp}, - options.Update().SetUpsert(true), - ) - return err - }) -} - -func (ms *MongoStorage) RemoveRateProfileDrv(tenant, id string) (err error) { - return ms.query(func(sctx mongo.SessionContext) (err error) { - dr, err := ms.getCol(ColRpp).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) - if dr.DeletedCount == 0 { - return utils.ErrNotFound - } - return err - }) -} - func (ms *MongoStorage) GetActionProfileDrv(tenant, id string) (ap *ActionProfile, err error) { ap = new(ActionProfile) err = ms.query(func(sctx mongo.SessionContext) (err error) { diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 384a34048..aab8e70aa 100644 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -1529,55 +1529,6 @@ func (ms *MongoStorage) SetTPDispatcherHosts(tpDPPs []*utils.TPDispatcherHost) ( }) } -func (ms *MongoStorage) GetTPRateProfiles(tpid, tenant, id string) ([]*utils.TPRateProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPRateProfile - err := ms.query(func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPRateProfiles).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPRateProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPRateProfiles(tpDPPs []*utils.TPRateProfile) (err error) { - if len(tpDPPs) == 0 { - return - } - - return ms.query(func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpDPPs { - _, err = ms.getCol(utils.TBLTPRateProfiles).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - func (ms *MongoStorage) GetTPActionProfiles(tpid, tenant, id string) ([]*utils.TPActionProfile, error) { filter := bson.M{"tpid": tpid} if id != "" { diff --git a/engine/storage_redis.go b/engine/storage_redis.go index 61feb0bcc..7b2214085 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -269,8 +269,7 @@ func (rs *RedisStorage) HasDataDrv(category, subject, tenant string) (exists boo case utils.ResourcesPrefix, utils.ResourceProfilesPrefix, utils.StatQueuePrefix, utils.StatQueueProfilePrefix, utils.ThresholdPrefix, utils.ThresholdProfilePrefix, utils.FilterPrefix, utils.RouteProfilePrefix, utils.AttributeProfilePrefix, - utils.ChargerProfilePrefix, utils.DispatcherProfilePrefix, utils.DispatcherHostPrefix, - utils.RateProfilePrefix: + utils.ChargerProfilePrefix, utils.DispatcherProfilePrefix, utils.DispatcherHostPrefix: err := rs.Cmd(&i, redis_EXISTS, category+utils.ConcatenatedKey(tenant, subject)) return i == 1, err } @@ -1248,30 +1247,6 @@ func (rs *RedisStorage) RemoveLoadIDsDrv() (err error) { return rs.Cmd(nil, redis_DEL, utils.LoadIDs) } -func (rs *RedisStorage) GetRateProfileDrv(tenant, id string) (rpp *utils.RateProfile, err error) { - var values []byte - if err = rs.Cmd(&values, redis_GET, utils.RateProfilePrefix+utils.ConcatenatedKey(tenant, id)); err != nil { - return - } else if len(values) == 0 { - err = utils.ErrNotFound - return - } - err = rs.ms.Unmarshal(values, &rpp) - return -} - -func (rs *RedisStorage) SetRateProfileDrv(rpp *utils.RateProfile) (err error) { - var result []byte - if result, err = rs.ms.Marshal(rpp); err != nil { - return - } - return rs.Cmd(nil, redis_SET, utils.RateProfilePrefix+utils.ConcatenatedKey(rpp.Tenant, rpp.ID), string(result)) -} - -func (rs *RedisStorage) RemoveRateProfileDrv(tenant, id string) (err error) { - return rs.Cmd(nil, redis_DEL, utils.RateProfilePrefix+utils.ConcatenatedKey(tenant, id)) -} - func (rs *RedisStorage) GetActionProfileDrv(tenant, id string) (ap *ActionProfile, err error) { var values []byte if err = rs.Cmd(&values, redis_GET, utils.ActionProfilePrefix+utils.ConcatenatedKey(tenant, id)); err != nil { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index cc8e6729d..f116f1915 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -241,8 +241,7 @@ func (sqls *SQLStorage) RemTpData(table, tpid string, args map[string]string) er utils.TBLTPSharedGroups, utils.TBLTPActions, utils.TBLTPActionTriggers, utils.TBLTPAccountActions, utils.TBLTPResources, utils.TBLTPStats, utils.TBLTPThresholds, utils.TBLTPFilters, utils.TBLTPActionPlans, utils.TBLTPRoutes, utils.TBLTPAttributes, - utils.TBLTPChargers, utils.TBLTPDispatchers, utils.TBLTPDispatcherHosts, - utils.TBLTPActionProfiles, utils.TBLTPRateProfiles} { + utils.TBLTPChargers, utils.TBLTPDispatchers, utils.TBLTPDispatcherHosts} { if err := tx.Table(tblName).Where("tpid = ?", tpid).Delete(nil).Error; err != nil { tx.Rollback() return err @@ -729,28 +728,6 @@ func (sqls *SQLStorage) SetTPDispatcherHosts(tpDPPs []*utils.TPDispatcherHost) e return nil } -func (sqls *SQLStorage) SetTPRateProfiles(tpDPPs []*utils.TPRateProfile) error { - if len(tpDPPs) == 0 { - return nil - } - tx := sqls.db.Begin() - for _, dpp := range tpDPPs { - // Remove previous - if err := tx.Where(&RateProfileMdl{Tpid: dpp.TPid, ID: dpp.ID}).Delete(RateProfileMdl{}).Error; err != nil { - tx.Rollback() - return err - } - for _, mst := range APItoModelTPRateProfile(dpp) { - if err := tx.Create(&mst).Error; err != nil { - tx.Rollback() - return err - } - } - } - tx.Commit() - return nil -} - func (sqls *SQLStorage) SetTPActionProfiles(tpAps []*utils.TPActionProfile) error { if len(tpAps) == 0 { return nil @@ -1595,25 +1572,6 @@ func (sqls *SQLStorage) GetTPDispatcherHosts(tpid, tenant, id string) ([]*utils. return arls, nil } -func (sqls *SQLStorage) GetTPRateProfiles(tpid, tenant, id string) ([]*utils.TPRateProfile, error) { - var dpps RateProfileMdls - q := sqls.db.Where("tpid = ?", tpid) - if len(id) != 0 { - q = q.Where("id = ?", id) - } - if len(tenant) != 0 { - q = q.Where("tenant = ?", tenant) - } - if err := q.Find(&dpps).Error; err != nil { - return nil, err - } - arls := dpps.AsTPRateProfile() - if len(arls) == 0 { - return arls, utils.ErrNotFound - } - return arls, nil -} - func (sqls *SQLStorage) GetTPActionProfiles(tpid, tenant, id string) ([]*utils.TPActionProfile, error) { var dpps ActionProfileMdls q := sqls.db.Where("tpid = ?", tpid) diff --git a/engine/tpexporter.go b/engine/tpexporter.go index 61804c0b9..bd266bec1 100644 --- a/engine/tpexporter.go +++ b/engine/tpexporter.go @@ -320,18 +320,6 @@ func (tpExp *TPExporter) Run() error { toExportMap[utils.DispatcherHostsCsv] = append(toExportMap[utils.DispatcherHostsCsv], APItoModelTPDispatcherHost(sd)) } - storDataRateProfiles, err := tpExp.storDb.GetTPRateProfiles(tpExp.tpID, "", "") - if err != nil && err.Error() != utils.ErrNotFound.Error() { - utils.Logger.Warning(fmt.Sprintf("<%s> error: %s, when getting %s from stordb for export", utils.ApierS, err, utils.TpRateProfiles)) - withError = true - } - for _, sd := range storDataRateProfiles { - sdModels := APItoModelTPRateProfile(sd) - for _, sdModel := range sdModels { - toExportMap[utils.RateProfilesCsv] = append(toExportMap[utils.RateProfilesCsv], sdModel) - } - } - storDataActionProfiles, err := tpExp.storDb.GetTPActionProfiles(tpExp.tpID, "", "") if err != nil && err.Error() != utils.ErrNotFound.Error() { utils.Logger.Warning(fmt.Sprintf("<%s> error: %s, when getting %s from stordb for export", utils.ApierS, err, utils.TpActionProfiles)) diff --git a/engine/tpimporter_csv.go b/engine/tpimporter_csv.go index f146b83c6..13c8e15ac 100644 --- a/engine/tpimporter_csv.go +++ b/engine/tpimporter_csv.go @@ -60,7 +60,6 @@ var fileHandlers = map[string]func(*TPCSVImporter, string) error{ utils.ChargersCsv: (*TPCSVImporter).importChargerProfiles, utils.DispatcherProfilesCsv: (*TPCSVImporter).importDispatcherProfiles, utils.DispatcherHostsCsv: (*TPCSVImporter).importDispatcherHosts, - utils.RateProfilesCsv: (*TPCSVImporter).importRateProfiles, utils.ActionProfilesCsv: (*TPCSVImporter).importActionProfiles, } @@ -360,17 +359,6 @@ func (tpImp *TPCSVImporter) importDispatcherHosts(fn string) error { return tpImp.StorDb.SetTPDispatcherHosts(dpps) } -func (tpImp *TPCSVImporter) importRateProfiles(fn string) error { - if tpImp.Verbose { - log.Printf("Processing file: <%s> ", fn) - } - rpps, err := tpImp.csvr.GetTPRateProfiles(tpImp.TPid, "", "") - if err != nil { - return err - } - return tpImp.StorDb.SetTPRateProfiles(rpps) -} - func (tpImp *TPCSVImporter) importActionProfiles(fn string) error { if tpImp.Verbose { log.Printf("Processing file: <%s> ", fn) diff --git a/engine/tpreader.go b/engine/tpreader.go index 6bd27db28..9f4fc60a3 100644 --- a/engine/tpreader.go +++ b/engine/tpreader.go @@ -56,7 +56,6 @@ type TpReader struct { chargerProfiles map[utils.TenantID]*utils.TPChargerProfile dispatcherProfiles map[utils.TenantID]*utils.TPDispatcherProfile dispatcherHosts map[utils.TenantID]*utils.TPDispatcherHost - rateProfiles map[utils.TenantID]*utils.TPRateProfile actionProfiles map[utils.TenantID]*utils.TPActionProfile resources []*utils.TenantID // IDs of resources which need creation based on resourceProfiles statQueues []*utils.TenantID // IDs of statQueues which need creation based on statQueueProfiles @@ -106,7 +105,6 @@ func (tpr *TpReader) Init() { tpr.chargerProfiles = make(map[utils.TenantID]*utils.TPChargerProfile) tpr.dispatcherProfiles = make(map[utils.TenantID]*utils.TPDispatcherProfile) tpr.dispatcherHosts = make(map[utils.TenantID]*utils.TPDispatcherHost) - tpr.rateProfiles = make(map[utils.TenantID]*utils.TPRateProfile) tpr.actionProfiles = make(map[utils.TenantID]*utils.TPActionProfile) tpr.filters = make(map[utils.TenantID]*utils.TPFilterProfile) tpr.acntActionPlans = make(map[string][]string) @@ -322,7 +320,7 @@ func (tpr *TpReader) LoadRatingProfilesFiltered(qriedRpf *utils.TPRatingProfile) var resultRatingProfile *RatingProfile mpTpRpfs, err := tpr.lr.GetTPRatingProfiles(qriedRpf) if err != nil { - return fmt.Errorf("no RateProfile for filter %v, error: %v", qriedRpf, err) + return fmt.Errorf("no RatingProfile for filter %v, error: %v", qriedRpf, err) } rpfs, err := MapTPRatingProfiles(mpTpRpfs) @@ -1285,26 +1283,6 @@ func (tpr *TpReader) LoadDispatcherHostsFiltered(tag string) (err error) { return nil } -func (tpr *TpReader) LoadRateProfiles() error { - return tpr.LoadRateProfilesFiltered("") -} - -func (tpr *TpReader) LoadRateProfilesFiltered(tag string) (err error) { - rls, err := tpr.lr.GetTPRateProfiles(tpr.tpid, "", tag) - if err != nil { - return err - } - mapRateProfiles := make(map[utils.TenantID]*utils.TPRateProfile) - for _, rl := range rls { - if err = verifyInlineFilterS(rl.FilterIDs); err != nil { - return - } - mapRateProfiles[utils.TenantID{Tenant: rl.Tenant, ID: rl.ID}] = rl - } - tpr.rateProfiles = mapRateProfiles - return nil -} - func (tpr *TpReader) LoadActionProfiles() error { return tpr.LoadActionProfilesFiltered("") } @@ -1390,9 +1368,6 @@ func (tpr *TpReader) LoadAll() (err error) { if err = tpr.LoadDispatcherHosts(); err != nil && err.Error() != utils.NotFoundCaps { return } - if err = tpr.LoadRateProfiles(); err != nil && err.Error() != utils.NotFoundCaps { - return - } if err = tpr.LoadActionProfiles(); err != nil && err.Error() != utils.NotFoundCaps { return } @@ -1838,25 +1813,6 @@ func (tpr *TpReader) WriteToDatabase(verbose, disableReverse bool) (err error) { loadIDs[utils.CacheDispatcherHosts] = loadID } - if verbose { - log.Print("RateProfiles:") - } - for _, tpTH := range tpr.rateProfiles { - var th *utils.RateProfile - if th, err = APItoRateProfile(tpTH, tpr.timezone); err != nil { - return - } - if err = tpr.dm.SetRateProfile(th, true); err != nil { - return - } - if verbose { - log.Print("\t", th.TenantID()) - } - } - if len(tpr.rateProfiles) != 0 { - loadIDs[utils.CacheRateProfiles] = loadID - } - if verbose { log.Print("ActionProfiles:") } @@ -1972,8 +1928,6 @@ func (tpr *TpReader) ShowStatistics() { log.Print("DispatcherProfiles: ", len(tpr.dispatcherProfiles)) // Dispatcher Hosts log.Print("DispatcherHosts: ", len(tpr.dispatcherHosts)) - // Rate profiles - log.Print("RateProfiles: ", len(tpr.rateProfiles)) // Action profiles log.Print("ActionProfiles: ", len(tpr.actionProfiles)) } @@ -2126,15 +2080,6 @@ func (tpr *TpReader) GetLoadedIds(categ string) ([]string, error) { i++ } return keys, nil - - case utils.RateProfilePrefix: - keys := make([]string, len(tpr.rateProfiles)) - i := 0 - for k := range tpr.rateProfiles { - keys[i] = k.TenantID() - i++ - } - return keys, nil case utils.ActionProfilePrefix: keys := make([]string, len(tpr.actionProfiles)) i := 0 @@ -2366,19 +2311,6 @@ func (tpr *TpReader) RemoveFromDatabase(verbose, disableReverse bool) (err error } } - if verbose { - log.Print("RateProfiles:") - } - for _, tpRp := range tpr.rateProfiles { - if err = tpr.dm.RemoveRateProfile(tpRp.Tenant, tpRp.ID, - utils.NonTransactional, true); err != nil { - return - } - if verbose { - log.Print("\t", utils.ConcatenatedKey(tpRp.Tenant, tpRp.ID)) - } - } - if verbose { log.Print("ActionProfiles:") } @@ -2495,9 +2427,6 @@ func (tpr *TpReader) RemoveFromDatabase(verbose, disableReverse bool) (err error if len(tpr.dispatcherHosts) != 0 { loadIDs[utils.CacheDispatcherHosts] = loadID } - if len(tpr.rateProfiles) != 0 { - loadIDs[utils.CacheRateProfiles] = loadID - } if len(tpr.actionProfiles) != 0 { loadIDs[utils.CacheActionProfiles] = loadID } @@ -2536,7 +2465,6 @@ func (tpr *TpReader) ReloadCache(caching string, verbose bool, opts map[string]i chargerIDs, _ := tpr.GetLoadedIds(utils.ChargerProfilePrefix) dppIDs, _ := tpr.GetLoadedIds(utils.DispatcherProfilePrefix) dphIDs, _ := tpr.GetLoadedIds(utils.DispatcherHostPrefix) - ratePrfIDs, _ := tpr.GetLoadedIds(utils.RateProfilePrefix) actionPrfIDs, _ := tpr.GetLoadedIds(utils.ActionProfilePrefix) aps, _ := tpr.GetLoadedIds(utils.ActionPlanPrefix) @@ -2565,7 +2493,6 @@ func (tpr *TpReader) ReloadCache(caching string, verbose bool, opts map[string]i utils.ChargerProfileIDs: chargerIDs, utils.DispatcherProfileIDs: dppIDs, utils.DispatcherHostIDs: dphIDs, - utils.RateProfileIDs: ratePrfIDs, utils.ActionProfileIDs: actionPrfIDs, }, } @@ -2618,10 +2545,6 @@ func (tpr *TpReader) ReloadCache(caching string, verbose bool, opts map[string]i if len(dppIDs) != 0 { cacheIDs = append(cacheIDs, utils.CacheDispatcherFilterIndexes) } - if len(ratePrfIDs) != 0 { - cacheIDs = append(cacheIDs, utils.CacheRateProfilesFilterIndexes) - cacheIDs = append(cacheIDs, utils.CacheRateFilterIndexes) - } if len(actionPrfIDs) != 0 { cacheIDs = append(cacheIDs, utils.CacheActionProfilesFilterIndexes) } diff --git a/engine/version.go b/engine/version.go index c5c99374c..6264c8a33 100644 --- a/engine/version.go +++ b/engine/version.go @@ -163,7 +163,6 @@ func CurrentDataDBVersions() Versions { utils.Chargers: 2, utils.Dispatchers: 2, utils.LoadIDsVrs: 1, - utils.RateProfiles: 1, utils.ActionProfiles: 1, } } @@ -195,7 +194,6 @@ func CurrentStorDBVersions() Versions { utils.TpRatingProfile: 1, utils.TpChargers: 1, utils.TpDispatchers: 1, - utils.TpRateProfiles: 1, utils.TpActionProfiles: 1, } } diff --git a/engine/version_test.go b/engine/version_test.go index 9d4ab7954..ff81dec90 100644 --- a/engine/version_test.go +++ b/engine/version_test.go @@ -92,8 +92,7 @@ func TestCurrentDBVersions(t *testing.T) { utils.Timing: 1, utils.RQF: 5, utils.Resource: 1, utils.Subscribers: 1, utils.Destinations: 1, utils.ReverseDestinations: 1, utils.RatingPlan: 1, utils.RatingProfile: 1, utils.Chargers: 2, - utils.Dispatchers: 2, utils.LoadIDsVrs: 1, utils.RateProfiles: 1, - utils.ActionProfiles: 1, + utils.Dispatchers: 2, utils.LoadIDsVrs: 1, utils.ActionProfiles: 1, } expVersStorDB := Versions{ utils.CostDetails: 2, utils.SessionSCosts: 3, utils.CDRs: 2, @@ -104,7 +103,7 @@ func TestCurrentDBVersions(t *testing.T) { utils.TpResources: 1, utils.TpRates: 1, utils.TpTiming: 1, utils.TpResource: 1, utils.TpDestinations: 1, utils.TpRatingPlan: 1, utils.TpRatingProfile: 1, utils.TpChargers: 1, utils.TpDispatchers: 1, - utils.TpRateProfiles: 1, utils.TpActionProfiles: 1, + utils.TpActionProfiles: 1, } if vrs := CurrentDBVersions(utils.Mongo, true); !reflect.DeepEqual(expVersDataDB, vrs) { t.Errorf("Expectred %+v, received %+v", expVersDataDB, vrs) diff --git a/engine/z_filterindexer_it_test.go b/engine/z_filterindexer_it_test.go index 94c83ff63..f7325b31d 100644 --- a/engine/z_filterindexer_it_test.go +++ b/engine/z_filterindexer_it_test.go @@ -82,10 +82,8 @@ var sTests = []func(t *testing.T){ testITFlush, testITIsDBEmpty, testITTestIndexingMetaNot, - testITIndexRateProfileRateIndexes, testITFlush, testITIsDBEmpty, - testITIndexRateProfileIndexes, testITFlush, testITIsDBEmpty, testITTestIndexingMetaSuffix, @@ -1971,386 +1969,6 @@ func testITTestIndexingMetaNot(t *testing.T) { } } -func testITIndexRateProfileRateIndexes(t *testing.T) { - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001", "*string:~*req.Subject:1002"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "FIRST_GI": { - ID: "FIRST_GI", - FilterIDs: []string{"*string:~*req.Category:call"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - Blocker: false, - }, - "SECOND_GI": { - ID: "SECOND_GI", - FilterIDs: []string{"*string:~*req.Category:voice"}, - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - Blocker: false, - }, - }, - } - if err := dataManager.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - eIdxes := map[string]utils.StringSet{ - "*string:*req.Category:call": { - "FIRST_GI": struct{}{}, - }, - "*string:*req.Category:voice": { - "SECOND_GI": struct{}{}, - }, - } - if rcvIdx, err := dataManager.GetIndexes( - utils.CacheRateFilterIndexes, "cgrates.org:RP1", - utils.EmptyString, true, true); err != nil { - t.Error(err) - } else { - if !reflect.DeepEqual(eIdxes, rcvIdx) { - t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) - } - } - - // update the RateProfile by adding a new Rate - rPrf = &utils.RateProfile{ // recreate the profile because if we test on internal - Tenant: "cgrates.org", // each update on the original item will update the item from DB - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001", "*string:~*req.Subject:1002"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "FIRST_GI": { - ID: "FIRST_GI", - FilterIDs: []string{"*string:~*req.Category:call"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - Blocker: false, - }, - "SECOND_GI": { - ID: "SECOND_GI", - FilterIDs: []string{"*string:~*req.Category:voice"}, - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - Blocker: false, - }, - "THIRD_GI": { - ID: "THIRD_GI", - FilterIDs: []string{"*string:~*req.Category:custom"}, - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - Blocker: false, - }, - }, - } - if err := dataManager.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - eIdxes = map[string]utils.StringSet{ - "*string:*req.Category:call": { - "FIRST_GI": struct{}{}, - }, - "*string:*req.Category:voice": { - "SECOND_GI": struct{}{}, - }, - "*string:*req.Category:custom": { - "THIRD_GI": struct{}{}, - }, - } - if rcvIdx, err := dataManager.GetIndexes( - utils.CacheRateFilterIndexes, "cgrates.org:RP1", - utils.EmptyString, true, true); err != nil { - t.Error(err) - } else { - if !reflect.DeepEqual(eIdxes, rcvIdx) { - t.Errorf("Expecting %+v, received: %+v", eIdxes, rcvIdx) - } - } - - //here we will set a filter - fltr := &Filter{ - Tenant: "cgrates.org", - ID: "FLTR", - Rules: []*FilterRule{{Type: utils.MetaString, Element: "Dan", Values: []string{"~*req.Account", "~*req.Destination", "DAN2"}}}, - } - if err := dataManager.SetFilter(fltr, true); err != nil { - t.Error(err) - } - rPrf2 := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP2", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "CUSTOM_RATE1": { - ID: "CUSTOM_RATE1", - FilterIDs: []string{"*string:~*req.Subject:1001", "FLTR"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - Blocker: false, - }, - "CUSTOM_RATE2": { - ID: "CUSTOM_RATE2", - FilterIDs: []string{"*string:~*req.Subject:1001", "*string:~*req.Category:call"}, - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - Blocker: false, - }, - }, - } - if err := dataManager.SetRateProfile(rPrf2, true); err != nil { - t.Error(err) - } - eIdxes = map[string]utils.StringSet{ - "*string:*req.Subject:1001": { - "CUSTOM_RATE1": struct{}{}, - "CUSTOM_RATE2": struct{}{}, - }, - "*string:*req.Category:call": { - "CUSTOM_RATE2": struct{}{}, - }, - "*string:*req.Account:Dan": { - "CUSTOM_RATE1": struct{}{}, - }, - "*string:*req.Destination:Dan": { - "CUSTOM_RATE1": struct{}{}, - }, - } - if rcvIdx, err := dataManager.GetIndexes( - utils.CacheRateFilterIndexes, "cgrates.org:RP2", - utils.EmptyString, true, true); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eIdxes, rcvIdx) { - t.Errorf("Expecting %+v, received: %+v", eIdxes, rcvIdx) - } - - //here we will check the reverse indexes - eIdxes = map[string]utils.StringSet{ - utils.CacheRateFilterIndexes: { - "CUSTOM_RATE1:RP2": struct{}{}, - }, - } - if rcvIdx, err := dataManager.GetIndexes( - utils.CacheReverseFilterIndexes, "cgrates.org:FLTR", - utils.EmptyString, true, true); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eIdxes, rcvIdx) { - t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) - } - - //now we will update the filter - fltr = &Filter{ - Tenant: "cgrates.org", - ID: "FLTR", - Rules: []*FilterRule{{Type: utils.MetaString, Element: "10m", Values: []string{"~*req.Usage", "~*req.Debited", "DAN2"}}}, - } - if err := dataManager.SetFilter(fltr, true); err != nil { - t.Error(err) - } - - eIdxes = map[string]utils.StringSet{ - "*string:*req.Subject:1001": { - "CUSTOM_RATE1": struct{}{}, - "CUSTOM_RATE2": struct{}{}, - }, - "*string:*req.Category:call": { - "CUSTOM_RATE2": struct{}{}, - }, - "*string:*req.Usage:10m": { - "CUSTOM_RATE1": struct{}{}, - }, - "*string:*req.Debited:10m": { - "CUSTOM_RATE1": struct{}{}, - }, - } - if rcvIdx, err := dataManager.GetIndexes( - utils.CacheRateFilterIndexes, "cgrates.org:RP2", - utils.EmptyString, true, true); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eIdxes, rcvIdx) { - t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) - } - - //invalid or inexisting tenant:context or index key - eIdxes = nil - if rcvIdx, err := dataManager.GetIndexes( - utils.CacheRateFilterIndexes, "cgrates.org:RP4", - utils.EmptyString, true, true); err == nil || err != utils.ErrNotFound { - t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) - } else if !reflect.DeepEqual(eIdxes, rcvIdx) { - t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) - } - -} - -func testITIndexRateProfileIndexes(t *testing.T) { - fltr1 := &Filter{ - Tenant: "cgrates.org", - ID: "FLTR", - Rules: []*FilterRule{{Type: utils.MetaString, Element: "~*req.Usage", Values: []string{"10m"}}}, - } - if err := dataManager.SetFilter(fltr1, true); err != nil { - t.Error(err) - } - rPrf1 := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1004|1005", "FLTR"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "CUSTOM1_RATE1": { - ID: "CUSTOM1_RATE1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Blocker: false, - }, - "CUSTOM1_RATE2": { - ID: "CUSTOM1_RATE2", - FilterIDs: []string{"*string:~*req.Subject:1001", "*string:~*req.Category:call"}, - Blocker: false, - }, - }, - } - rPrf2 := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP2", - FilterIDs: []string{"*string:~*req.ToR:*sms|*voice", "*string:~*req.Subject:1004"}, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "CUSTOM2_RATE1": { - ID: "CUSTOM2_RATE1", - FilterIDs: []string{"*string:~*req.Subject:1009"}, - Blocker: false, - }, - }, - } - if err := dataManager.SetRateProfile(rPrf1, true); err != nil { - t.Error(err) - } else if err := dataManager.SetRateProfile(rPrf2, true); err != nil { - t.Error(err) - } - - expIdx := map[string]utils.StringSet{ - "*string:*req.Subject:1004": { - "RP1": struct{}{}, - "RP2": struct{}{}, - }, - "*string:*req.Subject:1005": { - "RP1": struct{}{}, - }, - "*string:*req.ToR:*sms": { - "RP2": struct{}{}, - }, - "*string:*req.ToR:*voice": { - "RP2": struct{}{}, - }, - "*string:*req.Usage:10m": { - "RP1": struct{}{}, - }, - } - if rcv, err := dataManager.GetIndexes(utils.CacheRateProfilesFilterIndexes, - "cgrates.org", utils.EmptyString, false, false); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcv, expIdx) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expIdx), utils.ToJSON(rcv)) - } - - //we will update the filter - fltr1 = &Filter{ - Tenant: "cgrates.org", - ID: "FLTR", - Rules: []*FilterRule{{Type: utils.MetaString, Element: "~*req.CustomField", Values: []string{"234", "567"}}}, - } - if err := dataManager.SetFilter(fltr1, true); err != nil { - t.Error(err) - } - expIdx = map[string]utils.StringSet{ - "*string:*req.Subject:1004": { - "RP1": struct{}{}, - "RP2": struct{}{}, - }, - "*string:*req.Subject:1005": { - "RP1": struct{}{}, - }, - "*string:*req.ToR:*sms": { - "RP2": struct{}{}, - }, - "*string:*req.ToR:*voice": { - "RP2": struct{}{}, - }, - "*string:*req.CustomField:234": { - "RP1": struct{}{}, - }, - "*string:*req.CustomField:567": { - "RP1": struct{}{}, - }, - } - if rcv, err := dataManager.GetIndexes(utils.CacheRateProfilesFilterIndexes, - "cgrates.org", utils.EmptyString, false, false); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcv, expIdx) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expIdx), utils.ToJSON(rcv)) - } - - //here we will get the reverse indexes - expIdx = map[string]utils.StringSet{ - utils.CacheRateProfilesFilterIndexes: { - "RP1": struct{}{}, - }, - } - if rcv, err := dataManager.GetIndexes(utils.CacheReverseFilterIndexes, - "cgrates.org:FLTR", utils.EmptyString, false, false); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcv, expIdx) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expIdx), utils.ToJSON(rcv)) - } - - //nothing to get with with an invalid indexKey - expIdx = nil - if rcv, err := dataManager.GetIndexes(utils.CacheRateProfilesFilterIndexes, - "cgrates.org", "*string:*req.CustomField:2346", false, false); err == nil || err != utils.ErrNotFound { - t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) - } else if !reflect.DeepEqual(rcv, expIdx) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expIdx), utils.ToJSON(rcv)) - } -} - func testITTestIndexingMetaSuffix(t *testing.T) { th := &ThresholdProfile{ Tenant: "cgrates.org", diff --git a/engine/z_onstor_it_test.go b/engine/z_onstor_it_test.go index 102b3d8e4..e82a24074 100644 --- a/engine/z_onstor_it_test.go +++ b/engine/z_onstor_it_test.go @@ -75,7 +75,6 @@ var ( testOnStorITTestAttributeSubstituteIface, testOnStorITChargerProfile, testOnStorITDispatcherProfile, - testOnStorITRateProfile, testOnStorITActionProfile, //testOnStorITCacheActionTriggers, //testOnStorITCRUDActionTriggers, @@ -2154,87 +2153,6 @@ func testOnStorITDispatcherProfile(t *testing.T) { } } -func testOnStorITRateProfile(t *testing.T) { - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001", "*string:~*req.Subject:1002"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "FIRST_GI": { - ID: "FIRST_GI", - FilterIDs: []string{"*gi:~*req.Usage:0"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - Blocker: false, - }, - "SECOND_GI": { - ID: "SECOND_GI", - FilterIDs: []string{"*gi:~*req.Usage:1m"}, - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - Blocker: false, - }, - }, - } - if _, rcvErr := onStor.GetRateProfile("cgrates.org", "RP1", - true, false, utils.NonTransactional); rcvErr != nil && rcvErr != utils.ErrNotFound { - t.Error(rcvErr) - } - if err := onStor.SetRateProfile(rPrf, false); err != nil { - t.Error(err) - } - if err = rPrf.Compile(); err != nil { - t.Fatal(err) - } - //get from database - if rcv, err := onStor.GetRateProfile("cgrates.org", "RP1", - false, false, utils.NonTransactional); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rPrf, rcv) { - t.Errorf("Expecting: %v, received: %v", rPrf, rcv) - } - expectedT := []string{"rtp_cgrates.org:RP1"} - if itm, err := onStor.DataDB().GetKeysForPrefix(utils.RateProfilePrefix); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expectedT, itm) { - t.Errorf("Expected : %+v, but received %+v", expectedT, itm) - } - //update - rPrf.FilterIDs = []string{"*string:~*req.Accout:1001", "*prefix:~*req.Destination:10"} - if err := onStor.SetRateProfile(rPrf, false); err != nil { - t.Error(err) - } - - //get from database - if rcv, err := onStor.GetRateProfile("cgrates.org", "RP1", - false, false, utils.NonTransactional); err != nil { - t.Error(err) - } else if !(reflect.DeepEqual(rPrf, rcv)) { - t.Errorf("Expecting: %v, received: %v", rPrf, rcv) - } - if err := onStor.RemoveRateProfile(rPrf.Tenant, rPrf.ID, - utils.NonTransactional, false); err != nil { - t.Error(err) - } - //check database if removed - if _, rcvErr := onStor.GetRateProfile("cgrates.org", "RP1", - false, false, utils.NonTransactional); rcvErr != nil && rcvErr != utils.ErrNotFound { - t.Error(rcvErr) - } -} - func testOnStorITActionProfile(t *testing.T) { actPrf := &ActionProfile{ Tenant: "cgrates.org", diff --git a/engine/z_stordb_it_test.go b/engine/z_stordb_it_test.go index 5bee9037d..8145fc555 100644 --- a/engine/z_stordb_it_test.go +++ b/engine/z_stordb_it_test.go @@ -48,7 +48,6 @@ var sTestsStorDBit = []func(t *testing.T){ testStorDBitCRUDTPDispatcherProfiles, testStorDBitCRUDTPDispatcherHosts, testStorDBitCRUDTPFilters, - testStorDBitCRUDTPRateProfiles, testStorDBitCRUDTPRoutes, testStorDBitCRUDTPThresholds, testStorDBitCRUDTPAttributes, @@ -436,73 +435,6 @@ func testStorDBitCRUDTPFilters(t *testing.T) { } } -func testStorDBitCRUDTPRateProfiles(t *testing.T) { - //READ - if _, err := storDB.GetTPRateProfiles("ID_RP1", utils.EmptyString, utils.EmptyString); err != utils.ErrNotFound { - t.Error(err) - } - - //WRITE - tpr := []*utils.TPRateProfile{ - { - TPid: "id_RP1", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "FIRST_GI": { - ID: "FIRST_GI", - FilterIDs: []string{"*gi:~*req.Usage:0"}, - Weights: ";0", - IntervalRates: []*utils.TPIntervalRate{ - { - RecurrentFee: 0.12, - Unit: "1m", - Increment: "1m", - }, - }, - Blocker: false, - }, - }, - }, - } - if err := storDB.SetTPRateProfiles(tpr); err != nil { - t.Error(err) - } - - //READ - if rcv, err := storDB.GetTPRateProfiles(tpr[0].TPid, utils.EmptyString, utils.EmptyString); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcv[0], tpr[0]) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(tpr[0]), utils.ToJSON(rcv[0])) - } - - //UPDATE and WRITE - tpr[0].MaxCost = 2.0 - tpr[0].MinCost = 0.2 - if err := storDB.SetTPRateProfiles(tpr); err != nil { - t.Error(err) - } - - //READ - if rcv, err := storDB.GetTPRateProfiles(tpr[0].TPid, utils.EmptyString, utils.EmptyString); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcv[0], tpr[0]) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(tpr[0]), utils.ToJSON(rcv[0])) - } - - //REMOVE AND READ - if err := storDB.RemTpData(utils.EmptyString, tpr[0].TPid, nil); err != nil { - t.Error(err) - } else if _, err := storDB.GetTPRateProfiles(tpr[0].TPid, utils.EmptyString, utils.EmptyString); err != utils.ErrNotFound { - t.Error(err) - } -} - func testStorDBitCRUDTPRoutes(t *testing.T) { //READ if _, err := storDB.GetTPRoutes("TP1", utils.EmptyString, utils.EmptyString); err != utils.ErrNotFound { diff --git a/general_tests/filtered_replication_it_test.go b/general_tests/filtered_replication_it_test.go index 5dea677b9..2d82dbbdd 100644 --- a/general_tests/filtered_replication_it_test.go +++ b/general_tests/filtered_replication_it_test.go @@ -64,7 +64,6 @@ var ( testFltrRplChargerProfile, testFltrRplDispatcherProfile, testFltrRplDispatcherHost, - testFltrRplRateProfile, testFltrRplActionProfile, testFltrRplAccount, testFltrRplDestination, @@ -1339,146 +1338,6 @@ func testFltrRplDispatcherHost(t *testing.T) { } } -func testFltrRplRateProfile(t *testing.T) { - rpID := "RP1" - rpPrf := &utils.APIRateProfileWithAPIOpts{ - APIRateProfile: &utils.APIRateProfile{ - Tenant: "cgrates.org", - ID: rpID, - FilterIDs: []string{"*string:~*req.Account:dan"}, - Weights: ";0", - MaxCostStrategy: "*free", - Rates: map[string]*utils.APIRate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: ";0", - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.APIIntervalRate{ - { - IntervalStart: "0", - }, - }, - }, - }, - }, - } - expPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: rpID, - FilterIDs: []string{"*string:~*req.Account:dan"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - var result string - var replyPrfl *utils.RateProfile - var rplyIDs []string - // empty - if err := fltrRplEngine1RPC.Call(utils.APIerSv1GetRateProfileIDs, &utils.PaginatorWithTenant{}, &rplyIDs); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Fatalf("Unexpected error: %v", err) - } - if err := fltrRplEngine2RPC.Call(utils.APIerSv1GetRateProfileIDs, &utils.PaginatorWithTenant{}, &rplyIDs); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Fatalf("Unexpected error: %v", err) - } - - if err := fltrRplInternalRPC.Call(utils.APIerSv1SetRateProfile, rpPrf, &result); err != nil { - t.Fatal(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - if err := fltrRplInternalRPC.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: rpID}}, &replyPrfl); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expPrf, replyPrfl) { - t.Errorf("Expecting : %s, received: %s", utils.ToJSON(expPrf), utils.ToJSON(replyPrfl)) - } - replyPrfl = nil - - if err := fltrRplEngine1RPC.Call(utils.APIerSv1GetRateProfileIDs, &utils.PaginatorWithTenant{}, &rplyIDs); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Fatalf("Unexpected error: %v", err) - } - if err := fltrRplEngine2RPC.Call(utils.APIerSv1GetRateProfileIDs, &utils.PaginatorWithTenant{}, &rplyIDs); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Fatalf("Unexpected error: %v", err) - } - - if err := fltrRplEngine1RPC.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: rpID}}, &replyPrfl); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expPrf, replyPrfl) { - t.Errorf("Expecting : %s, received: %s", utils.ToJSON(expPrf), utils.ToJSON(replyPrfl)) - } - replyPrfl = nil - rpPrf.Weights = ";15" - expPrf.Weights[0].Weight = 15 - if err := fltrRplInternalRPC.Call(utils.APIerSv1SetRateProfile, rpPrf, &result); err != nil { - t.Fatal(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - if err := fltrRplInternalRPC.Call(utils.APIerSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: rpID}}, &replyPrfl); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expPrf, replyPrfl) { - t.Errorf("Expecting : %s, received: %s", utils.ToJSON(expPrf), utils.ToJSON(replyPrfl)) - } - replyPrfl = nil - - // use replicator to see if the attribute was changed in the DB - if err := fltrRplEngine1RPC.Call(utils.ReplicatorSv1GetRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: rpID}}, &replyPrfl); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expPrf, replyPrfl) { - t.Errorf("Expecting : %s, received: %s", utils.ToJSON(expPrf), utils.ToJSON(replyPrfl)) - } - - if err := fltrRplEngine2RPC.Call(utils.APIerSv1GetRateProfileIDs, &utils.PaginatorWithTenant{}, &rplyIDs); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Fatalf("Unexpected error: %v", err) - } - - if err := fltrRplInternalRPC.Call(utils.APIerSv1RemoveRateProfile, - utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: rpID}}, &result); err != nil { - t.Error(err) - } else if result != utils.OK { - t.Error("Unexpected reply returned", result) - } - if err := fltrRplEngine1RPC.Call(utils.APIerSv1GetRateProfileIDs, &utils.PaginatorWithTenant{}, &rplyIDs); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Fatalf("Unexpected error: %v", err) - } - if err := fltrRplEngine2RPC.Call(utils.APIerSv1GetRateProfileIDs, &utils.PaginatorWithTenant{}, &rplyIDs); err == nil || - err.Error() != utils.ErrNotFound.Error() { - t.Fatalf("Unexpected error: %v", err) - } -} - func testFltrRplActionProfile(t *testing.T) { acID := "ATTR1" acPrf := &engine.ActionProfileWithAPIOpts{ diff --git a/loaders/lib_test.go b/loaders/lib_test.go index fb6bf2bf7..c131ade74 100644 --- a/loaders/lib_test.go +++ b/loaders/lib_test.go @@ -69,197 +69,6 @@ func (s *testMockCacheConn) Call(method string, arg interface{}, rply interface{ } } -func TestProcessContentCallsLoadCache(t *testing.T) { - sMock := &testMockCacheConn{ - calls: map[string]func(arg interface{}, rply interface{}) error{ - utils.CacheSv1LoadCache: func(arg interface{}, rply interface{}) error { - prply, can := rply.(*string) - if !can { - t.Errorf("Wrong argument type: %T", rply) - } - *prply = utils.OK - return nil - }, - utils.CacheSv1Clear: func(arg interface{}, rply interface{}) error { - prply, can := rply.(*string) - if !can { - t.Errorf("Wrong argument type : %T", rply) - return nil - } - *prply = utils.OK - return nil - }, - }, - } - internalCacheSChann := make(chan rpcclient.ClientConnector, 1) - internalCacheSChann <- sMock - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestProcessContentCallsLoadCache", - bufLoaderData: make(map[string][]LoaderData), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - connMgr: engine.NewConnManager(config.CgrConfig(), map[string]chan rpcclient.ClientConnector{ - utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches): internalCacheSChann, - }), - cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)}, - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - {Tag: "Weight", - Path: "Weight", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)}, - }, - } - ratePrfCsv := ` -#Tenant[0],ID[1],Weight[2] -cgrates.org,MOCK_RELOAD_ID,20 -` - rdr := io.NopCloser(strings.NewReader(ratePrfCsv)) - rdrCsv := csv.NewReader(rdr) - rdrCsv.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: rdrCsv, - }, - }, - } - if err := ldr.processContent(utils.MetaRateProfiles, utils.MetaLoad); err != nil { - t.Error(err) - } - - // Calling the method again while cacheConnsID is not valid - ldr.cacheConns = []string{utils.MetaInternal} - rdr = io.NopCloser(strings.NewReader(ratePrfCsv)) - rdrCsv = csv.NewReader(rdr) - rdrCsv.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: rdrCsv, - }, - }, - } - expected := "UNSUPPORTED_SERVICE_METHOD" - if err := ldr.processContent(utils.MetaRateProfiles, utils.MetaLoad); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", expected, err) - } -} - -func TestProcessContentCallsReloadCache(t *testing.T) { - // Clear cache because connManager sets the internal connection in cache - engine.Cache.Clear([]string{utils.CacheRPCConnections}) - - sMock2 := &testMockCacheConn{ - calls: map[string]func(arg interface{}, rply interface{}) error{ - utils.CacheSv1ReloadCache: func(arg interface{}, rply interface{}) error { - prply, can := rply.(*string) - if !can { - t.Errorf("Wrong argument type : %T", rply) - return nil - } - *prply = utils.OK - return nil - }, - utils.CacheSv1Clear: func(arg interface{}, rply interface{}) error { - prply, can := rply.(*string) - if !can { - t.Errorf("Wrong argument type : %T", rply) - return nil - } - *prply = utils.OK - return nil - }, - }, - } - data := engine.NewInternalDB(nil, nil, true) - - internalCacheSChan := make(chan rpcclient.ClientConnector, 1) - internalCacheSChan <- sMock2 - ldr := &Loader{ - ldrID: "TestProcessContentCalls", - bufLoaderData: make(map[string][]LoaderData), - connMgr: engine.NewConnManager(config.CgrConfig(), map[string]chan rpcclient.ClientConnector{ - utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches): internalCacheSChan, - }), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)}, - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - {Tag: "Weight", - Path: "Weight", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)}, - }, - } - ratePrfCsv := ` -#Tenant[0],ID[1],Weight[2] -cgrates.org,MOCK_RELOAD_ID,20 -` - rdr := io.NopCloser(strings.NewReader(ratePrfCsv)) - rdrCsv := csv.NewReader(rdr) - rdrCsv.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: rdrCsv, - }, - }, - } - if err := ldr.processContent(utils.MetaRateProfiles, utils.MetaReload); err != nil { - t.Error(err) - } - - // Calling the method again while cacheConnsID is not valid - ldr.cacheConns = []string{utils.MetaInternal} - rdr = io.NopCloser(strings.NewReader(ratePrfCsv)) - rdrCsv = csv.NewReader(rdr) - rdrCsv.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: rdrCsv, - }, - }, - } - expected := "UNSUPPORTED_SERVICE_METHOD" - if err := ldr.processContent(utils.MetaRateProfiles, utils.MetaReload); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", expected, err) - } -} - func TestProcessContentCallsRemoveItems(t *testing.T) { // Clear cache because connManager sets the internal connection in cache engine.Cache.Clear([]string{utils.CacheRPCConnections}) diff --git a/loaders/loader.go b/loaders/loader.go index fcf25f95f..39affbd02 100644 --- a/loaders/loader.go +++ b/loaders/loader.go @@ -574,41 +574,6 @@ func (ldr *Loader) storeLoadedData(loaderType string, cacheArgs[utils.DispatcherHostIDs] = ids } } - case utils.MetaRateProfiles: - cacheIDs = []string{utils.CacheRateProfilesFilterIndexes, utils.CacheRateFilterIndexes} - for _, lDataSet := range lds { - rpMdls := make(engine.RateProfileMdls, len(lDataSet)) - for i, ld := range lDataSet { - rpMdls[i] = new(engine.RateProfileMdl) - if err = utils.UpdateStructWithIfaceMap(rpMdls[i], ld); err != nil { - return - } - } - for _, tpRpl := range rpMdls.AsTPRateProfile() { - rpl, err := engine.APItoRateProfile(tpRpl, ldr.timezone) - if err != nil { - return err - } - if ldr.dryRun { - utils.Logger.Info( - fmt.Sprintf("<%s-%s> DRY_RUN: RateProfile: %s", - utils.LoaderS, ldr.ldrID, utils.ToJSON(rpl))) - continue - } - // get IDs so we can reload in cache - ids = append(ids, rpl.TenantID()) - if ldr.flagsTpls[loaderType].GetBool(utils.MetaPartial) { - if err := ldr.dm.SetRateProfileRates(rpl, true); err != nil { - return err - } - } else { - if err := ldr.dm.SetRateProfile(rpl, true); err != nil { - return err - } - } - cacheArgs[utils.RateProfileIDs] = ids - } - } case utils.MetaActionProfiles: cacheIDs = []string{utils.CacheActionProfilesFilterIndexes} for _, lDataSet := range lds { @@ -930,36 +895,6 @@ func (ldr *Loader) removeLoadedData(loaderType string, lds map[string][]LoaderDa cacheArgs[utils.DispatcherHostIDs] = ids } } - case utils.MetaRateProfiles: - cacheIDs = []string{utils.CacheRateProfilesFilterIndexes, utils.CacheRateFilterIndexes} - for tntID, ldData := range lds { - if ldr.dryRun { - utils.Logger.Info( - fmt.Sprintf("<%s-%s> DRY_RUN: RateProfileIDs: %s", - utils.LoaderS, ldr.ldrID, tntID)) - } else { - tntIDStruct := utils.NewTenantID(tntID) - // get IDs so we can reload in cache - ids = append(ids, tntID) - if ldr.flagsTpls[loaderType].GetBool(utils.MetaPartial) { - rateIDs, err := ldData[0].GetRateIDs() - if err != nil { - return err - } - if err := ldr.dm.RemoveRateProfileRates(tntIDStruct.Tenant, - tntIDStruct.ID, rateIDs, true); err != nil { - return err - } - } else { - if err := ldr.dm.RemoveRateProfile(tntIDStruct.Tenant, - tntIDStruct.ID, utils.NonTransactional, true); err != nil { - return err - } - } - - cacheArgs[utils.RateProfileIDs] = ids - } - } case utils.MetaActionProfiles: cacheIDs = []string{utils.CacheActionProfiles, utils.CacheActionProfilesFilterIndexes} for tntID := range lds { diff --git a/loaders/loader_test.go b/loaders/loader_test.go index 0f7d20ec0..1f95aa392 100644 --- a/loaders/loader_test.go +++ b/loaders/loader_test.go @@ -1455,854 +1455,6 @@ func TestLoaderRemoveContentSingleFile(t *testing.T) { t.Error(err) } } - -func TestLoaderProcessRateProfile(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestLoaderProcessRateProfile", - bufLoaderData: make(map[string][]LoaderData), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - {Tag: "FilterIDs", - Path: "FilterIDs", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)}, - {Tag: "ActivationInterval", - Path: "ActivationInterval", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.3", utils.InfieldSep)}, - {Tag: "Weights", - Path: "Weights", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.4", utils.InfieldSep)}, - {Tag: "MinCost", - Path: "MinCost", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.5", utils.InfieldSep)}, - {Tag: "MaxCost", - Path: "MaxCost", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.6", utils.InfieldSep)}, - {Tag: "MaxCostStrategy", - Path: "MaxCostStrategy", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.7", utils.InfieldSep)}, - {Tag: "RateID", - Path: "RateID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.8", utils.InfieldSep)}, - {Tag: "RateFilterIDs", - Path: "RateFilterIDs", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.9", utils.InfieldSep)}, - {Tag: "RateActivationTimes", - Path: "RateActivationTimes", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.10", utils.InfieldSep)}, - {Tag: "RateWeights", - Path: "RateWeights", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.11", utils.InfieldSep)}, - {Tag: "RateBlocker", - Path: "RateBlocker", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.12", utils.InfieldSep)}, - {Tag: "RateIntervalStart", - Path: "RateIntervalStart", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.13", utils.InfieldSep)}, - {Tag: "RateFixedFee", - Path: "RateFixedFee", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.14", utils.InfieldSep)}, - {Tag: "RateRecurrentFee", - Path: "RateRecurrentFee", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.15", utils.InfieldSep)}, - {Tag: "RateUnit", - Path: "RateUnit", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.16", utils.InfieldSep)}, - {Tag: "RateIncrement", - Path: "RateIncrement", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.17", utils.InfieldSep)}, - }, - } - rdr := io.NopCloser(strings.NewReader(engine.RateProfileCSVContent)) - csvRdr := csv.NewReader(rdr) - csvRdr.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{fileName: utils.RateProfilesCsv, - rdr: rdr, csvRdr: csvRdr}}, - } - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - if len(ldr.bufLoaderData) != 0 { - t.Errorf("wrong buffer content: %+v", ldr.bufLoaderData) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - eRatePrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - FixedFee: utils.NewDecimal(1234, 3), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(89, 3), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(564, 4), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - rcv, err := ldr.dm.GetRateProfile("cgrates.org", "RP1", - true, false, utils.NonTransactional) - if err != nil { - t.Error(err) - } - rcv.Compile() - eRatePrf.Compile() - if !reflect.DeepEqual(rcv, eRatePrf) { - t.Errorf("expecting: %+v,\n received: %+v", utils.ToJSON(eRatePrf), utils.ToJSON(rcv)) - } - - //cannot set RateProfile when dryrun is true - ldr.dryRun = true - rdr = io.NopCloser(strings.NewReader(engine.RateProfileCSVContent)) - csvRdr = csv.NewReader(rdr) - csvRdr.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{fileName: utils.RateProfilesCsv, - rdr: rdr, csvRdr: csvRdr}}, - } - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - -} - -func TestLoaderProcessRateProfileRates(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestLoaderProcessRateProfile", - bufLoaderData: make(map[string][]LoaderData), - flagsTpls: make(map[string]utils.FlagsWithParams), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - {Tag: "FilterIDs", - Path: "FilterIDs", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)}, - {Tag: "ActivationInterval", - Path: "ActivationInterval", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.3", utils.InfieldSep)}, - {Tag: "Weights", - Path: "Weights", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.4", utils.InfieldSep)}, - {Tag: "MinCost", - Path: "MinCost", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.5", utils.InfieldSep)}, - {Tag: "MaxCost", - Path: "MaxCost", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.6", utils.InfieldSep)}, - {Tag: "MaxCostStrategy", - Path: "MaxCostStrategy", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.7", utils.InfieldSep)}, - {Tag: "RateID", - Path: "RateID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.8", utils.InfieldSep)}, - {Tag: "RateFilterIDs", - Path: "RateFilterIDs", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.9", utils.InfieldSep)}, - {Tag: "RateActivationTimes", - Path: "RateActivationTimes", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.10", utils.InfieldSep)}, - {Tag: "RateWeights", - Path: "RateWeights", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.11", utils.InfieldSep)}, - {Tag: "RateBlocker", - Path: "RateBlocker", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.12", utils.InfieldSep)}, - {Tag: "RateIntervalStart", - Path: "RateIntervalStart", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.13", utils.InfieldSep)}, - {Tag: "RateFixedFee", - Path: "RateFixedFee", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.14", utils.InfieldSep)}, - {Tag: "RateRecurrentFee", - Path: "RateRecurrentFee", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.15", utils.InfieldSep)}, - {Tag: "RateUnit", - Path: "RateUnit", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.16", utils.InfieldSep)}, - {Tag: "RateIncrement", - Path: "RateIncrement", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.17", utils.InfieldSep)}, - }, - } - ratePrfCnt1 := ` -#Tenant,ID,FilterIDs,ActivationInterval,Weights,MinCost,MaxCost,MaxCostStrategy,RateID,RateFilterIDs,RateActivationTimes,RateWeights,RateBlocker,RateIntervalStart,RateFixedFee,RateRecurrentFee,RateUnit,RateIncrement -cgrates.org,RP1,*string:~*req.Subject:1001,,;0,0.1,0.6,*free,RT_WEEK,,"* * * * 1-5",;0,false,0s,0.4,0.12,1m,1m -cgrates.org,RP1,,,,,,,RT_WEEK,,,,,1m,,0.06,1m,1s -` - ratePrfCnt2 := ` -#Tenant,ID,FilterIDs,ActivationInterval,Weights,RoundingMethod,RoundingDecimals,MinCost,MaxCost,MaxCostStrategy,RateID,RateFilterIDs,RateActivationTimes,RateWeights,RateBlocker,RateIntervalStart,RateValue,RateUnit,RateIncrement -cgrates.org,RP1,,,,,,,RT_WEEKEND,,"* * * * 0,6",;10,false,0s,,0.06,1m,1s -cgrates.org,RP1,,,,,,,RT_CHRISTMAS,,* * 24 12 *,;30,false,0s,,0.06,1m,1s -` - rdr1 := io.NopCloser(strings.NewReader(ratePrfCnt1)) - csvRdr1 := csv.NewReader(rdr1) - csvRdr1.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{fileName: utils.RateProfilesCsv, - rdr: rdr1, csvRdr: csvRdr1}}, - } - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - if len(ldr.bufLoaderData) != 0 { - t.Errorf("wrong buffer content: %+v", ldr.bufLoaderData) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - eRatePrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(4, 1), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - rcv, err := ldr.dm.GetRateProfile("cgrates.org", "RP1", - true, false, utils.NonTransactional) - if err != nil { - t.Error(err) - } - rcv.Compile() - eRatePrf.Compile() - if !reflect.DeepEqual(rcv, eRatePrf) { - t.Errorf("expecting: %+v,\n received: %+v", utils.ToJSON(eRatePrf), utils.ToJSON(rcv)) - } - - rdr2 := io.NopCloser(strings.NewReader(ratePrfCnt2)) - csvRdr2 := csv.NewReader(rdr2) - csvRdr2.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{fileName: utils.RateProfilesCsv, - rdr: rdr2, csvRdr: csvRdr2}}, - } - ldr.flagsTpls[utils.MetaRateProfiles] = utils.FlagsWithParamsFromSlice([]string{utils.MetaPartial}) - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - if len(ldr.bufLoaderData) != 0 { - t.Errorf("wrong buffer content: %+v", ldr.bufLoaderData) - } - eRatePrf = &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(4, 1), - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - rcv, err = ldr.dm.GetRateProfile("cgrates.org", "RP1", - true, false, utils.NonTransactional) - if err != nil { - t.Error(err) - } - rcv.Compile() - eRatePrf.Compile() - if !reflect.DeepEqual(rcv, eRatePrf) { - t.Errorf("expecting: %+v,\n received: %+v", utils.ToJSON(eRatePrf), utils.ToJSON(rcv)) - } - -} - -func TestLoaderRemoveRateProfileRates(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestLoaderRemoveRateProfileRates", - bufLoaderData: make(map[string][]LoaderData), - flagsTpls: make(map[string]utils.FlagsWithParams), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - {Tag: "RateIDs", - Path: "RateIDs", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)}, - }, - } - - rPfr := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - if err := ldr.dm.SetRateProfile(rPfr, true); err != nil { - t.Error(err) - } - rPfr2 := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP2", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - if err := ldr.dm.SetRateProfile(rPfr2, true); err != nil { - t.Error(err) - } - - ratePrfCnt1 := ` -#Tenant,ID,RateIDs -cgrates.org,RP1,RT_WEEKEND -` - ratePrfCnt2 := ` -#Tenant,ID,RateIDs -cgrates.org,RP2,RT_WEEKEND;RT_CHRISTMAS -cgrates.org,RP1, -` - rdr1 := io.NopCloser(strings.NewReader(ratePrfCnt1)) - csvRdr1 := csv.NewReader(rdr1) - csvRdr1.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{fileName: utils.RateProfilesCsv, - rdr: rdr1, csvRdr: csvRdr1}}, - } - ldr.flagsTpls[utils.MetaRateProfiles] = utils.FlagsWithParamsFromSlice([]string{utils.MetaPartial}) - if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - if len(ldr.bufLoaderData) != 0 { - t.Errorf("wrong buffer content: %+v", ldr.bufLoaderData) - } - - eRatePrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - rcv, err := ldr.dm.GetRateProfile("cgrates.org", "RP1", - true, false, utils.NonTransactional) - if err != nil { - t.Error(err) - } - rcv.Compile() - eRatePrf.Compile() - if !reflect.DeepEqual(rcv, eRatePrf) { - t.Errorf("expecting: %+v,\n received: %+v", utils.ToJSON(eRatePrf), utils.ToJSON(rcv)) - } - - rdr2 := io.NopCloser(strings.NewReader(ratePrfCnt2)) - csvRdr2 := csv.NewReader(rdr2) - csvRdr2.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{fileName: utils.RateProfilesCsv, - rdr: rdr2, csvRdr: csvRdr2}}, - } - ldr.flagsTpls[utils.MetaRateProfiles] = utils.FlagsWithParamsFromSlice([]string{utils.MetaPartial}) - if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - if len(ldr.bufLoaderData) != 0 { - t.Errorf("wrong buffer content: %+v", ldr.bufLoaderData) - } - - eRatePrf2 := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP2", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - }, - }, - } - rcv, err = ldr.dm.GetRateProfile("cgrates.org", "RP2", - true, false, utils.NonTransactional) - if err != nil { - t.Error(err) - } - rcv.Compile() - eRatePrf2.Compile() - if !reflect.DeepEqual(rcv, eRatePrf2) { - t.Errorf("expecting: %+v,\n received: %+v", utils.ToJSON(eRatePrf2), utils.ToJSON(rcv)) - } - - eRatePrf3 := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{}, - } - rcv, err = ldr.dm.GetRateProfile("cgrates.org", "RP1", - true, false, utils.NonTransactional) - if err != nil { - t.Error(err) - } - rcv.Compile() - eRatePrf3.Compile() - if !reflect.DeepEqual(rcv, eRatePrf3) { - t.Errorf("expecting: %+v,\n received: %+v", utils.ToJSON(eRatePrf3), utils.ToJSON(rcv)) - } -} - -func TestRemoveRateProfileFlagsError(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestLoaderRemoveRateProfileRates", - bufLoaderData: make(map[string][]LoaderData), - flagsTpls: make(map[string]utils.FlagsWithParams), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - }, - } - ratePrfCnt1 := ` -#Tenant,ID -cgrates.org,RP2 -` - rPfr := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - } - if err := ldr.dm.SetRateProfile(rPfr, true); err != nil { - t.Error(err) - } - - rdr1 := io.NopCloser(strings.NewReader(ratePrfCnt1)) - csvRdr1 := csv.NewReader(rdr1) - csvRdr1.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{fileName: utils.RateProfilesCsv, - rdr: rdr1, csvRdr: csvRdr1}}, - } - ldr.flagsTpls[utils.MetaRateProfiles] = utils.FlagsWithParamsFromSlice([]string{utils.MetaPartial}) - expectedErr := "cannot find RateIDs in " - if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } -} - func TestNewLoaderWithMultiFiles(t *testing.T) { data := engine.NewInternalDB(nil, nil, true) @@ -2351,7 +1503,6 @@ func TestNewLoaderWithMultiFiles(t *testing.T) { "File1.csv": {}, "File2.csv": {}, utils.FiltersCsv: {}, - utils.RateProfilesCsv: {}, utils.ResourcesCsv: {}, utils.RoutesCsv: {}, utils.StatsCsv: {}, @@ -3408,82 +2559,6 @@ NOT_UINT } } -func TestLoadRateProfilesAsStructErrType(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestLoadRateProfilesAsStructErrType", - bufLoaderData: make(map[string][]LoaderData), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "PK", - Path: "PK", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep)}, - }, - } - thresholdsCsv := ` -#PK -NOT_UINT -` - rdr := io.NopCloser(strings.NewReader(thresholdsCsv)) - rdrCsv := csv.NewReader(rdr) - rdrCsv.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: rdrCsv, - }, - }, - } - expectedErr := "cannot update unsupported struct field: 0" - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } -} - -func TestLoadRateProfilesAsStructErrConversion(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestLoadRateProfilesAsStructErrConversion", - bufLoaderData: make(map[string][]LoaderData), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "ActivationInterval", - Path: "ActivationInterval", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep)}, - }, - } - thresholdsCsv := ` -#ActivationInterval -* * * * * * -` - rdr := io.NopCloser(strings.NewReader(thresholdsCsv)) - rdrCsv := csv.NewReader(rdr) - rdrCsv.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: rdrCsv, - }, - }, - } - expectedErr := "Unsupported time format" - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } -} - func TestLoadAndRemoveResources(t *testing.T) { data := engine.NewInternalDB(nil, nil, true) ldr := &Loader{ @@ -4310,100 +3385,6 @@ func TestProcessContentEmptyDataBase(t *testing.T) { } } -func TestRemoveRateProfileContent(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestRemoveRateProfileContent", - bufLoaderData: make(map[string][]LoaderData), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - }, - } - rtPrfCsv := ` -#Tenant[0],ID[1] -cgrates.org,REM_RATEPROFILE_1 -` - rdr := io.NopCloser(strings.NewReader(rtPrfCsv)) - csvRdr := csv.NewReader(rdr) - csvRdr.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: csvRdr, - }, - }, - } - expRtPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "REM_RATEPROFILE_1", - } - if err := ldr.dm.SetRateProfile(expRtPrf, true); err != nil { - t.Error(err) - } else if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - - //nothing to remvoe from database - if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err != utils.ErrNotFound { - t.Error(err) - } - - //cannot remove DispatcherHosts when dryrun is true - ldr.dryRun = true - rdr = io.NopCloser(strings.NewReader(rtPrfCsv)) - csvRdr = csv.NewReader(rdr) - csvRdr.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: csvRdr, - }, - }, - } - if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } - - ldr.dryRun = true - ldr.flagsTpls = map[string]utils.FlagsWithParams{ - utils.MetaRateProfiles: { - utils.MetaPartial: nil, - }, - } - rdr = io.NopCloser(strings.NewReader(rtPrfCsv)) - csvRdr = csv.NewReader(rdr) - csvRdr.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: csvRdr, - }, - }, - } - if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err != nil { - t.Error(err) - } -} - func TestRemoveActionProfileContent(t *testing.T) { data := engine.NewInternalDB(nil, nil, true) ldr := &Loader{ @@ -4611,91 +3592,6 @@ func TestLoaderListenAndServe(t *testing.T) { } } -func TestRemoveRateProfileRatesError(t *testing.T) { - data := engine.NewInternalDB(nil, nil, true) - ldr := &Loader{ - ldrID: "TestRemoveRateProfileRatesMockError", - bufLoaderData: make(map[string][]LoaderData), - flagsTpls: make(map[string]utils.FlagsWithParams), - dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil), - timezone: "UTC", - } - ldr.dataTpls = map[string][]*config.FCTemplate{ - utils.MetaRateProfiles: { - {Tag: "TenantID", - Path: "Tenant", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep), - Mandatory: true}, - {Tag: "ProfileID", - Path: "ID", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep), - Mandatory: true}, - {Tag: "RateIDs", - Path: "RateIDs", - Type: utils.MetaComposed, - Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)}, - }, - } - rtPrfCsv := ` -#Tenant[0],ID[1],RateIDs[2] -cgrates.org,REM_RATEPROFILE_1,RT_WEEKEND -` - rdr := io.NopCloser(strings.NewReader(rtPrfCsv)) - csvRdr := csv.NewReader(rdr) - csvRdr.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: csvRdr, - }, - }, - } - expRtPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "REM_RATEPROFILE_1", - } - ldr.flagsTpls[utils.MetaRateProfiles] = utils.FlagsWithParamsFromSlice([]string{utils.MetaPartial}) - ldr.dm = nil - expected := "NO_DATA_BASE_CONNECTION" - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(err)) - } - - rdr = io.NopCloser(strings.NewReader(rtPrfCsv)) - csvRdr = csv.NewReader(rdr) - csvRdr.Comment = '#' - ldr.rdrs = map[string]map[string]*openedCSVFile{ - utils.MetaRateProfiles: { - utils.RateProfilesCsv: &openedCSVFile{ - fileName: utils.RateProfilesCsv, - rdr: rdr, - csvRdr: csvRdr, - }, - }, - } - ldr.flagsTpls[utils.MetaRateProfiles] = utils.FlagsWithParamsFromSlice([]string{"INVALID_FLAGS"}) - expected = "NO_DATA_BASE_CONNECTION" - if err := ldr.processContent(utils.MetaRateProfiles, utils.EmptyString); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(err)) - } - - ldr.dm = engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - if err := ldr.dm.SetRateProfile(expRtPrf, true); err != nil { - t.Error(err) - } - - ldr.dm = nil - ldr.flagsTpls[utils.MetaRateProfiles] = utils.FlagsWithParamsFromSlice([]string{utils.MetaPartial}) - expected = "NO_DATA_BASE_CONNECTION" - if err := ldr.removeContent(utils.MetaRateProfiles, utils.EmptyString); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(err)) - } -} - func TestRemoveThresholdsMockError(t *testing.T) { data := engine.NewInternalDB(nil, nil, true) ldr := &Loader{ diff --git a/migrator/migrator.go b/migrator/migrator.go index d4e0c212f..2c66fd8a1 100755 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -143,8 +143,6 @@ func (m *Migrator) Migrate(taskIDs []string) (err error, stats map[string]int) { err = m.migrateTimings() case utils.MetaResources: err = m.migrateResources() - case utils.MetaRateProfiles: - err = m.migrateRateProfiles() case MetaAliases: err = m.migrateAlias() case utils.MetaUsers: @@ -182,8 +180,6 @@ func (m *Migrator) Migrate(taskIDs []string) (err error, stats map[string]int) { err = m.migrateTPsharedgroups() case utils.MetaTpRatingProfiles: err = m.migrateTPratingprofiles() - case utils.MetaTpRateProfiles: - err = m.migrateTPRateProfiles() case utils.MetaTpActionProfiles: err = m.migrateTPActionProfiles() case utils.MetaTpResources: diff --git a/migrator/rateprofiles.go b/migrator/rateprofiles.go deleted file mode 100644 index 3571cdbd1..000000000 --- a/migrator/rateprofiles.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package migrator - -import ( - "fmt" - "strings" - - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" -) - -func (m *Migrator) migrateCurrentRateProfiles() (err error) { - var ids []string - ids, err = m.dmIN.DataManager().DataDB().GetKeysForPrefix(utils.RateProfilePrefix) - if err != nil { - return err - } - for _, id := range ids { - tntID := strings.SplitN(strings.TrimPrefix(id, utils.RateProfilePrefix), utils.InInFieldSep, 2) - if len(tntID) < 2 { - return fmt.Errorf("Invalid key <%s> when migrating rate profiles", id) - } - rp, err := m.dmIN.DataManager().GetRateProfile(tntID[0], tntID[1], false, false, utils.NonTransactional) - if err != nil { - return err - } - if rp == nil || m.dryRun { - continue - } - if err := m.dmOut.DataManager().SetRateProfile(rp, true); err != nil { - return err - } - if err := m.dmIN.DataManager().RemoveRateProfile(tntID[0], tntID[1], utils.NonTransactional, false); err != nil { - return err - } - m.stats[utils.RateProfiles]++ - } - return -} - -func (m *Migrator) migrateRateProfiles() (err error) { - var vrs engine.Versions - current := engine.CurrentDataDBVersions() - if vrs, err = m.getVersions(utils.RateProfiles); err != nil { - return - } - - migrated := true - for { - version := vrs[utils.RateProfiles] - for { - switch version { - default: - return fmt.Errorf("Unsupported version %v", version) - case current[utils.RateProfiles]: - migrated = false - if m.sameDataDB { - break - } - if err = m.migrateCurrentRateProfiles(); err != nil { - return - } - } - if version == current[utils.RateProfiles] || err == utils.ErrNoMoreData { - break - } - } - if err == utils.ErrNoMoreData || !migrated { - break - } - m.stats[utils.RateProfiles]++ - } - // All done, update version wtih current one - if err = m.setVersions(utils.RateProfiles); err != nil { - return - } - return m.ensureIndexesDataDB(engine.ColRpp) -} diff --git a/migrator/rateprofiles_it_test.go b/migrator/rateprofiles_it_test.go deleted file mode 100644 index 0754fa2f9..000000000 --- a/migrator/rateprofiles_it_test.go +++ /dev/null @@ -1,275 +0,0 @@ -// +build integration - -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package migrator - -import ( - "log" - "path" - "reflect" - "testing" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" -) - -var ( - ratePrfPathIn string - ratePrfPathOut string - ratePrfCfgIn *config.CGRConfig - ratePrfCfgOut *config.CGRConfig - ratePrfMigrator *Migrator - ratePrfAction string -) - -var sTestsRatePrfIT = []func(t *testing.T){ - testRatePrfITConnect, - testRatePrfITFlush, - testRatePrfITMigrateAndMove, -} - -func TestRatePrfITMove1(t *testing.T) { - var err error - ratePrfPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo") - ratePrfCfgIn, err = config.NewCGRConfigFromPath(ratePrfPathIn) - if err != nil { - t.Fatal(err) - } - ratePrfPathOut = path.Join(*dataDir, "conf", "samples", "tutmysql") - ratePrfCfgOut, err = config.NewCGRConfigFromPath(ratePrfPathOut) - if err != nil { - t.Fatal(err) - } - ratePrfAction = utils.Move - for _, stest := range sTestsRatePrfIT { - t.Run("TestRatePrfITMove", stest) - } - ratePrfMigrator.Close() -} - -func TestRatePrfITMove2(t *testing.T) { - var err error - ratePrfPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql") - ratePrfCfgIn, err = config.NewCGRConfigFromPath(ratePrfPathIn) - if err != nil { - t.Fatal(err) - } - ratePrfPathOut = path.Join(*dataDir, "conf", "samples", "tutmongo") - ratePrfCfgOut, err = config.NewCGRConfigFromPath(ratePrfPathOut) - if err != nil { - t.Fatal(err) - } - ratePrfAction = utils.Move - for _, stest := range sTestsRatePrfIT { - t.Run("TestRatePrfITMove", stest) - } - ratePrfMigrator.Close() -} - -func TestRatePrfITMoveEncoding(t *testing.T) { - var err error - ratePrfPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo") - ratePrfCfgIn, err = config.NewCGRConfigFromPath(ratePrfPathIn) - if err != nil { - t.Fatal(err) - } - ratePrfPathOut = path.Join(*dataDir, "conf", "samples", "tutmongojson") - ratePrfCfgOut, err = config.NewCGRConfigFromPath(ratePrfPathOut) - if err != nil { - t.Fatal(err) - } - ratePrfAction = utils.Move - for _, stest := range sTestsRatePrfIT { - t.Run("TestRatePrfITMoveEncoding", stest) - } - ratePrfMigrator.Close() -} - -func TestRatePrfITMoveEncoding2(t *testing.T) { - var err error - ratePrfPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql") - ratePrfCfgIn, err = config.NewCGRConfigFromPath(ratePrfPathIn) - if err != nil { - t.Fatal(err) - } - ratePrfPathOut = path.Join(*dataDir, "conf", "samples", "tutmysqljson") - ratePrfCfgOut, err = config.NewCGRConfigFromPath(ratePrfPathOut) - if err != nil { - t.Fatal(err) - } - ratePrfAction = utils.Move - for _, stest := range sTestsRatePrfIT { - t.Run("TestRatePrfITMoveEncoding2", stest) - } - ratePrfMigrator.Close() -} - -func testRatePrfITConnect(t *testing.T) { - dataDBIn, err := NewMigratorDataDB(ratePrfCfgIn.DataDbCfg().Type, - ratePrfCfgIn.DataDbCfg().Host, ratePrfCfgIn.DataDbCfg().Port, - ratePrfCfgIn.DataDbCfg().Name, ratePrfCfgIn.DataDbCfg().User, - ratePrfCfgIn.DataDbCfg().Password, ratePrfCfgIn.GeneralCfg().DBDataEncoding, - config.CgrConfig().CacheCfg(), ratePrfCfgIn.DataDbCfg().Opts) - if err != nil { - log.Fatal(err) - } - dataDBOut, err := NewMigratorDataDB(ratePrfCfgOut.DataDbCfg().Type, - ratePrfCfgOut.DataDbCfg().Host, ratePrfCfgOut.DataDbCfg().Port, - ratePrfCfgOut.DataDbCfg().Name, ratePrfCfgOut.DataDbCfg().User, - ratePrfCfgOut.DataDbCfg().Password, ratePrfCfgOut.GeneralCfg().DBDataEncoding, - config.CgrConfig().CacheCfg(), ratePrfCfgOut.DataDbCfg().Opts) - if err != nil { - log.Fatal(err) - } - if reflect.DeepEqual(ratePrfPathIn, ratePrfPathOut) { - ratePrfMigrator, err = NewMigrator(dataDBIn, dataDBOut, nil, nil, - false, true, false, false) - } else { - ratePrfMigrator, err = NewMigrator(dataDBIn, dataDBOut, nil, nil, - false, false, false, false) - } - if err != nil { - log.Fatal(err) - } -} - -func testRatePrfITFlush(t *testing.T) { - if err := ratePrfMigrator.dmOut.DataManager().DataDB().Flush(""); err != nil { - t.Error(err) - } - if isEmpty, err := ratePrfMigrator.dmOut.DataManager().DataDB().IsDBEmpty(); err != nil { - t.Error(err) - } else if isEmpty != true { - t.Errorf("Expecting: true got :%+v", isEmpty) - } - if err := engine.SetDBVersions(ratePrfMigrator.dmOut.DataManager().DataDB()); err != nil { - t.Error("Error ", err.Error()) - } - if err := ratePrfMigrator.dmIN.DataManager().DataDB().Flush(""); err != nil { - t.Error(err) - } - if isEmpty, err := ratePrfMigrator.dmIN.DataManager().DataDB().IsDBEmpty(); err != nil { - t.Error(err) - } else if isEmpty != true { - t.Errorf("Expecting: true got :%+v", isEmpty) - } - if err := engine.SetDBVersions(ratePrfMigrator.dmIN.DataManager().DataDB()); err != nil { - t.Error("Error ", err.Error()) - } -} - -func testRatePrfITMigrateAndMove(t *testing.T) { - minDec, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDec, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - MinCost: utils.NewDecimal(1, 1), - MaxCost: utils.NewDecimal(6, 1), - MaxCostStrategy: "*free", - Rates: map[string]*utils.Rate{ - "FIRST_GI": { - ID: "FIRST_GI", - FilterIDs: []string{"*gi:~*req.Usage:0"}, - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - RecurrentFee: utils.NewDecimal(12, 2), - Unit: minDec, - Increment: minDec, - }, - }, - Blocker: false, - }, - "SECOND_GI": { - ID: "SECOND_GI", - FilterIDs: []string{"*gi:~*req.Usage:1m"}, - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - RecurrentFee: utils.NewDecimal(6, 2), - Unit: minDec, - Increment: secDec, - }, - }, - Blocker: false, - }, - }, - } - if err := rPrf.Compile(); err != nil { - t.Fatal(err) - } - switch ratePrfAction { - case utils.Migrate: //QQ for the moment only one version of rate profiles exists - case utils.Move: - if err := ratePrfMigrator.dmIN.DataManager().SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - currentVersion := engine.CurrentDataDBVersions() - err := ratePrfMigrator.dmIN.DataManager().DataDB().SetVersions(currentVersion, false) - if err != nil { - t.Error("Error when setting version for RatePrf ", err.Error()) - } - - _, err = ratePrfMigrator.dmOut.DataManager().GetRateProfile("cgrates.org", "RP1", false, false, utils.NonTransactional) - if err != utils.ErrNotFound { - t.Error(err) - } - - err, _ = ratePrfMigrator.Migrate([]string{utils.MetaRateProfiles}) - if err != nil { - t.Error("Error when migrating RatePrf ", err.Error()) - } - ratePrfult, err := ratePrfMigrator.dmOut.DataManager().GetRateProfile("cgrates.org", "RP1", false, false, utils.NonTransactional) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(ratePrfult, rPrf) { - t.Errorf("Expecting: %+v, received: %+v", rPrf, ratePrfult) - } - ratePrfult, err = ratePrfMigrator.dmIN.DataManager().GetRateProfile("cgrates.org", "RP1", false, false, utils.NonTransactional) - if err != utils.ErrNotFound { - t.Error(err) - } else if ratePrfMigrator.stats[utils.RateProfiles] != 1 { - t.Errorf("Expected 1, received: %v", ratePrfMigrator.stats[utils.RateProfiles]) - } - } -} diff --git a/migrator/rating_plan_it_test.go b/migrator/rating_plan_it_test.go index 8f776bbad..1b0aeebce 100644 --- a/migrator/rating_plan_it_test.go +++ b/migrator/rating_plan_it_test.go @@ -127,7 +127,7 @@ func testRtPlITConnect(t *testing.T) { rtplCfgIn.DataDbCfg().Host, rtplCfgIn.DataDbCfg().Port, rtplCfgIn.DataDbCfg().Name, rtplCfgIn.DataDbCfg().User, rtplCfgIn.DataDbCfg().Password, rtplCfgIn.GeneralCfg().DBDataEncoding, - config.CgrConfig().CacheCfg(), ratePrfCfgIn.DataDbCfg().Opts) + config.CgrConfig().CacheCfg(), rtplCfgIn.DataDbCfg().Opts) if err != nil { log.Fatal(err) } @@ -135,7 +135,7 @@ func testRtPlITConnect(t *testing.T) { rtplCfgOut.DataDbCfg().Host, rtplCfgOut.DataDbCfg().Port, rtplCfgOut.DataDbCfg().Name, rtplCfgOut.DataDbCfg().User, rtplCfgOut.DataDbCfg().Password, rtplCfgOut.GeneralCfg().DBDataEncoding, - config.CgrConfig().CacheCfg(), ratePrfCfgOut.DataDbCfg().Opts) + config.CgrConfig().CacheCfg(), rtplCfgOut.DataDbCfg().Opts) if err != nil { log.Fatal(err) } diff --git a/migrator/tp_rate_profiles.go b/migrator/tp_rate_profiles.go deleted file mode 100644 index 33dbade25..000000000 --- a/migrator/tp_rate_profiles.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package migrator - -import ( - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" -) - -func (m *Migrator) migrateCurrentTPRateProfiles() (err error) { - tpids, err := m.storDBIn.StorDB().GetTpIds(utils.TBLTPRateProfiles) - if err != nil { - return err - } - - for _, tpid := range tpids { - ids, err := m.storDBIn.StorDB().GetTpTableIds(tpid, utils.TBLTPRateProfiles, - utils.TPDistinctIds{"id"}, map[string]string{}, nil) - if err != nil { - return err - } - for _, id := range ids { - rateProfiles, err := m.storDBIn.StorDB().GetTPRateProfiles(tpid, utils.EmptyString, id) - if err != nil { - return err - } - if rateProfiles == nil || m.dryRun { - continue - } - if err := m.storDBOut.StorDB().SetTPRateProfiles(rateProfiles); err != nil { - return err - } - for _, rateProfile := range rateProfiles { - if err := m.storDBIn.StorDB().RemTpData(utils.TBLTPRateProfiles, rateProfile.TPid, - map[string]string{"tenant": rateProfile.Tenant, "id": rateProfile.ID}); err != nil { - return err - } - } - m.stats[utils.TpRateProfiles]++ - } - } - return -} - -func (m *Migrator) migrateTPRateProfiles() (err error) { - var vrs engine.Versions - current := engine.CurrentStorDBVersions() - if vrs, err = m.getVersions(utils.TpRateProfiles); err != nil { - return err - } - switch vrs[utils.TpRateProfiles] { - case current[utils.TpRateProfiles]: - if m.sameStorDB { - break - } - if err := m.migrateCurrentTPRateProfiles(); err != nil { - return err - } - } - return m.ensureIndexesStorDB(utils.TpRateProfiles) -} diff --git a/migrator/tp_rate_profiles_it_test.go b/migrator/tp_rate_profiles_it_test.go deleted file mode 100644 index b7f75cf22..000000000 --- a/migrator/tp_rate_profiles_it_test.go +++ /dev/null @@ -1,184 +0,0 @@ -// +build integration - -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package migrator - -import ( - "path" - "reflect" - "testing" - - "github.com/cgrates/cgrates/engine" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/utils" -) - -var ( - tpRatePrfPathIn string - tpRatePrfPathOut string - tpRatePrfCfgIn *config.CGRConfig - tpRatePrfCfgOut *config.CGRConfig - tpRatePrfMigrator *Migrator - tpRateProfiles []*utils.TPRateProfile -) - -var sTestsTPRatePrfIT = []func(t *testing.T){ - testTPRateProfileConnect, - testTPRateProfileFlush, - testTPRateProfilePopulate, - testTpRateProfileMove, - testTpRateProfileCheckData, -} - -func TestTPRateProfileIT(t *testing.T) { - for _, tests := range sTestsTPRatePrfIT { - t.Run("TestTPRatePrfIT", tests) - } - tpRatePrfMigrator.Close() -} - -func testTPRateProfileConnect(t *testing.T) { - var err error - tpRatePrfPathIn := path.Join(*dataDir, "conf", "samples", "tutmongo") - if tpRatePrfCfgIn, err = config.NewCGRConfigFromPath(tpRatePrfPathIn); err != nil { - t.Error(err) - } - tpRatePrfPathOut := path.Join(*dataDir, "conf", "samples", "tutmysql") - if tpRatePrfCfgOut, err = config.NewCGRConfigFromPath(tpRatePrfPathOut); err != nil { - t.Error(err) - } - storDBIn, err := NewMigratorStorDB(tpRatePrfCfgIn.StorDbCfg().Type, - tpRatePrfCfgIn.StorDbCfg().Host, tpRatePrfCfgIn.StorDbCfg().Port, - tpRatePrfCfgIn.StorDbCfg().Name, tpRatePrfCfgIn.StorDbCfg().User, - tpRatePrfCfgIn.StorDbCfg().Password, tpRatePrfCfgIn.GeneralCfg().DBDataEncoding, - tpRatePrfCfgIn.StorDbCfg().StringIndexedFields, tpRatePrfCfgIn.StorDbCfg().PrefixIndexedFields, - tpRatePrfCfgIn.StorDbCfg().Opts) - if err != nil { - t.Error(err) - } - storDBOut, err := NewMigratorStorDB(tpRatePrfCfgOut.StorDbCfg().Type, - tpRatePrfCfgOut.StorDbCfg().Host, tpRatePrfCfgOut.StorDbCfg().Port, - tpRatePrfCfgOut.StorDbCfg().Name, tpRatePrfCfgOut.StorDbCfg().User, - tpRatePrfCfgOut.StorDbCfg().Password, tpRatePrfCfgOut.GeneralCfg().DBDataEncoding, - tpRatePrfCfgOut.StorDbCfg().StringIndexedFields, tpRatePrfCfgOut.StorDbCfg().PrefixIndexedFields, - tpRatePrfCfgOut.StorDbCfg().Opts) - if err != nil { - t.Error(err) - } - tpRatePrfMigrator, err = NewMigrator(nil, nil, storDBIn, storDBOut, - false, false, false, false) - if err != nil { - t.Error(err) - } -} - -func testTPRateProfileFlush(t *testing.T) { - if err := tpRatePrfMigrator.storDBIn.StorDB().Flush( - path.Join(tpRatePrfCfgIn.DataFolderPath, "storage", tpRatePrfCfgIn.StorDbCfg().Type)); err != nil { - t.Error(err) - } - if err := tpRatePrfMigrator.storDBOut.StorDB().Flush( - path.Join(tpRatePrfCfgOut.DataFolderPath, "storage", tpRatePrfCfgOut.StorDbCfg().Type)); err != nil { - t.Error(err) - } -} - -func testTPRateProfilePopulate(t *testing.T) { - tpRateProfiles = []*utils.TPRateProfile{ - { - TPid: "id_RP1", - Tenant: "cgrates.org", - ID: "RP1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: ";0", - MinCost: 0.1, - MaxCost: 0.6, - MaxCostStrategy: "*free", - Rates: map[string]*utils.TPRate{ - "FIRST_GI": { - ID: "FIRST_GI", - FilterIDs: []string{"*gi:~*req.Usage:0"}, - Weights: ";0", - IntervalRates: []*utils.TPIntervalRate{ - { - RecurrentFee: 0.12, - Unit: "1m", - Increment: "1m", - }, - }, - Blocker: false, - }, - "SECOND_GI": { - ID: "SECOND_GI", - FilterIDs: []string{"*gi:~*req.Usage:1m"}, - Weights: ";10", - IntervalRates: []*utils.TPIntervalRate{ - { - RecurrentFee: 0.06, - Unit: "1m", - Increment: "1s", - }, - }, - Blocker: false, - }, - }, - }, - } - //empty in database - if _, err := tpRatePrfMigrator.storDBIn.StorDB().GetTPRateProfiles(tpRateProfiles[0].TPid, - utils.EmptyString, tpRateProfiles[0].ID); err != utils.ErrNotFound { - t.Error(err) - } - - if err := tpRatePrfMigrator.storDBIn.StorDB().SetTPRateProfiles(tpRateProfiles); err != nil { - t.Error("Error when setting TpRateProfile ", err.Error()) - } - currentVersion := engine.CurrentStorDBVersions() - err := tpRatePrfMigrator.storDBIn.StorDB().SetVersions(currentVersion, false) - if err != nil { - t.Error("Error when setting version for TpRateProfile ", err.Error()) - } -} - -func testTpRateProfileMove(t *testing.T) { - err, _ := tpRatePrfMigrator.Migrate([]string{utils.MetaTpRateProfiles}) - if err != nil { - t.Error("Error when migrating TpRateProfiles", err.Error()) - } -} - -func testTpRateProfileCheckData(t *testing.T) { - rcv, err := tpRatePrfMigrator.storDBOut.StorDB().GetTPRateProfiles(tpRateProfiles[0].TPid, - utils.EmptyString, tpRateProfiles[0].ID) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(rcv[0], tpRateProfiles[0]) { - t.Errorf("Expected %+v, received %+v", tpRateProfiles[0], rcv[0]) - } - - _, err = tpRatePrfMigrator.storDBIn.StorDB().GetTPRateProfiles(tpRateProfiles[0].TPid, - utils.EmptyString, tpRateProfiles[0].ID) - if err != utils.ErrNotFound { - t.Error(err) - } - -} diff --git a/rates/librates.go b/rates/librates.go deleted file mode 100644 index 84e1a2e71..000000000 --- a/rates/librates.go +++ /dev/null @@ -1,281 +0,0 @@ -/* -Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package rates - -import ( - "fmt" - "sort" - "time" - - "github.com/ericlagergren/decimal" - - "github.com/cgrates/cgrates/utils" -) - -type rpWithWeight struct { - *utils.RateProfile - weight float64 -} - -func newRatesWithWinner(rIt *rateWithTimes) *ratesWithWinner { - return &ratesWithWinner{ - rts: map[string]*rateWithTimes{ - rIt.id(): rIt, - }, - wnr: rIt, - } -} - -func initRatesWithWinner() *ratesWithWinner { - return &ratesWithWinner{ - rts: make(map[string]*rateWithTimes), - } -} - -// ratesWithWinner computes always the winner based on highest Weight -type ratesWithWinner struct { - rts map[string]*rateWithTimes - wnr *rateWithTimes -} - -//add will add the rate to the rates -func (rs *ratesWithWinner) add(rWt *rateWithTimes) { - rs.rts[rWt.id()] = rWt - if rs.wnr == nil || rs.wnr.weight < rWt.weight { - rs.wnr = rWt - } -} - -// winner returns the rate with the highest Weight -func (rs *ratesWithWinner) winner() *rateWithTimes { - return rs.wnr -} - -// has tests if the rateID is present in rates -func (rs *ratesWithWinner) has(rtID string) (has bool) { - _, has = rs.rts[rtID] - return -} - -// rateWithTimes activates a rate on an interval -type rateWithTimes struct { - uId string - rt *utils.Rate - aTime, - iTime time.Time - weight float64 -} - -// id is used to provide an unique identifier for a rateWithTimes -func (rWt *rateWithTimes) id() string { - if rWt.uId == "" { - rWt.uId = fmt.Sprintf("%s_%d", rWt.rt.ID, rWt.aTime.Unix()) - } - return rWt.uId -} - -type orderedRate struct { - *decimal.Big - *utils.Rate -} - -// orderRatesOnIntervals will order the rates based on ActivationInterval and intervalStart of each Rate -// there can be only one winning Rate for each interval, prioritized by the Weight -func orderRatesOnIntervals(aRts []*utils.Rate, wghts []float64, sTime time.Time, usage *decimal.Big, - isDuration bool, verbosity int) (ordRts []*orderedRate, err error) { - - usageInt, ok := usage.Int64() - if !ok { - return nil, fmt.Errorf("<%s> cannot convert <%+v> increment to Int64", utils.RateS, usage) - } - endTime := sTime.Add(time.Duration(usageInt)) - - // index the received rates based on unique times they run - rtIdx := make(map[time.Time]*ratesWithWinner) // map[ActivationTimes]*ratesWithWinner - allRates := make(map[string]*rateWithTimes) - for i, rt := range aRts { - var rTimes [][]time.Time - if rTimes, err = rt.RunTimes(sTime, endTime, verbosity); err != nil { - return - } - for _, rTimeSet := range rTimes { - rIt := &rateWithTimes{ - rt: rt, - aTime: rTimeSet[0], - iTime: rTimeSet[1], - weight: wghts[i], // weights are in order of aRts - } - allRates[rIt.id()] = rIt - if _, hasKey := rtIdx[rTimeSet[0]]; !hasKey { - rtIdx[rTimeSet[0]] = initRatesWithWinner() - } - rtIdx[rTimeSet[0]].add(rIt) - if rTimeSet[1].IsZero() { // the rate will always be active - continue - } - if _, hasKey := rtIdx[rTimeSet[1]]; !hasKey { - rtIdx[rTimeSet[1]] = initRatesWithWinner() - } - } - } - // add the active rates to all time samples - for tm, rWw := range rtIdx { - for _, rIt := range allRates { - if rWw.has(rIt.id()) || - rIt.aTime.After(tm) || - (!rIt.iTime.IsZero() && !tm.Before(rIt.iTime)) { - continue - } - rWw.add(rIt) - } - } - - // sort the activation times - sortedATimes := make([]time.Time, len(rtIdx)) - idxATimes := 0 - for aTime := range rtIdx { - sortedATimes[idxATimes] = aTime - idxATimes++ - } - sort.Slice(sortedATimes, func(i, j int) bool { - return sortedATimes[i].Before(sortedATimes[j]) - }) - // start with most recent activationTime lower or equal to sTime - for i, aT := range sortedATimes { - if !aT.After(sTime) || i == 0 { - continue - } - sortedATimes = sortedATimes[i-1:] - break - } - - // compute the list of returned rates together with their index interval - if isDuration { - // add all the possible ActivationTimes from cron expressions - usageIndx := decimal.New(0, 0) // the difference between setup and activation time of the rate - for _, aTime := range sortedATimes { - if !endTime.After(aTime) { - break // we are not interested about further rates - } - wnr := rtIdx[aTime].winner() - if wnr == nil { - continue - } - if sTime.Before(aTime) { - usageIndx = decimal.New(int64(aTime.Sub(sTime)), 0) - } - if len(ordRts) == 0 || wnr.rt.ID != ordRts[len(ordRts)-1].Rate.ID { // only add the winner if not already active - ordRts = append(ordRts, &orderedRate{usageIndx, rtIdx[aTime].winner().rt}) - } - } - } else { // only first rate is considered for units - ordRts = []*orderedRate{{decimal.New(0, 0), rtIdx[sortedATimes[0]].winner().rt}} - } - return -} - -// computeRateSIntervals will give out the cost projection for the given orderedRates and usage -func computeRateSIntervals(rts []*orderedRate, intervalStart, usage *decimal.Big) (rtIvls []*utils.RateSInterval, err error) { - totalUsage := usage - if intervalStart.Cmp(decimal.New(0, 0)) != 0 { - totalUsage = utils.SumBig(usage, intervalStart) - } - for i, rt := range rts { - isLastRt := i == len(rts)-1 - var rtUsageEIdx *decimal.Big - if !isLastRt { - rtUsageEIdx = rts[i+1].Big - } else { - rtUsageEIdx = totalUsage - } - var rIcmts []*utils.RateSIncrement - iRtUsageSIdx := intervalStart - iRtUsageEIdx := rtUsageEIdx - for j, iRt := range rt.IntervalRates { - //fmt.Printf("ivalStart: %v, ivalEnd: %v, rtID: %s, increment idx: %d, iRtUsageSIdx: %+v, iRtUsageEIdx: %+v, iRt: %s\n", - // intervalStart, rtUsageEIdx, rt.ID, j, iRtUsageSIdx, iRtUsageEIdx, utils.ToIJSON(iRt)) - if iRtUsageSIdx.Cmp(rtUsageEIdx) >= 0 { // charged enough for interval - break - } - // make sure we bill from start - if iRt.IntervalStart.Cmp(iRtUsageSIdx) > 0 && j == 0 { - return nil, fmt.Errorf("intervalStart for rate: <%s> higher than usage: %v", - rt.UID(), iRtUsageSIdx) - } - isLastIRt := j == len(rt.IntervalRates)-1 - if !isLastIRt && rt.IntervalRates[j+1].IntervalStart.Cmp(iRtUsageSIdx) <= 0 { - continue // the next interval changes the rating - } - if isLastIRt { - iRtUsageEIdx = rtUsageEIdx - } else if rt.IntervalRates[j+1].IntervalStart.Cmp(rtUsageEIdx) > 0 { - iRtUsageEIdx = rtUsageEIdx - } else { - iRtUsageEIdx = rt.IntervalRates[j+1].IntervalStart.Big - } - if iRt.Increment.Cmp(decimal.New(0, 0)) == 0 { - return nil, fmt.Errorf("zero increment to be charged within rate: <%s>", rt.UID()) - } - if rt.IntervalRates[j].FixedFee != nil && rt.IntervalRates[j].FixedFee.Cmp(decimal.New(0, 0)) != 0 { // Add FixedFee - rIcmts = append(rIcmts, &utils.RateSIncrement{ - IncrementStart: &utils.Decimal{iRtUsageSIdx}, - Rate: rt.Rate, - IntervalRateIndex: j, - CompressFactor: 1, - Usage: utils.NewDecimal(utils.InvalidUsage, 0), - }) - } - iRtUsage := utils.SubstractBig(iRtUsageEIdx, iRtUsageSIdx) - intUsage := iRtUsage - intIncrm := iRt.Increment.Big - cmpFactor, rem := utils.DivideBigWithReminder(intUsage, intIncrm) - if rem.Cmp(decimal.New(0, 0)) != 0 { - cmpFactor = utils.SumBig(cmpFactor, decimal.New(1, 0)) // int division has used math.Floor, need Ceil - } - cmpFactorInt, ok := cmpFactor.Int64() - if !ok { - return nil, fmt.Errorf("<%s> cannot convert <%+v> increment to Int64", utils.RateS, cmpFactor) - } - rIcmts = append(rIcmts, &utils.RateSIncrement{ - IncrementStart: &utils.Decimal{iRtUsageSIdx}, - Rate: rt.Rate, - IntervalRateIndex: j, - CompressFactor: cmpFactorInt, - Usage: &utils.Decimal{iRtUsage}, - }) - iRtUsageSIdx = utils.SumBig(iRtUsageSIdx, iRtUsage) - - } - usageStart := intervalStart - intervalStart = rtUsageEIdx // continue for the next interval - if len(rIcmts) == 0 { // no match found - continue - } - rtIvls = append(rtIvls, &utils.RateSInterval{ - IntervalStart: &utils.Decimal{usageStart}, - Increments: rIcmts, - CompressFactor: 1, - }) - if iRtUsageSIdx.Cmp(totalUsage) >= 0 { // charged enough for the usage - break - } - - } - return -} diff --git a/rates/librates_test.go b/rates/librates_test.go deleted file mode 100644 index 70453bd10..000000000 --- a/rates/librates_test.go +++ /dev/null @@ -1,5064 +0,0 @@ -/* -Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package rates - -import ( - "reflect" - "testing" - "time" - - "github.com/cgrates/cgrates/utils" -) - -func TestOrderRatesOnIntervals11(t *testing.T) { - rt0 := &utils.Rate{ - ID: "RATE0", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt0.Compile() - rtChristmas := &utils.Rate{ - ID: "RT_CHRISTMAS", - ActivationTimes: "* * 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtChristmas.Compile() - allRts := []*utils.Rate{rt0, rtChristmas} - expOrdered := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - } - wghts := []float64{10, 50} - sTime := time.Date(2020, time.June, 28, 18, 56, 05, 0, time.UTC) - usage := utils.NewDecimal(int64(2*time.Minute), 0) - if ordRts, err := orderRatesOnIntervals( - allRts, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expOrdered, ordRts) { - t.Errorf("expecting: %s\n, received: %s", utils.ToJSON(expOrdered), utils.ToJSON(ordRts)) - } - - expOrdered = []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - { - utils.NewDecimal(int64(55*time.Second), 0).Big, - rtChristmas, - }, - } - sTime = time.Date(2020, time.December, 23, 23, 59, 05, 0, time.UTC) - usage = utils.NewDecimal(int64(2*time.Minute), 0) - if ordRts, err := orderRatesOnIntervals( - allRts, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expOrdered, ordRts) { - t.Errorf("expecting: %s\n, received: %s", - utils.ToJSON(expOrdered), utils.ToJSON(ordRts)) - } - - expOrdered = []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - { - utils.NewDecimal(int64(55*time.Second), 0).Big, - rtChristmas, - }, - { - utils.NewDecimal(int64(86455*time.Second), 0).Big, - rt0, - }, - } - sTime = time.Date(2020, time.December, 23, 23, 59, 05, 0, time.UTC) - usage = utils.NewDecimal(int64(25*time.Hour), 0) - if ordRts, err := orderRatesOnIntervals( - allRts, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expOrdered, ordRts) { - t.Errorf("expecting: %s\n, received: %s", - utils.ToJSON(expOrdered), utils.ToJSON(ordRts)) - } - - rts := []*utils.Rate{rtChristmas} - expOrdered = nil - sTime = time.Date(2020, time.December, 25, 23, 59, 05, 0, time.UTC) - usage = utils.NewDecimal(int64(2*time.Minute), 0) - if ordRts, err := orderRatesOnIntervals( - rts, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expOrdered, ordRts) { - t.Errorf("expecting: %s\n, received: %s", - utils.ToJSON(expOrdered), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsChristmasDay(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh1 := &utils.Rate{ - ID: "CHRISTMAS1", - ActivationTimes: "* 0-6 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh2 := &utils.Rate{ - ID: "CHRISTMAS2", - ActivationTimes: "* 7-12 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh3 := &utils.Rate{ - ID: "CHRISTMAS3", - ActivationTimes: "* 13-19 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh4 := &utils.Rate{ - ID: "CHRISTMAS4", - ActivationTimes: "* 20-23 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20, 20, 20, 20} - allRates := []*utils.Rate{rt1, rtCh1, rtCh2, rtCh3, rtCh4} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 12, 23, 22, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(31*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(2*time.Hour), 0).Big, - rtCh1, - }, - { - utils.NewDecimal(int64(9*time.Hour), 0).Big, - rtCh2, - }, - { - utils.NewDecimal(int64(15*time.Hour), 0).Big, - rtCh3, - }, - { - utils.NewDecimal(int64(22*time.Hour), 0).Big, - rtCh4, - }, - { - utils.NewDecimal(int64(26*time.Hour), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsDoubleRates1(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh1 := &utils.Rate{ - ID: "CHRISTMAS1", - ActivationTimes: "* * 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh2 := &utils.Rate{ - ID: "CHRISTMAS2", - ActivationTimes: "* 18-23 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20, 30} - allRates := []*utils.Rate{rt1, rtCh1, rtCh2} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 12, 23, 21, 28, 12, 0, time.UTC) - usage := utils.NewDecimal(int64(31*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(2*time.Hour+31*time.Minute+48*time.Second), 0).Big, - rtCh1, - }, - { - utils.NewDecimal(int64(20*time.Hour+31*time.Minute+48*time.Second), 0).Big, - rtCh2, - }, - { - utils.NewDecimal(int64(26*time.Hour+31*time.Minute+48*time.Second), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsEveryTwentyFiveMins(t *testing.T) { - rtTwentyFiveMins := &utils.Rate{ - ID: "TWENTYFIVE_MINS", - ActivationTimes: "*/25 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt1 := &utils.Rate{ - ID: "DAY_RATE", - ActivationTimes: "* * * * 3", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRates := []*utils.Rate{rt1, rtTwentyFiveMins} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 10, 28, 20, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtTwentyFiveMins, - }, - { - utils.NewDecimal(int64(time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(25*time.Minute), 0).Big, - rtTwentyFiveMins, - }, - { - utils.NewDecimal(int64(26*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(50*time.Minute), 0).Big, - rtTwentyFiveMins, - }, - { - utils.NewDecimal(int64(51*time.Minute), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsOneMinutePause(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - ActivationTimes: "26 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtFirstInterval := &utils.Rate{ - ID: "FIRST_INTERVAL", - ActivationTimes: "0-25 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtSecondINterval := &utils.Rate{ - ID: "SECOND_INTERVAL", - ActivationTimes: "27-59 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20, 20} - allRates := []*utils.Rate{rt1, rtFirstInterval, rtSecondINterval} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 10, 28, 20, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtFirstInterval, - }, - { - utils.NewDecimal(int64(26*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(27*time.Minute), 0).Big, - rtSecondINterval, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsNewYear(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt1NewYear := &utils.Rate{ - ID: "NEW_YEAR1", - ActivationTimes: "* 20-23 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt1NewYear2 := &utils.Rate{ - ID: "NEW_YEAR2", - ActivationTimes: "0-30 22 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20, 30} - allRates := []*utils.Rate{rt1, rt1NewYear, rt1NewYear2} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 12, 30, 23, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(26*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1NewYear, - }, - { - utils.NewDecimal(int64(time.Hour), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(21*time.Hour), 0).Big, - rt1NewYear, - }, - { - utils.NewDecimal(int64(23*time.Hour), 0).Big, - rt1NewYear2, - }, - { - utils.NewDecimal(int64(23*time.Hour+31*time.Minute), 0).Big, - rt1NewYear, - }, - { - utils.NewDecimal(int64(25*time.Hour), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRateOnIntervalsEveryHourEveryDay(t *testing.T) { - rtEveryHour := &utils.Rate{ - ID: "HOUR_RATE", - ActivationTimes: "* */1 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtEveryDay := &utils.Rate{ - ID: "DAY_RATE", - ActivationTimes: "* * 22 * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRates := []*utils.Rate{rtEveryHour, rtEveryDay} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 21, 10, 24, 15, 0, time.UTC) - usage := utils.NewDecimal(int64(49*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtEveryHour, - }, - { - utils.NewDecimal(int64(13*time.Hour+35*time.Minute+45*time.Second), 0).Big, - rtEveryDay, - }, - { - utils.NewDecimal(int64(37*time.Hour+35*time.Minute+45*time.Second), 0).Big, - rtEveryHour, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsOneHourInThreeRates(t *testing.T) { - rtOneHour1 := &utils.Rate{ - ID: "HOUR_RATE_1", - ActivationTimes: "0-19 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtOneHour2 := &utils.Rate{ - ID: "HOUR_RATE_2", - ActivationTimes: "20-39 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtOneHour3 := &utils.Rate{ - ID: "HOUR_RATE_3", - ActivationTimes: "40-59 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{20, 20, 20} - allRates := []*utils.Rate{rtOneHour1, rtOneHour2, rtOneHour3} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 15, 10, 59, 59, 0, time.UTC) - usage := utils.NewDecimal(int64(2*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtOneHour3, - }, - { - utils.NewDecimal(int64(time.Second), 0).Big, - rtOneHour1, - }, - { - utils.NewDecimal(int64(20*time.Minute+time.Second), 0).Big, - rtOneHour2, - }, - { - utils.NewDecimal(int64(40*time.Minute+time.Second), 0).Big, - rtOneHour3, - }, - { - utils.NewDecimal(int64(time.Hour+time.Second), 0).Big, - rtOneHour1, - }, - { - utils.NewDecimal(int64(time.Hour+20*time.Minute+time.Second), 0).Big, - rtOneHour2, - }, - { - utils.NewDecimal(int64(time.Hour+40*time.Minute+time.Second), 0).Big, - rtOneHour3, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRateOnIntervalsEveryThreeHours(t *testing.T) { - rtEveryThreeH := &utils.Rate{ - ID: "EVERY_THREE_RATE", - ActivationTimes: "* */3 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtByDay := &utils.Rate{ - ID: "DAY_RATE", - ActivationTimes: "* 15-23 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRates := []*utils.Rate{rtEveryThreeH, rtByDay} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 15, 0, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(24*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtEveryThreeH, - }, - { - utils.NewDecimal(int64(15*time.Hour), 0).Big, - rtByDay, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRateOnIntervalsTwoRatesInOne(t *testing.T) { - rtHalfDay1 := &utils.Rate{ - ID: "HALF_RATE1", - ActivationTimes: "* 0-11 22 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtHalfDay2 := &utils.Rate{ - ID: "HALF_RATE2", - ActivationTimes: "* 12-23 22 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtHalfDay2r1 := &utils.Rate{ - ID: "HALF_RATE2.1", - ActivationTimes: "* 12-16 22 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtHalfDay2r2 := &utils.Rate{ - ID: "HALF_RATE2.2", - ActivationTimes: "* 18-23 22 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 10, 20, 20} - allRates := []*utils.Rate{rtHalfDay1, rtHalfDay2, rtHalfDay2r1, rtHalfDay2r2} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 12, 21, 23, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(25*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(int64(time.Hour), 0).Big, - rtHalfDay1, - }, - { - utils.NewDecimal(int64(13*time.Hour), 0).Big, - rtHalfDay2r1, - }, - { - utils.NewDecimal(int64(18*time.Hour), 0).Big, - rtHalfDay2, - }, - { - utils.NewDecimal(int64(19*time.Hour), 0).Big, - rtHalfDay2r2, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRateOnIntervalsEvery1Hour30Mins(t *testing.T) { - rateEvery1H := &utils.Rate{ - ID: "HOUR_RATE", - ActivationTimes: "* */1 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rateEvery30Mins := &utils.Rate{ - ID: "MINUTES_RATE", - ActivationTimes: "*/30 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRates := []*utils.Rate{rateEvery1H, rateEvery30Mins} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 9, 20, 10, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(time.Hour+time.Second), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rateEvery30Mins, - }, - { - utils.NewDecimal(int64(time.Minute), 0).Big, - rateEvery1H, - }, - { - utils.NewDecimal(int64(30*time.Minute), 0).Big, - rateEvery30Mins, - }, - { - utils.NewDecimal(int64(30*time.Minute+time.Minute), 0).Big, - rateEvery1H, - }, - { - utils.NewDecimal(int64(time.Hour), 0).Big, - rateEvery30Mins, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsOnePrinciapalRateCase1(t *testing.T) { - rtPrincipal := &utils.Rate{ - ID: "PRINCIPAL_RATE", - ActivationTimes: "* 10-22 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt1 := &utils.Rate{ - ID: "RT1", - ActivationTimes: "* 10-18 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt2 := &utils.Rate{ - ID: "RT2", - ActivationTimes: "* 10-16 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt3 := &utils.Rate{ - ID: "RT3", - ActivationTimes: "* 10-14 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 40, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20, 30, 40} - allRates := []*utils.Rate{rtPrincipal, rt1, rt2, rt3} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 21, 10, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(13*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt3, - }, - { - utils.NewDecimal(int64(5*time.Hour), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(7*time.Hour), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(9*time.Hour), 0).Big, - rtPrincipal, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsOnePrinciapalRateCase2(t *testing.T) { - rtPrincipal := &utils.Rate{ - ID: "PRINCIPAL_RATE", - ActivationTimes: "* 10-22 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt1 := &utils.Rate{ - ID: "RT1", - ActivationTimes: "* 18-22 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 40, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt2 := &utils.Rate{ - ID: "RT2", - ActivationTimes: "* 16-22 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rt3 := &utils.Rate{ - ID: "RT3", - ActivationTimes: "* 14-22 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wght := []float64{10, 40, 30, 20} - allRates := []*utils.Rate{rtPrincipal, rt1, rt2, rt3} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 21, 10, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(13*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtPrincipal, - }, - { - utils.NewDecimal(int64(4*time.Hour), 0).Big, - rt3, - }, - { - utils.NewDecimal(int64(6*time.Hour), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(8*time.Hour), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wght, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsEvenOddMinutes(t *testing.T) { - rtOddMInutes := &utils.Rate{ - ID: "ODD_RATE", - ActivationTimes: "*/1 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtEvenMinutes := &utils.Rate{ - ID: "EVEN_RATE", - ActivationTimes: "*/2 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRates := []*utils.Rate{rtOddMInutes, rtEvenMinutes} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 12, 23, 22, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(5*time.Minute+time.Second), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtEvenMinutes, - }, - { - utils.NewDecimal(int64(time.Minute), 0).Big, - rtOddMInutes, - }, - { - utils.NewDecimal(int64(2*time.Minute), 0).Big, - rtEvenMinutes, - }, - { - utils.NewDecimal(int64(3*time.Minute), 0).Big, - rtOddMInutes, - }, - { - utils.NewDecimal(int64(4*time.Minute), 0).Big, - rtEvenMinutes, - }, - { - utils.NewDecimal(int64(5*time.Minute), 0).Big, - rtOddMInutes, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsDoubleRates2(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh1 := &utils.Rate{ - ID: "CHRISTMAS1", - ActivationTimes: "* * 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh2 := &utils.Rate{ - ID: "CHRISTMAS2", - ActivationTimes: "* 10-12 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtCh3 := &utils.Rate{ - ID: "CHRISTMAS3", - ActivationTimes: "* 20-22 24 12 *", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20, 30, 30} - allRates := []*utils.Rate{rt1, rtCh1, rtCh2, rtCh3} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 12, 23, 22, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(36*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(2*time.Hour), 0).Big, - rtCh1, - }, - { - utils.NewDecimal(int64(12*time.Hour), 0).Big, - rtCh2, - }, - { - utils.NewDecimal(int64(15*time.Hour), 0).Big, - rtCh1, - }, - { - utils.NewDecimal(int64(22*time.Hour), 0).Big, - rtCh3, - }, - { - utils.NewDecimal(int64(25*time.Hour), 0).Big, - rtCh1, - }, - { - utils.NewDecimal(int64(26*time.Hour), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderOnRatesIntervalsEveryTwoHours(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtEvTwoHours := &utils.Rate{ - ID: "EVERY_TWO_HOURS", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - ActivationTimes: "* */2 * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRates := []*utils.Rate{rt1, rtEvTwoHours} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 21, 12, 10, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(4*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtEvTwoHours, - }, - { - utils.NewDecimal(int64(50*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Hour+50*time.Minute), 0).Big, - rtEvTwoHours, - }, - { - utils.NewDecimal(int64(2*time.Hour+50*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(3*time.Hour+50*time.Minute), 0).Big, - rtEvTwoHours, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsEveryTwoDays(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtEveryTwoDays := &utils.Rate{ - ID: "RATE_EVERY_DAY", - ActivationTimes: "* * */2 * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRates := []*utils.Rate{rt1, rtEveryTwoDays} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 21, 23, 59, 59, 0, time.UTC) - usage := utils.NewDecimal(int64(96*time.Hour+2*time.Second), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rtEveryTwoDays, - }, - { - utils.NewDecimal(int64(time.Second), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(24*time.Hour+time.Second), 0).Big, - rtEveryTwoDays, - }, - { - utils.NewDecimal(int64(48*time.Hour+time.Second), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(72*time.Hour+time.Second), 0).Big, - rtEveryTwoDays, - }, - { - utils.NewDecimal(int64(96*time.Hour+time.Second), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsSpecialHour(t *testing.T) { - rtRestricted := &utils.Rate{ - ID: "RESTRICTED", - ActivationTimes: "* 10-22 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtWayRestricted := &utils.Rate{ - ID: "WAY_RESTRICTED", - ActivationTimes: "* 12-14 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtSpecialHour := &utils.Rate{ - ID: "SPECIAL_HOUR", - ActivationTimes: "* 13 * * *", - Weights: utils.DynamicWeights{ - { - Weight: 40, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{20, 30, 40} - allRts := []*utils.Rate{rtRestricted, rtWayRestricted, rtSpecialHour} - for _, idx := range allRts { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 21, 9, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(11*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(int64(time.Hour), 0).Big, - rtRestricted, - }, - { - utils.NewDecimal(int64(3*time.Hour), 0).Big, - rtWayRestricted, - }, - { - utils.NewDecimal(int64(4*time.Hour), 0).Big, - rtSpecialHour, - }, - { - utils.NewDecimal(int64(5*time.Hour), 0).Big, - rtWayRestricted, - }, - { - utils.NewDecimal(int64(6*time.Hour), 0).Big, - rtRestricted, - }, - } - if ordRts, err := orderRatesOnIntervals(allRts, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRateIntervalsRateEveryTenMinutes(t *testing.T) { - rt1 := &utils.Rate{ - ID: "DAY_RATE", - ActivationTimes: "* * 21 7 *", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtEveryTenMin := &utils.Rate{ - ID: "EVERY_TEN_MIN", - ActivationTimes: "*/20 * * * *", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20} - allRts := []*utils.Rate{rt1, rtEveryTenMin} - for _, idx := range allRts { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 21, 10, 05, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(40*time.Minute), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(15*time.Minute), 0).Big, - rtEveryTenMin, - }, - { - utils.NewDecimal(int64(16*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(35*time.Minute), 0).Big, - rtEveryTenMin, - }, - { - utils.NewDecimal(int64(36*time.Minute), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRts, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalsDayOfTheWeek(t *testing.T) { - rt1 := &utils.Rate{ - ID: "ALWAYS_RATE", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtDay := &utils.Rate{ - ID: "DAY_RATE", - ActivationTimes: "* * 21 7 2", - Weights: utils.DynamicWeights{ - { - Weight: 20, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtDay1 := &utils.Rate{ - ID: "DAY_RATE1", - ActivationTimes: "* 15 21 7 2", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - rtDay2 := &utils.Rate{ - ID: "DAY_RATE2", - ActivationTimes: "* 18 21 7 2", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{10, 20, 30, 30} - allRates := []*utils.Rate{rt1, rtDay, rtDay1, rtDay2} - for _, idx := range allRates { - if err := idx.Compile(); err != nil { - t.Error(err) - } - } - sTime := time.Date(2020, 7, 20, 23, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(30*time.Hour), 0) - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Hour), 0).Big, - rtDay, - }, - { - utils.NewDecimal(int64(16*time.Hour), 0).Big, - rtDay1, - }, - { - utils.NewDecimal(int64(17*time.Hour), 0).Big, - rtDay, - }, - { - utils.NewDecimal(int64(19*time.Hour), 0).Big, - rtDay2, - }, - { - utils.NewDecimal(int64(20*time.Hour), 0).Big, - rtDay, - }, - { - utils.NewDecimal(int64(25*time.Hour), 0).Big, - rt1, - }, - } - if ordRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestNewRatesWithWinner(t *testing.T) { - rt := &rateWithTimes{ - uId: "randomID", - } - expected := &ratesWithWinner{ - rts: map[string]*rateWithTimes{ - "randomID": rt, - }, - wnr: rt, - } - if !reflect.DeepEqual(expected, newRatesWithWinner(rt)) { - t.Errorf("Expected %+v, received %+v", expected, newRatesWithWinner(rt)) - } -} - -func TestOrderRatesOnIntervalCaseMaxIterations(t *testing.T) { - rt1 := &utils.Rate{ - ID: "RT_1", - ActivationTimes: "1 * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - wghts := []float64{0} - err := rt1.Compile() - if err != nil { - t.Error(err) - } - aRts := []*utils.Rate{rt1} - sTime := time.Date(2020, 01, 02, 0, 1, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(96*time.Hour), 0) - expectedErr := "maximum iterations reached" - if _, err := orderRatesOnIntervals(aRts, wghts, sTime, usage.Big, false, 1); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } -} - -func TestOrderRatesOnIntervalIsDirectionFalse(t *testing.T) { - rt1 := &utils.Rate{ - ID: "RT_1", - ActivationTimes: "* * 27 02 *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - err := rt1.Compile() - if err != nil { - t.Error(err) - } - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - } - err = expected[0].Rate.Compile() - if err != nil { - t.Error(err) - } - wghts := []float64{0} - aRts := []*utils.Rate{rt1} - sTime := time.Date(0001, 02, 27, 0, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(48*time.Hour), 0) - if ordRts, err := orderRatesOnIntervals(aRts, wghts, sTime, usage.Big, false, 5); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalWinnNill(t *testing.T) { - rt1 := &utils.Rate{ - ID: "RT_1", - ActivationTimes: "* * 1 * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - }, - } - err := rt1.Compile() - if err != nil { - t.Error(err) - } - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - } - err = expected[0].Rate.Compile() - if err != nil { - t.Error(err) - } - wghts := []float64{0} - aRts := []*utils.Rate{rt1} - sTime := time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(96*time.Hour), 0) - if ordRts, err := orderRatesOnIntervals(aRts, wghts, sTime, usage.Big, true, 4); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestOrderRatesOnIntervalIntervalStartHigherThanEndIdx(t *testing.T) { - rt1 := &utils.Rate{ - ID: "RT_1", - ActivationTimes: "* * 1 * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(48*time.Hour), 0), - }, - }, - } - err := rt1.Compile() - if err != nil { - t.Error(err) - } - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - } - err = expected[0].Rate.Compile() - if err != nil { - t.Error(err) - } - wghts := []float64{0} - aRts := []*utils.Rate{rt1} - sTime := time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(48*time.Hour), 0) - if _, err := orderRatesOnIntervals(aRts, wghts, sTime, usage.Big, false, 4); err != nil { - t.Error(err) - } -} - -func TestOrderRatesOnIntervalStartLowerThanEndIdx(t *testing.T) { - rt1 := &utils.Rate{ - ID: "RT_1", - ActivationTimes: "* * 1 * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(23*time.Hour), 0), - }, - { - IntervalStart: utils.NewDecimal(int64(-time.Hour), 0), - }, - }, - } - err := rt1.Compile() - if err != nil { - t.Error(err) - } - expected := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - } - err = expected[0].Rate.Compile() - if err != nil { - t.Error(err) - } - aRts := []*utils.Rate{rt1} - wghts := []float64{0} - sTime := time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(48*time.Hour), 0) - if ordRts, err := orderRatesOnIntervals(aRts, wghts, sTime, usage.Big, false, 4); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(ordRts, expected) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(ordRts)) - } -} - -func TestComputeRateSIntervals(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rt0 := &utils.Rate{ - ID: "RATE0", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(10, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(60*time.Second), 0), - RecurrentFee: utils.NewDecimal(5, 3), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt0.ID: rt0, - rt1.ID: rt1, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - rts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - { - utils.NewDecimal(int64(90*time.Second), 0).Big, - rt1, - }, - } - - eRtIvls := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Usage: utils.NewDecimal(int64(time.Minute), 0), - Rate: rt0, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Usage: utils.NewDecimal(int64(30*time.Second), 0), - Rate: rt0, - IntervalRateIndex: 1, - CompressFactor: 30, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(90*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(90*time.Second), 0), - Usage: utils.NewDecimal(int64(30*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 30, - }, - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute), 0), - Usage: utils.NewDecimal(int64(10*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 10, - }, - }, - CompressFactor: 1, - }, - } - if rtIvls, err := computeRateSIntervals(rts, - utils.NewDecimal(0, 0).Big, utils.NewDecimal(int64(130*time.Second), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eRtIvls, rtIvls) { - t.Errorf("expecting: %+v \n,received: %+v", utils.ToJSON(eRtIvls), utils.ToJSON(rtIvls)) - } - - rts = []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - { - utils.NewDecimal(int64(90*time.Second), 0).Big, - rt1, - }, - } - - eRtIvls = []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Usage: utils.NewDecimal(int64(30*time.Second), 0), - Rate: rt0, - IntervalRateIndex: 1, - CompressFactor: 30, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(90*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(90*time.Second), 0), - Usage: utils.NewDecimal(int64(30*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 30, - }, - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute), 0), - Usage: utils.NewDecimal(int64(10*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 10, - }, - }, - CompressFactor: 1, - }, - } - if rtIvls, err := computeRateSIntervals(rts, - utils.NewDecimal(int64(time.Minute), 0).Big, utils.NewDecimal(int64(70*time.Second), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eRtIvls, rtIvls) { - t.Errorf("expecting: %+v, received: %+v", utils.ToIJSON(eRtIvls), utils.ToIJSON(rtIvls)) - } -} - -func TestComputeRateSIntervals1(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - rt0 := &utils.Rate{ - ID: "RATE0", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tsecDecimal, - Increment: tsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Second), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt0.ID: rt0, - rt1.ID: rt1, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - { - utils.NewDecimal(int64(time.Minute+10*time.Second), 0).Big, - rt1, - }, - } - - eRtIvls := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(int64(30*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(30*time.Second), 0), - Usage: utils.NewDecimal(int64(40*time.Second), 0), - Rate: rt0, - IntervalRateIndex: 1, - CompressFactor: 40, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute+10*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute+10*time.Second), 0), - Usage: utils.NewDecimal(int64(50*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 50, - }, - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute), 0), - Usage: utils.NewDecimal(int64(90*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 90, - }, - }, - CompressFactor: 1, - }, - } - if rtIvls, err := computeRateSIntervals(ordRts, utils.NewDecimal(int64(30*time.Second), 0).Big, - utils.NewDecimal(int64(3*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rtIvls, eRtIvls) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eRtIvls), utils.ToJSON(rtIvls)) - } -} - -func TestComputeRateSIntervalsWIthFixedFee(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - rt0 := &utils.Rate{ - ID: "RATE0", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(123, 3), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tsecDecimal, - Increment: tsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Second), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - FixedFee: utils.NewDecimal(567, 3), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt0.ID: rt0, - rt1.ID: rt1, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - { - utils.NewDecimal(int64(time.Minute+10*time.Second), 0).Big, - rt1, - }, - } - - eRtIvls := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt0, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: utils.NewDecimal(-1, 0), - }, - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt0, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(30*time.Second), 0), - Rate: rt0, - IntervalRateIndex: 1, - CompressFactor: 40, - Usage: utils.NewDecimal(int64(40*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute+10*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute+10*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: utils.NewDecimal(-1, 0), - }, - { - IncrementStart: utils.NewDecimal(int64(time.Minute+10*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 50, - Usage: utils.NewDecimal(int64(50*time.Second), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(60*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - } - if rtIvls, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(3*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rtIvls, eRtIvls) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eRtIvls), utils.ToJSON(rtIvls)) - } -} - -func TestComputeRateSIntervals2(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rt0 := &utils.Rate{ - ID: "RATE0", - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(1, 0), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(50*time.Minute), 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - } - rt0.Compile() - - rt1 := &utils.Rate{ - ID: "RATE1", - ActivationTimes: "45-49 * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(45*time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - } - rt1.Compile() - wghts := []float64{0, 0} - allRates := []*utils.Rate{rt0, rt1} - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt0, - }, - { - utils.NewDecimal(int64(45*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(50*time.Minute), 0).Big, - rt0, - }, - } - - eRtIvls := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt0, - IntervalRateIndex: 0, - CompressFactor: 45, - Usage: utils.NewDecimal(int64(45*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(45*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(45*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 5, - Usage: utils.NewDecimal(int64(5*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(50*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(50*time.Minute), 0), - Rate: rt0, - IntervalRateIndex: 1, - CompressFactor: 10, - Usage: utils.NewDecimal(int64(10*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - sTime := time.Date(2020, 7, 21, 0, 0, 0, 0, time.UTC) - usage := utils.NewDecimal(int64(time.Hour), 0) - if rcvOrdRts, err := orderRatesOnIntervals(allRates, wghts, sTime, usage.Big, true, 10); err != nil { - t.Error(eRtIvls) - } else if !reflect.DeepEqual(ordRts, rcvOrdRts) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(ordRts), utils.ToJSON(rcvOrdRts)) - } else if rcveRtIvls, err := computeRateSIntervals(rcvOrdRts, utils.NewDecimal(0, 0).Big, usage.Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcveRtIvls, eRtIvls) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(eRtIvls), utils.ToJSON(rcveRtIvls)) - } -} - -func TestComputeRateSIntervalsEvery30Seconds(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - RecurrentFee: utils.NewDecimal(3, 1), - Unit: tsecDecimal, - Increment: secDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(30*time.Second), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute+30*time.Second), 0), - RecurrentFee: utils.NewDecimal(25, 2), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0), - RecurrentFee: utils.NewDecimal(35, 2), - Unit: tsecDecimal, - Increment: secDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(30*time.Second), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Minute+30*time.Second), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(2*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0).Big, - rt2, - }, - } - - expOrdRates := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(30*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute+30*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute+30*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 2, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 2, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - } - if rcvOrdRates, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(3*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRates, expOrdRates) { - t.Errorf("Expected %+v,\nreceived %+v", utils.ToJSON(expOrdRates), utils.ToJSON(rcvOrdRates)) - } -} - -func TestComputeRateSIntervalsStartHigherThanUsage(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tsecDecimal, - Increment: tsecDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tsecDecimal, - Increment: tsecDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - } - - expected := "intervalStart for rate: higher than usage: 0" - if _, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(3*time.Minute), 0).Big); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, \nreceived %+q", expected, err) - } -} - -func TestComputeRateSIntervalsZeroIncrement(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - zeroDecimal, err := utils.NewDecimalFromUsage("0s") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tsecDecimal, - Increment: zeroDecimal, - }, - }, - } - rt1.Compile() - - ordRts := []*orderedRate{ - { - utils.NewDecimal(int64(0*time.Second), 0).Big, - rt1, - }, - } - - expected := "zero increment to be charged within rate: <>" - if _, err := computeRateSIntervals(ordRts, utils.NewDecimal(int64(33*time.Second), 0).Big, - utils.NewDecimal(int64(3*time.Minute), 0).Big); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, \nreceived %+q", expected, err) - } -} - -func TestComputeRateSIntervalsCeilingCmpFactor(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - ssecDecimal, err := utils.NewDecimalFromUsage("7s") - if err != nil { - t.Error(err) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Second), 0), - RecurrentFee: utils.NewDecimal(25, 3), - Unit: minDecimal, - Increment: ssecDecimal, - }, - }, - } - rt1.Compile() - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - } - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - CompressFactor: 30, - }, - { - IncrementStart: utils.NewDecimal(int64(30*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(40*time.Second), 0), - CompressFactor: 6, - }, - }, - CompressFactor: 1, - }, - } - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(time.Minute+10*time.Second), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsSwitchingRates(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - ssecDecimal, err := utils.NewDecimalFromUsage("7s") - if err != nil { - t.Error(err) - } - fsecDecimal, err := utils.NewDecimalFromUsage("5s") - if err != nil { - t.Error(err) - } - fssecDecimal, err := utils.NewDecimalFromUsage("25s") - if err != nil { - t.Error(err) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(25*time.Second), 0), - RecurrentFee: utils.NewDecimal(25, 2), - Unit: minDecimal, - Increment: ssecDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(45*time.Second), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(55*time.Second), 0), - RecurrentFee: utils.NewDecimal(3, 1), - Unit: tsecDecimal, - Increment: fsecDecimal, - }, - }, - } - - rt3 := &utils.Rate{ - ID: "RATE3", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(30*time.Second), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: fssecDecimal, - Increment: fsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(5, 3), - Unit: tsecDecimal, - Increment: fsecDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - rt3.ID: rt3, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(35*time.Second), 0).Big, - rt3, - }, - { - utils.NewDecimal(int64(46*time.Second), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(time.Minute), 0).Big, - rt3, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(25*time.Second), 0), - CompressFactor: 25, - }, - { - IncrementStart: utils.NewDecimal(int64(25*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(10*time.Second), 0), - CompressFactor: 2, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(35*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(35*time.Second), 0), - Rate: rt3, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(11*time.Second), 0), - CompressFactor: 3, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(46*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(46*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(9*time.Second), 0), - CompressFactor: 9, - }, - { - IncrementStart: utils.NewDecimal(int64(55*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(5*time.Second), 0), - CompressFactor: 1, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Rate: rt3, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(10*time.Second), 0), - CompressFactor: 2, - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(time.Minute+10*time.Second), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRatesIntervalsAllInOne(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - ssecDecimal, err := utils.NewDecimalFromUsage("7s") - if err != nil { - t.Error(err) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(3, 1), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(3*time.Minute), 0), - RecurrentFee: utils.NewDecimal(3, 1), - Unit: minDecimal, - Increment: ssecDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(time.Minute+30*time.Second), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tsecDecimal, - Increment: ssecDecimal, - }, - }, - } - - rt3 := &utils.Rate{ - ID: "RATE3", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tsecDecimal, - Increment: tsecDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - rt3.ID: rt3, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRates := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Minute+30*time.Second), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(2*time.Minute), 0).Big, - rt3, - }, - { - utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(3*time.Minute), 0).Big, - rt1, - }, - } - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - CompressFactor: 30, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute+30*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Minute+30*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - CompressFactor: 30, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute), 0), - Rate: rt3, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - CompressFactor: 1, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(2*time.Minute+30*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(30*time.Second), 0), - CompressFactor: 5, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(3*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(3*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(4*time.Minute), 0), - CompressFactor: 35, - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRates, utils.NewDecimal(int64(time.Minute), 0).Big, - utils.NewDecimal(int64(6*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestOrderRatesIntervalsFullDay(t *testing.T) { - hourDecimal, err := utils.NewDecimalFromUsage("1h") - if err != nil { - t.Error(err) - } - tminDecimal, err := utils.NewDecimalFromUsage("3m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: hourDecimal, - Increment: tminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(4*time.Hour), 0), - RecurrentFee: utils.NewDecimal(35, 2), - Unit: hourDecimal, - Increment: tminDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(13*time.Hour), 0), - RecurrentFee: utils.NewDecimal(4, 1), - Unit: hourDecimal, - Increment: tminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(16*time.Hour), 0), - RecurrentFee: utils.NewDecimal(35, 2), - Unit: hourDecimal, - Increment: tminDecimal, - }, - }, - } - thourDecimal, err := utils.NewDecimalFromUsage("30h") - if err != nil { - t.Error(err) - } - dminDecimal, err := utils.NewDecimalFromUsage("2m") - if err != nil { - t.Error(err) - } - fminDecimal, err := utils.NewDecimalFromUsage("5m") - if err != nil { - t.Error(err) - } - rtGH := &utils.Rate{ - ID: "RATE_GOLDEN_HOUR", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(12*time.Hour), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: thourDecimal, - Increment: dminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(12*time.Hour+30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: hourDecimal, - Increment: fminDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFIOLE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - rtGH.ID: rtGH, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(6*time.Hour), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(12*time.Hour), 0).Big, - rtGH, - }, - { - utils.NewDecimal(int64(13*time.Hour), 0).Big, - rt2, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(4*time.Hour), 0), - CompressFactor: 80, - }, - { - IncrementStart: utils.NewDecimal(int64(4*time.Hour), 0), - Rate: rt1, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(2*time.Hour), 0), - CompressFactor: 40, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(6*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(6*time.Hour), 0), - Rate: rt1, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(6*time.Hour), 0), - CompressFactor: 120, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(12*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(12*time.Hour), 0), - Rate: rtGH, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(30*time.Minute), 0), - CompressFactor: 15, - }, - { - IncrementStart: utils.NewDecimal(int64(12*time.Hour+30*time.Minute), 0), - Rate: rtGH, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(30*time.Minute), 0), - CompressFactor: 6, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(13*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(13*time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 0, - Usage: utils.NewDecimal(int64(3*time.Hour), 0), - CompressFactor: 60, - }, - { - IncrementStart: utils.NewDecimal(int64(16*time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 1, - Usage: utils.NewDecimal(int64(9*time.Hour), 0), - CompressFactor: 180, - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(25*time.Hour), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRatesIntervalsEveryTwoSeconds(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("10s") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - twsecDecimal, err := utils.NewDecimalFromUsage("2s") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: tsecDecimal, - Increment: twsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(4*time.Second), 0), - RecurrentFee: utils.NewDecimal(48, 2), - Unit: tsecDecimal, - Increment: twsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(8*time.Second), 0), - RecurrentFee: utils.NewDecimal(45, 2), - Unit: tsecDecimal, - Increment: twsecDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: twsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Second), 0), - RecurrentFee: utils.NewDecimal(48, 2), - Unit: twsecDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(6*time.Second), 0), - RecurrentFee: utils.NewDecimal(45, 2), - Unit: twsecDecimal, - Increment: secDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Second), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(2*time.Second), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(3*time.Second), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(5*time.Second), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(7*time.Second), 0).Big, - rt2, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Second), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(2*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(3*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(3*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 2, - Usage: utils.NewDecimal(int64(2*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(5*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(5*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(2*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(7*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(7*time.Second), 0), - Rate: rt2, - IntervalRateIndex: 2, - CompressFactor: 3, - Usage: utils.NewDecimal(int64(3*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(10*time.Second), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsOneHourRate(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("15m") - if err != nil { - t.Error(err) - } - fminDeminal, err := utils.NewDecimalFromUsage("5m") - if err != nil { - t.Error(err) - } - cDecimal, err := utils.NewDecimalFromUsage("1m30s") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 3), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour), 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: fminDeminal, - Increment: cDecimal, - }, - }, - } - tminDeminal, err := utils.NewDecimalFromUsage("10m") - if err != nil { - t.Error(err) - } - ominDeminal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(15*time.Minute), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tminDeminal, - Increment: ominDeminal, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(15, 2), - Unit: tminDeminal, - Increment: ominDeminal, - }, - { - IntervalStart: utils.NewDecimal(int64(45*time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tminDeminal, - Increment: ominDeminal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(20*time.Minute), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(time.Hour+time.Minute), 0).Big, - rt1, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 2, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(20*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(20*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 10, - Usage: utils.NewDecimal(int64(10*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(30*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 15, - Usage: utils.NewDecimal(int64(15*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(45*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 2, - CompressFactor: 16, - Usage: utils.NewDecimal(int64(16*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour+time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Hour+time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 6, - Usage: utils.NewDecimal(int64(9*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(time.Hour+10*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsCompressIncrements(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: tsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: tsecDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: tsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: tsecDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(25*time.Minute), 0).Big, - rt1, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 50, - Usage: utils.NewDecimal(int64(25*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(25*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(25*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 10, - Usage: utils.NewDecimal(int64(5*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(30*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(30*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(time.Hour), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsStartAfterIntervalStartDifferentRates(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - - tminDecimal, err := utils.NewDecimalFromUsage("10m") - if err != nil { - t.Error(err) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - tensecDecimal, err := utils.NewDecimalFromUsage("10s") - if err != nil { - t.Error(err) - } - - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(22, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(60*time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tminDecimal, - Increment: tensecDecimal, - }, - }, - } - twminDecimal, err := utils.NewDecimalFromUsage("20m") - if err != nil { - t.Error(err) - } - twsecDecimal, err := utils.NewDecimalFromUsage("20s") - if err != nil { - t.Error(err) - } - - rt3 := &utils.Rate{ - ID: "RATE3", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(120*time.Minute), 0), - RecurrentFee: utils.NewDecimal(18, 2), - Unit: twminDecimal, - Increment: twsecDecimal, - }, - }, - } - trminDecimal, err := utils.NewDecimalFromUsage("30m") - if err != nil { - t.Error(err) - } - - rt4 := &utils.Rate{ - ID: "RATE4", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(180*time.Minute), 0), - RecurrentFee: utils.NewDecimal(16, 2), - Unit: trminDecimal, - Increment: tsecDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - rt3.ID: rt3, - rt4.ID: rt4, - }, - } - if err := rp.Compile(); err != nil { - t.Fatal(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(int64(20*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(80*time.Minute), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(140*time.Minute), 0).Big, - rt3, - }, - { - utils.NewDecimal(int64(200*time.Minute), 0).Big, - rt4, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(int64(20*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(20*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 3600, - Usage: utils.NewDecimal(int64(time.Hour), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(80*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(80*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 360, - Usage: utils.NewDecimal(int64(60*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(140*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(140*time.Minute), 0), - Rate: rt3, - IntervalRateIndex: 0, - CompressFactor: 180, - Usage: utils.NewDecimal(int64(60*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(200*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(200*time.Minute), 0), - Rate: rt4, - IntervalRateIndex: 0, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(30*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(int64(20*time.Minute), 0).Big, - utils.NewDecimal(int64(210*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsStartAfterIntervalStartSameRate(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("30s") - if err != nil { - t.Error(err) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - twsecDecimal, err := utils.NewDecimalFromUsage("20s") - if err != nil { - t.Error(err) - } - tssecDecimal, err := utils.NewDecimalFromUsage("10s") - if err != nil { - t.Error(err) - } - tminDecimal, err := utils.NewDecimalFromUsage("10m") - if err != nil { - t.Error(err) - } - twminDecimal, err := utils.NewDecimalFromUsage("20m") - if err != nil { - t.Error(err) - } - thminDecimal, err := utils.NewDecimalFromUsage("30m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(22, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(60*time.Minute), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: tminDecimal, - Increment: tssecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(120*time.Minute), 0), - RecurrentFee: utils.NewDecimal(18, 2), - Unit: twminDecimal, - Increment: twsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(180*time.Minute), 0), - RecurrentFee: utils.NewDecimal(16, 2), - Unit: thminDecimal, - Increment: tsecDecimal, - }, - }, - } - rt1.Compile() - - ordRts := []*orderedRate{ - { - utils.NewDecimal(int64(20*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(80*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(140*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(200*time.Minute), 0).Big, - rt1, - }, - } - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(int64(20*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(20*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 2400, - Usage: utils.NewDecimal(int64(40*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(60*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 120, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(80*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(80*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 240, - Usage: utils.NewDecimal(int64(40*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(120*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 2, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(140*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(140*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 2, - CompressFactor: 120, - Usage: utils.NewDecimal(int64(40*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(180*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 3, - CompressFactor: 40, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(200*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(200*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 3, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(30*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(int64(20*time.Minute), 0).Big, - utils.NewDecimal(int64(210*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } - - expOrdRts = []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 3600, - Usage: utils.NewDecimal(int64(60*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(60*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 120, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(80*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(80*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 240, - Usage: utils.NewDecimal(int64(40*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(120*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 2, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(140*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(140*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 2, - CompressFactor: 120, - Usage: utils.NewDecimal(int64(40*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(180*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 3, - CompressFactor: 40, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(200*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(200*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 3, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(30*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(int64(0*time.Minute), 0).Big, - utils.NewDecimal(int64(230*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsHalfDayIntervals(t *testing.T) { - twminDecimal, err := utils.NewDecimalFromUsage("30m") - if err != nil { - t.Error(err) - } - - nminDecimal, err := utils.NewDecimalFromUsage("9m") - if err != nil { - t.Error(err) - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: twminDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(24*time.Hour), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: twminDecimal, - Increment: secDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(4*time.Hour+30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(45, 2), - Unit: twminDecimal, - Increment: nminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(8*time.Hour+30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(4, 1), - Unit: twminDecimal, - Increment: nminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(16*time.Hour+30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(35, 2), - Unit: twminDecimal, - Increment: nminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(20*time.Hour+30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(3, 1), - Unit: twminDecimal, - Increment: nminDecimal, - }, - }, - } - - rt3 := &utils.Rate{ - ID: "RATE_SPECIAL", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(12*time.Hour), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: twminDecimal, - Increment: secDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - rt3.ID: rt3, - }, - } - if err := rp.Compile(); err != nil { - t.Error(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(4*time.Hour+31*time.Minute), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(12*time.Hour), 0).Big, - rt3, - }, - { - utils.NewDecimal(int64(13*time.Hour), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(24*time.Hour), 0).Big, - rt1, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 271, - Usage: utils.NewDecimal(int64(4*time.Hour+31*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(4*time.Hour+31*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(4*time.Hour+31*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 27, - Usage: utils.NewDecimal(int64(3*time.Hour+59*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(8*time.Hour+30*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 24, - Usage: utils.NewDecimal(int64(3*time.Hour+30*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(12*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(12*time.Hour), 0), - Rate: rt3, - IntervalRateIndex: 0, - CompressFactor: 3600, - Usage: utils.NewDecimal(int64(time.Hour), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(13*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(13*time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 24, - Usage: utils.NewDecimal(int64(3*time.Hour+30*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(16*time.Hour+30*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 2, - CompressFactor: 27, - Usage: utils.NewDecimal(int64(4*time.Hour), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(20*time.Hour+30*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 3, - CompressFactor: 24, - Usage: utils.NewDecimal(int64(3*time.Hour+30*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(24*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(24*time.Hour), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 3600, - Usage: utils.NewDecimal(int64(time.Hour), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(25*time.Hour), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsConsecutiveRates(t *testing.T) { - fminDecimal, err := utils.NewDecimalFromUsage("15m") - if err != nil { - t.Error(err) - } - eminDecimal, err := utils.NewDecimalFromUsage("11m") - if err != nil { - t.Error(err) - } - nminDecimal, err := utils.NewDecimalFromUsage("9m") - if err != nil { - t.Error(err) - } - sminDecimal, err := utils.NewDecimalFromUsage("7m") - if err != nil { - t.Error(err) - } - fvminDecimal, err := utils.NewDecimalFromUsage("5m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - }, - { - IntervalStart: utils.NewDecimal(int64(15*time.Minute), 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: fminDecimal, - Increment: eminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(30*time.Minute), 0), - RecurrentFee: utils.NewDecimal(4, 1), - Unit: fminDecimal, - Increment: nminDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(45*time.Minute), 0), - RecurrentFee: utils.NewDecimal(3, 1), - Unit: fminDecimal, - Increment: sminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: fminDecimal, - Increment: fvminDecimal, - }, - }, - } - - rp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PROFILE", - Rates: map[string]*utils.Rate{ - rt1.ID: rt1, - rt2.ID: rt2, - }, - } - if err := rp.Compile(); err != nil { - t.Error(err) - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(45*time.Minute), 0).Big, - rt2, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(int64(15*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(15*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 2, - Usage: utils.NewDecimal(int64(15*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(30*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 2, - CompressFactor: 2, - Usage: utils.NewDecimal(int64(15*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(45*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(45*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 3, - Usage: utils.NewDecimal(int64(15*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 6, - Usage: utils.NewDecimal(int64(30*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(int64(15*time.Minute), 0).Big, - utils.NewDecimal(int64(time.Hour+15*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsRatesByMinutes(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("2s") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - tminDecimal, err := utils.NewDecimalFromUsage("2m") - if err != nil { - t.Error(err) - } - sminDecimal, err := utils.NewDecimalFromUsage("6m") - if err != nil { - t.Error(err) - } - nminDecimal, err := utils.NewDecimalFromUsage("9m") - if err != nil { - t.Error(err) - } - eminDecimal, err := utils.NewDecimalFromUsage("8m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: tminDecimal, - Increment: tsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(12*time.Minute+35*time.Second), 0), - RecurrentFee: utils.NewDecimal(4, 1), - Unit: sminDecimal, - Increment: secDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour+37*time.Minute+19*time.Second), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: nminDecimal, - Increment: sminDecimal, - }, - }, - } - rt1.Compile() - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(38*time.Minute+15*time.Second), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: eminDecimal, - Increment: secDecimal, - }, - }, - } - rt2.Compile() - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(39*time.Minute), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(time.Hour+37*time.Minute+19*time.Second), 0).Big, - rt1, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 378, - Usage: utils.NewDecimal(int64(12*time.Minute+35*time.Second), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(12*time.Minute+35*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 1585, - Usage: utils.NewDecimal(int64(26*time.Minute+25*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(39*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(39*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 3499, - Usage: utils.NewDecimal(int64(58*time.Minute+19*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour+37*time.Minute+19*time.Second), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Hour+37*time.Minute+19*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 2, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(41*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(time.Hour+38*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsSwitchingRates2(t *testing.T) { - tsecDecimal, err := utils.NewDecimalFromUsage("2s") - if err != nil { - t.Error(err) - } - tminDecimal, err := utils.NewDecimalFromUsage("2m") - if err != nil { - t.Error(err) - } - ttminDecimal, err := utils.NewDecimalFromUsage("10m") - if err != nil { - t.Error(err) - } - fsecDecimal, err := utils.NewDecimalFromUsage("4s") - if err != nil { - t.Error(err) - } - fminDecimal, err := utils.NewDecimalFromUsage("4m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: tminDecimal, - Increment: tsecDecimal, - }, - }, - } - rt1.Compile() - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(20*time.Minute), 0), - RecurrentFee: utils.NewDecimal(4, 1), - Unit: ttminDecimal, - Increment: tsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(40*time.Minute), 0), - RecurrentFee: utils.NewDecimal(3, 1), - Unit: ttminDecimal, - Increment: fsecDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour), 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: ttminDecimal, - Increment: tminDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Hour), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: ttminDecimal, - Increment: fminDecimal, - }, - }, - } - rt2.Compile() - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(20*time.Minute), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(21*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(40*time.Minute), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(41*time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Hour), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(time.Hour+time.Minute), 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(2*time.Hour), 0).Big, - rt2, - }, - { - utils.NewDecimal(int64(2*time.Hour+time.Minute), 0).Big, - rt1, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 600, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(20*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(20*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(21*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(21*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 570, - Usage: utils.NewDecimal(int64(19*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(40*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(40*time.Minute), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 15, - Usage: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(41*time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(41*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 570, - Usage: utils.NewDecimal(int64(19*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 2, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour+time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Hour+time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 1770, - Usage: utils.NewDecimal(int64(59*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(2*time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 3, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(2*time.Hour+time.Minute), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(2*time.Hour+time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 30, - Usage: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(2*time.Hour+2*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsSOneWeekCall(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - hourDecimal, err := utils.NewDecimalFromUsage("1h") - if err != nil { - t.Error(err) - } - fminDecimal, err := utils.NewDecimalFromUsage("17m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: hourDecimal, - Increment: fminDecimal, - }, - }, - } - rt1.Compile() - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(168*time.Hour), 0), - RecurrentFee: utils.NewDecimal(5, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - } - rt2.Compile() - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(168*time.Hour), 0).Big, - rt2, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 593, - Usage: utils.NewDecimal(int64(168*time.Hour), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(168*time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(168*time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 0, - CompressFactor: 60, - Usage: utils.NewDecimal(int64(time.Hour), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(169*time.Hour), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} - -func TestComputeRateSIntervalsPauseBetweenRates(t *testing.T) { - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - fminDecimal, err := utils.NewDecimalFromUsage("5m") - if err != nil { - t.Error(err) - } - tminDecimal, err := utils.NewDecimalFromUsage("10m") - if err != nil { - t.Error(err) - } - rt1 := &utils.Rate{ - ID: "RATE1", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: fminDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(20*time.Minute), 0), - RecurrentFee: utils.NewDecimal(4, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - - rt2 := &utils.Rate{ - ID: "RATE2", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(int64(50*time.Minute), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: tminDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour), 0), - RecurrentFee: utils.NewDecimal(5, 3), - Unit: fminDecimal, - Increment: secDecimal, - }, - }, - } - - ordRts := []*orderedRate{ - { - utils.NewDecimal(0, 0).Big, - rt1, - }, - { - utils.NewDecimal(int64(time.Hour), 0).Big, - rt2, - }, - } - - expOrdRts := []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 20, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - { - IncrementStart: utils.NewDecimal(int64(20*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 2400, - Usage: utils.NewDecimal(int64(40*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Hour), 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(int64(time.Hour), 0), - Rate: rt2, - IntervalRateIndex: 1, - CompressFactor: 1200, - Usage: utils.NewDecimal(int64(20*time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - } - - if rcvOrdRts, err := computeRateSIntervals(ordRts, utils.NewDecimal(0, 0).Big, - utils.NewDecimal(int64(time.Hour+20*time.Minute), 0).Big); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcvOrdRts, expOrdRts) { - t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expOrdRts), utils.ToJSON(rcvOrdRts)) - } -} diff --git a/rates/rates.go b/rates/rates.go deleted file mode 100644 index 322cdf42d..000000000 --- a/rates/rates.go +++ /dev/null @@ -1,231 +0,0 @@ -/* -Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package rates - -import ( - "fmt" - "time" - - "github.com/ericlagergren/decimal" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" -) - -// NewRateS instantiates the RateS -func NewRateS(cfg *config.CGRConfig, filterS *engine.FilterS, dm *engine.DataManager) *RateS { - return &RateS{ - cfg: cfg, - filterS: filterS, - dm: dm, - } -} - -// RateS calculates costs for events -type RateS struct { - cfg *config.CGRConfig - filterS *engine.FilterS - dm *engine.DataManager -} - -// ListenAndServe keeps the service alive -func (rS *RateS) ListenAndServe(stopChan, cfgRld chan struct{}) { - utils.Logger.Info(fmt.Sprintf("<%s> starting <%s>", - utils.CoreS, utils.RateS)) - for { - select { - case <-stopChan: - return - case rld := <-cfgRld: // configuration was reloaded - cfgRld <- rld - } - } -} - -// Shutdown is called to shutdown the service -func (rS *RateS) Shutdown() (err error) { - utils.Logger.Info(fmt.Sprintf("<%s> shutdown <%s>", utils.CoreS, utils.RateS)) - return -} - -// Call implements rpcclient.ClientConnector interface for internal RPC -func (rS *RateS) Call(serviceMethod string, args interface{}, reply interface{}) error { - return utils.RPCCall(rS, serviceMethod, args, reply) -} - -// matchingRateProfileForEvent returns the matched RateProfile for the given event -func (rS *RateS) matchingRateProfileForEvent(tnt string, rPfIDs []string, args *utils.ArgsCostForEvent) (rtPfl *utils.RateProfile, err error) { - evNm := utils.MapStorage{ - utils.MetaReq: args.CGREvent.Event, - utils.MetaOpts: args.APIOpts, - } - if len(rPfIDs) == 0 { - var rPfIDMp utils.StringSet - if rPfIDMp, err = engine.MatchingItemIDsForEvent( - evNm, - rS.cfg.RateSCfg().StringIndexedFields, - rS.cfg.RateSCfg().PrefixIndexedFields, - rS.cfg.RateSCfg().SuffixIndexedFields, - rS.dm, - utils.CacheRateProfilesFilterIndexes, - tnt, - rS.cfg.RateSCfg().IndexedSelects, - rS.cfg.RateSCfg().NestedFields, - ); err != nil { - return - } - rPfIDs = rPfIDMp.AsSlice() - } - var rpWw *rpWithWeight - for _, rPfID := range rPfIDs { - var rPf *utils.RateProfile - if rPf, err = rS.dm.GetRateProfile(tnt, rPfID, - true, true, utils.NonTransactional); err != nil { - if err == utils.ErrNotFound { - err = nil - continue - } - return - } - if rPf.ActivationInterval != nil && args.CGREvent.Time != nil && - !rPf.ActivationInterval.IsActiveAtTime(*args.CGREvent.Time) { // not active - continue - } - var pass bool - if pass, err = rS.filterS.Pass(tnt, rPf.FilterIDs, evNm); err != nil { - return - } else if !pass { - continue - } - var rPfWeight float64 - if rPfWeight, err = engine.WeightFromDynamics(rPf.Weights, - rS.filterS, tnt, evNm); err != nil { - return - } - if rpWw == nil || rpWw.weight < rPfWeight { - rpWw = &rpWithWeight{rPf, rPfWeight} - } - } - if rpWw == nil { - return nil, utils.ErrNotFound - } - - return rpWw.RateProfile, nil -} - -// rateProfileCostForEvent computes the rateProfileCost for an event based on a preselected rate profile -func (rS *RateS) rateProfileCostForEvent(rtPfl *utils.RateProfile, args *utils.ArgsCostForEvent, verbosity int) (rpCost *utils.RateProfileCost, err error) { - evNm := utils.MapStorage{ - utils.MetaReq: args.CGREvent.Event, - utils.MetaOpts: args.APIOpts, - } - var rtIDs utils.StringSet - if rtIDs, err = engine.MatchingItemIDsForEvent( - evNm, - rS.cfg.RateSCfg().RateStringIndexedFields, - rS.cfg.RateSCfg().RatePrefixIndexedFields, - rS.cfg.RateSCfg().RateSuffixIndexedFields, - rS.dm, - utils.CacheRateFilterIndexes, - utils.ConcatenatedKey(args.CGREvent.Tenant, rtPfl.ID), - rS.cfg.RateSCfg().RateIndexedSelects, - rS.cfg.RateSCfg().RateNestedFields, - ); err != nil { - return - } - aRates := make([]*utils.Rate, 0, len(rtIDs)) - for rtID := range rtIDs { - rt := rtPfl.Rates[rtID] // pick the rate directly from map based on matched ID - var pass bool - if pass, err = rS.filterS.Pass(args.CGREvent.Tenant, rt.FilterIDs, evNm); err != nil { - return - } else if !pass { - continue - } - aRates = append(aRates, rt) - } - // populate weights to be used on ordering - wghts := make([]float64, len(aRates)) - for i, aRt := range aRates { - if wghts[i], err = engine.WeightFromDynamics(aRt.Weights, - rS.filterS, args.CGREvent.Tenant, evNm); err != nil { - return - } - } - var sTime time.Time - if sTime, err = args.StartTime(rS.cfg.GeneralCfg().DefaultTimezone); err != nil { - return - } - var usage *decimal.Big - if usage, err = args.Usage(); err != nil { - return - } - var ordRts []*orderedRate - if ordRts, err = orderRatesOnIntervals(aRates, wghts, sTime, usage, true, verbosity); err != nil { - return - } - rpCost = &utils.RateProfileCost{ - ID: rtPfl.ID, - } - var ok bool - if rtPfl.MinCost != nil { - if rpCost.MinCost, ok = rtPfl.MinCost.Float64(); !ok { - return nil, fmt.Errorf("<%s> cannot convert <%+v> min cost to Float64", utils.RateS, rtPfl.MinCost) - } - } - if rtPfl.MaxCost != nil { - if rpCost.MaxCost, ok = rtPfl.MaxCost.Float64(); !ok { - return nil, fmt.Errorf("<%s> cannot convert <%+v> max cost to Float64", utils.RateS, rtPfl.MaxCost) - } - } - - if rpCost.RateSIntervals, err = computeRateSIntervals(ordRts, decimal.New(0, 0), usage); err != nil { - return nil, err - } - // in case we have error it is returned in the function from above - // this came to light in coverage tests - rpCost.Cost, _ = utils.CostForIntervals(rpCost.RateSIntervals).Float64() - - return -} - -// V1CostForEvent will be called to calculate the cost for an event -func (rS *RateS) V1CostForEvent(args *utils.ArgsCostForEvent, rpCost *utils.RateProfileCost) (err error) { - rPfIDs := make([]string, len(args.RateProfileIDs)) - for i, rpID := range args.RateProfileIDs { - rPfIDs[i] = rpID - } - var rtPrl *utils.RateProfile - if rtPrl, err = rS.matchingRateProfileForEvent(args.Tenant, rPfIDs, args); err != nil { - if err != utils.ErrNotFound { - err = utils.NewErrServerError(err) - } - return - } - var rcvCost *utils.RateProfileCost - if rcvCost, err = rS.rateProfileCostForEvent(rtPrl, args, rS.cfg.RateSCfg().Verbosity); err != nil { - if err != utils.ErrNotFound { - err = utils.NewErrServerError(err) - } - return - } - *rpCost = *rcvCost - return -} diff --git a/rates/rates_test.go b/rates/rates_test.go deleted file mode 100644 index 74bad439f..000000000 --- a/rates/rates_test.go +++ /dev/null @@ -1,966 +0,0 @@ -/* -Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package rates - -import ( - "reflect" - "testing" - "time" - - "github.com/cgrates/cgrates/utils" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" -) - -func TestListenAndServe(t *testing.T) { - newRates := &RateS{} - cfgRld := make(chan struct{}, 1) - stopChan := make(chan struct{}, 1) - cfgRld <- struct{}{} - go func() { - time.Sleep(10) - stopChan <- struct{}{} - }() - newRates.ListenAndServe(stopChan, cfgRld) -} - -func TestNewRateS(t *testing.T) { - config := config.NewDefaultCGRConfig() - - data := engine.NewInternalDB(nil, nil, true) - dataManager := engine.NewDataManager(data, config.CacheCfg(), nil) - filters := engine.NewFilterS(config, nil, dataManager) - expected := &RateS{ - cfg: config, - filterS: filters, - dm: dataManager, - } - if newRateS := NewRateS(config, filters, dataManager); !reflect.DeepEqual(newRateS, expected) { - t.Errorf("Expected %+v, received %+v", expected, newRateS) - } -} - -func TestCallRates(t *testing.T) { - newRates := &RateS{} - var reply *string - expectedErr := "UNSUPPORTED_SERVICE_METHOD" - if err := newRates.Call("inexistentMethodCall", nil, reply); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } -} - -func TestMatchingRateProfileForEventActivationInterval(t *testing.T) { - dftCfg := config.NewDefaultCGRConfig() - - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, dftCfg.CacheCfg(), nil) - filterS := engine.NewFilterS(dftCfg, nil, dm) - rateS := RateS{ - cfg: dftCfg, - filterS: filterS, - dm: dm, - } - - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - Weights: utils.DynamicWeights{ - { - Weight: 10, - }, - }, - FilterIDs: []string{"*string:~*req.Account:1001|1002|1003", "*prefix:~*req.Destination:10"}, - ActivationInterval: &utils.ActivationInterval{ - ActivationTime: time.Date(2020, 7, 21, 0, 0, 0, 0, time.UTC), - ExpiryTime: time.Date(2020, 7, 21, 10, 0, 0, 0, time.UTC), - }, - } - - err := dm.SetRateProfile(rPrf, true) - if err != nil { - t.Error(err) - } - if _, err := rateS.matchingRateProfileForEvent("cgrates.org", []string{}, - &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Time: utils.TimePointer(time.Date(2020, 7, 21, 11, 0, 0, 0, time.UTC)), - Event: map[string]interface{}{ - utils.AccountField: "1001", - utils.Destination: 1002, - utils.AnswerTime: rPrf.ActivationInterval.ExpiryTime.Add(-10 * time.Second), - }, - }, - }); err != utils.ErrNotFound { - t.Error(err) - } - - err = dm.RemoveRateProfile(rPrf.Tenant, rPrf.ID, utils.NonTransactional, true) - if err != nil { - t.Error(err) - } -} - -func TestRateProfileCostForEvent(t *testing.T) { - defaultCfg := config.NewDefaultCGRConfig() - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - rateS := NewRateS(defaultCfg, filters, dm) - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_1", - FilterIDs: []string{"*string:~*req.Account:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": { - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - }, - }, - } - - //MatchItmID before setting - if _, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}}}, rateS.cfg.RateSCfg().Verbosity); err == nil || err != utils.ErrNotFound { - t.Error(err) - } - - if err := rateS.dm.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - - expectedRPCost := &utils.RateProfileCost{ - ID: "RATE_1", - Cost: 0.20, - RateSIntervals: []*utils.RateSInterval{ - { - IntervalStart: utils.NewDecimal(0, 0), - Increments: []*utils.RateSIncrement{ - { - IncrementStart: utils.NewDecimal(0, 0), - Rate: rPrf.Rates["RATE1"], - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: utils.NewDecimal(int64(time.Minute), 0), - }, - }, - CompressFactor: 1, - }, - }, - } - expectedRPCost.RateSIntervals[0].Cost() - - if rcv, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}}}, rateS.cfg.RateSCfg().Verbosity); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rcv, expectedRPCost) { - t.Errorf("Expected %+v\n, received %+v", utils.ToJSON(expectedRPCost), utils.ToJSON(rcv)) - } - - expRpCostAfterV1 := expectedRPCost - if err := rateS.V1CostForEvent(&utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}}}, expectedRPCost); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expectedRPCost, expRpCostAfterV1) { - t.Errorf("Expected %+v, received %+v", utils.ToJSON(expRpCostAfterV1), utils.ToJSON(expectedRPCost)) - } - - if err := dm.RemoveRateProfile(rPrf.Tenant, rPrf.ID, utils.NonTransactional, true); err != nil { - t.Error(err) - } -} - -func TestRateProfileCostForEventUnmatchEvent(t *testing.T) { - defaultCfg := config.NewDefaultCGRConfig() - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - rateS := NewRateS(defaultCfg, filters, dm) - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_PRF1", - FilterIDs: []string{"*string:~*req.Account:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": { - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - FilterIDs: []string{"*string:~*req.Destination:10"}, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - }, - "RATE2": { - ID: "RATE2", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - FilterIDs: []string{"*string:~*req.Destination:10"}, - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - }, - }, - } - - if err := rateS.dm.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - - expectedErr := "invalid converter terminator in rule: <~*req.Cost{*>" - rPrf.Rates["RATE2"].FilterIDs = []string{"*gt:~*req.Cost{*:10"} - if _, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001", - utils.Destination: "10", - utils.Cost: 1002, - }}}, rateS.cfg.RateSCfg().Verbosity); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, receied %+v", expectedErr, err) - } - rPrf.Rates["RATE2"].FilterIDs = []string{"*prefix:~*req.CustomValue:randomValue"} - - if _, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001", - utils.Destination: "10", - utils.Cost: 1002, - }}}, rateS.cfg.RateSCfg().Verbosity); err != nil { - t.Error(err) - } - - if err := rateS.dm.RemoveRateProfile(rPrf.Tenant, rPrf.ID, utils.NonTransactional, true); err != nil { - t.Error(err) - } -} - -func TestMatchingRateProfileEvent(t *testing.T) { - defaultCfg := config.NewDefaultCGRConfig() - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - rate := RateS{ - cfg: defaultCfg, - filterS: filters, - dm: dm, - } - t1 := time.Date(2020, 7, 21, 10, 0, 0, 0, time.UTC) - rpp := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - Weights: utils.DynamicWeights{ - { - Weight: 7, - }, - }, - FilterIDs: []string{"*string:~*req.Account:1001|1002|1003", "*prefix:~*req.Destination:10"}, - ActivationInterval: &utils.ActivationInterval{ - ExpiryTime: t1, - }, - } - err := dm.SetRateProfile(rpp, true) - if err != nil { - t.Error(err) - } - - if rtPRf, err := rate.matchingRateProfileForEvent("cgrates.org", []string{}, - &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Event: map[string]interface{}{ - utils.AccountField: "1001", - utils.Destination: 1002, - utils.AnswerTime: t1.Add(-10 * time.Second), - }, - }, - }); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rtPRf, rpp) { - t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(rpp), utils.ToJSON(rtPRf)) - } - - if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{}, - &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Event: map[string]interface{}{ - utils.AccountField: "1001", - utils.Destination: 2002, - utils.AnswerTime: t1.Add(-10 * time.Second), - }, - }, - }); err != utils.ErrNotFound { - t.Error(err) - } - if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{}, - &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Event: map[string]interface{}{ - utils.AccountField: "1001", - utils.Destination: 2002, - utils.AnswerTime: t1.Add(10 * time.Second), - }, - }, - }); err != utils.ErrNotFound { - t.Error(err) - } - if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{}, - &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Event: map[string]interface{}{ - utils.AccountField: "1007", - utils.Destination: 1002, - utils.AnswerTime: t1.Add(-10 * time.Second), - }, - }, - }); err != utils.ErrNotFound { - t.Error(err) - } - - if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{"rp2"}, - &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Event: map[string]interface{}{ - utils.AccountField: "1007", - utils.Destination: 1002, - utils.AnswerTime: t1.Add(-10 * time.Second), - }, - }, - }); err != utils.ErrNotFound { - t.Error(err) - } - rpp.FilterIDs = []string{"*string:~*req.Account:1001|1002|1003", "*gt:~*req.Cost{*:10"} - if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{}, - &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Event: map[string]interface{}{ - utils.AccountField: "1001", - utils.Cost: 1002, - utils.AnswerTime: t1.Add(-10 * time.Second), - }, - }, - }); err.Error() != "invalid converter terminator in rule: <~*req.Cost{*>" { - t.Error(err) - } - rpp.FilterIDs = []string{"*string:~*req.Account:1001|1002|1003"} - - rate.dm = nil - if _, err := rate.matchingRateProfileForEvent("cgrates.org", []string{"rp3"}, - &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "CACHE1", - Event: map[string]interface{}{ - utils.AccountField: "1007", - utils.Destination: 1002, - utils.AnswerTime: t1.Add(-10 * time.Second), - }, - }, - }); err != utils.ErrNoDatabaseConn { - t.Error(err) - } - - err = dm.RemoveRateProfile(rpp.Tenant, rpp.ID, utils.NonTransactional, true) - if err != nil { - t.Error(err) - } -} - -func TestV1CostForEventError(t *testing.T) { - defaultCfg := config.NewDefaultCGRConfig() - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - rateS := NewRateS(defaultCfg, filters, dm) - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_1", - FilterIDs: []string{"*string:~*req.Account:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": { - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - }, - }, - } - - if err := rateS.dm.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - rcv, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}}}, rateS.cfg.RateSCfg().Verbosity) - if err != nil { - t.Error(err) - } - - expectedErr := "SERVER_ERROR: NOT_IMPLEMENTED:*notAType" - rPrf.FilterIDs = []string{"*notAType:~*req.Account:1001"} - if err := rateS.V1CostForEvent(&utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}}, - RateProfileIDs: []string{"RATE_1"}}, rcv); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } - rPrf.FilterIDs = []string{"*string:~*req.Destination:10"} - - expectedErr = "SERVER_ERROR: zero increment to be charged within rate: " - rPrf.Rates["RATE1"].IntervalRates[0].Increment = utils.NewDecimal(0, 0) - if err := rateS.V1CostForEvent(&utils.ArgsCostForEvent{ - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.Destination: "10"}}, - RateProfileIDs: []string{"RATE_1"}}, rcv); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } - - if err := rateS.dm.RemoveRateProfile(rPrf.Tenant, rPrf.ID, utils.NonTransactional, true); err != nil { - t.Error(err) - } -} - -// go test -run=^$ -v -bench=BenchmarkRateS_V1CostForEvent -benchtime=5s -func BenchmarkRateS_V1CostForEvent(b *testing.B) { - defaultCfg := config.NewDefaultCGRConfig() - - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - rateS := RateS{ - cfg: defaultCfg, - filterS: filters, - dm: dm, - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - b.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - b.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RateChristmas", - FilterIDs: []string{"*string:~*req.Subject:1010"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": &utils.Rate{ - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RATE_CHRISTMAS": &utils.Rate{ - ID: "RT_CHRISTMAS", - Weights: utils.DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*utils.IntervalRate{{ - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(6, 3), - Unit: minDecimal, - Increment: secDecimal, - }}, - }, - }, - } - if err := dm.SetRateProfile(rPrf, true); err != nil { - b.Error(err) - } - if err := rPrf.Compile(); err != nil { - b.Fatal(err) - } - if rcv, err := dm.GetRateProfile("cgrates.org", "RateChristmas", - true, true, utils.NonTransactional); err != nil { - b.Error(err) - } else if !reflect.DeepEqual(rPrf, rcv) { - b.Errorf("Expecting: %v, received: %v", rPrf, rcv) - } - rply := new(utils.RateProfileCost) - argsRt := &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1010", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2020, 12, 23, 59, 0, 0, 0, time.UTC), - utils.OptsRatesUsage: "2h", - }, - }, - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := rateS.V1CostForEvent(argsRt, rply); err != nil { - b.Error(err) - } - } - b.StopTimer() - -} - -// go test -run=^$ -v -bench=BenchmarkRateS_V1CostForEventSingleRate -benchtime=5s -func BenchmarkRateS_V1CostForEventSingleRate(b *testing.B) { - defaultCfg := config.NewDefaultCGRConfig() - - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - rateS := RateS{ - cfg: defaultCfg, - filterS: filters, - dm: dm, - } - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - b.Error(err) - } - secDecimal, err := utils.NewDecimalFromUsage("1s") - if err != nil { - b.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RateAlways", - FilterIDs: []string{"*string:~*req.Subject:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": &utils.Rate{ - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: utils.NewDecimal(int64(time.Minute), 0), - RecurrentFee: utils.NewDecimal(1, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - if err := dm.SetRateProfile(rPrf, true); err != nil { - b.Error(err) - } - if err := rPrf.Compile(); err != nil { - b.Fatal(err) - } - if rcv, err := dm.GetRateProfile("cgrates.org", "RateAlways", - true, true, utils.NonTransactional); err != nil { - b.Error(err) - } else if !reflect.DeepEqual(rPrf, rcv) { - b.Errorf("Expecting: %v, received: %v", rPrf, rcv) - } - rply := new(utils.RateProfileCost) - argsRt := &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: utils.UUIDSha1Prefix(), - Event: map[string]interface{}{ - utils.Subject: "1001", - }, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: time.Date(2020, 12, 23, 59, 0, 0, 0, time.UTC), - utils.OptsRatesUsage: "2h", - }, - }, - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := rateS.V1CostForEvent(argsRt, rply); err != nil { - b.Error(err) - } - } - b.StopTimer() -} - -func TestRatesShutDown(t *testing.T) { - rateS := new(RateS) - if err := rateS.Shutdown(); err != nil { - t.Error(err) - } -} - -func TestRateProfileCostForEventInvalidUsage(t *testing.T) { - defaultCfg := config.NewDefaultCGRConfig() - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - - rateS := NewRateS(defaultCfg, filters, dm) - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_1", - FilterIDs: []string{"*string:~*req.Account:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": { - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - }, - }, - } - - if err := rateS.dm.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - - expected := "can't convert to decimal" - if _, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}, - APIOpts: map[string]interface{}{ - utils.OptsRatesUsage: "invalidUsageFormat", - }}}, rateS.cfg.RateSCfg().Verbosity); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", expected, err) - } - - expected = "Unsupported time format" - if _, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}, - APIOpts: map[string]interface{}{ - utils.OptsRatesStartTime: "invalidStartTimeFormat", - }}}, rateS.cfg.RateSCfg().Verbosity); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", expected, err) - } - - if err := dm.RemoveRateProfile(rPrf.Tenant, rPrf.ID, utils.NonTransactional, true); err != nil { - t.Error(err) - } -} - -func TestRateProfileCostForEventZeroIncrement(t *testing.T) { - defaultCfg := config.NewDefaultCGRConfig() - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - - rateS := NewRateS(defaultCfg, filters, dm) - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_1", - FilterIDs: []string{"*string:~*req.Account:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": { - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "1 * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - - if err := rateS.dm.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - - expected := "zero increment to be charged within rate: " - if _, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}, - APIOpts: map[string]interface{}{ - utils.OptsRatesUsage: "100m", - }}}, rateS.cfg.RateSCfg().Verbosity); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", expected, err) - } - if err := dm.RemoveRateProfile(rPrf.Tenant, rPrf.ID, utils.NonTransactional, true); err != nil { - t.Error(err) - } -} - -func TestRateProfileCostForEventMaximumIterations(t *testing.T) { - defaultCfg := config.NewDefaultCGRConfig() - data := engine.NewInternalDB(nil, nil, true) - dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil) - filters := engine.NewFilterS(defaultCfg, nil, dm) - - rateS := NewRateS(defaultCfg, filters, dm) - minDecimal, err := utils.NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rPrf := &utils.RateProfile{ - Tenant: "cgrates.org", - ID: "RATE_1", - FilterIDs: []string{"*string:~*req.Account:1001"}, - Weights: utils.DynamicWeights{ - { - Weight: 50, - }, - }, - Rates: map[string]*utils.Rate{ - "RATE1": { - ID: "RATE1", - Weights: utils.DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "1 * * * *", - IntervalRates: []*utils.IntervalRate{ - { - IntervalStart: utils.NewDecimal(0, 0), - RecurrentFee: utils.NewDecimal(2, 1), - Unit: minDecimal, - Increment: utils.NewDecimal(0, 0), - }, - }, - }, - }, - } - if err := rateS.dm.SetRateProfile(rPrf, true); err != nil { - t.Error(err) - } - rateS.cfg.RateSCfg().Verbosity = 10 - - expected := "maximum iterations reached" - if _, err := rateS.rateProfileCostForEvent(rPrf, &utils.ArgsCostForEvent{ - - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "RATE_1", - Event: map[string]interface{}{ - utils.AccountField: "1001"}, - APIOpts: map[string]interface{}{ - utils.OptsRatesUsage: "10000m", - }}}, rateS.cfg.RateSCfg().Verbosity); err == nil || err.Error() != expected { - t.Errorf("Expected %+v, received %+v", expected, err) - } - - if err := dm.RemoveRateProfile(rPrf.Tenant, rPrf.ID, utils.NonTransactional, true); err != nil { - t.Error(err) - } -} diff --git a/services/datadb_it_test.go b/services/datadb_it_test.go index 237b9c7ae..a3cbfbe79 100644 --- a/services/datadb_it_test.go +++ b/services/datadb_it_test.go @@ -176,9 +176,6 @@ func TestDataDBReload(t *testing.T) { utils.MetaIndexes: { Replicate: false, Remote: false}, - utils.MetaRateProfiles: { - Replicate: false, - Remote: false}, utils.MetaActionProfiles: { Replicate: false, Remote: false}, @@ -242,7 +239,6 @@ func TestDataDBReloadBadType(t *testing.T) { utils.Chargers: 2, utils.Dispatchers: 2, utils.LoadIDsVrs: 1, - utils.RateProfiles: 1, utils.ActionProfiles: 1, }, true) if err != nil { @@ -351,9 +347,6 @@ func TestDataDBReloadBadType(t *testing.T) { utils.MetaIndexes: { Replicate: false, Remote: false}, - utils.MetaRateProfiles: { - Replicate: false, - Remote: false}, utils.MetaActionProfiles: { Replicate: false, Remote: false}, @@ -480,9 +473,6 @@ func TestDataDBReloadErrorMarsheler(t *testing.T) { utils.MetaIndexes: { Replicate: false, Remote: false}, - utils.MetaRateProfiles: { - Replicate: false, - Remote: false}, utils.MetaActionProfiles: { Replicate: false, Remote: false}, @@ -536,7 +526,6 @@ func TestDataDBStartVersion(t *testing.T) { utils.Chargers: 2, utils.Dispatchers: 2, utils.LoadIDsVrs: 1, - utils.RateProfiles: 1, utils.ActionProfiles: 1, }, true) if err != nil { @@ -599,7 +588,6 @@ func TestDataDBReloadCastError(t *testing.T) { utils.Chargers: 2, utils.Dispatchers: 2, utils.LoadIDsVrs: 1, - utils.RateProfiles: 1, utils.ActionProfiles: 1, }, true) if err != nil { @@ -708,9 +696,6 @@ func TestDataDBReloadCastError(t *testing.T) { utils.MetaIndexes: { Replicate: false, Remote: false}, - utils.MetaRateProfiles: { - Replicate: false, - Remote: false}, utils.MetaActionProfiles: { Replicate: false, Remote: false}, @@ -767,7 +752,6 @@ func TestDataDBReloadIfaceAsDurationError(t *testing.T) { utils.Chargers: 2, utils.Dispatchers: 2, utils.LoadIDsVrs: 1, - utils.RateProfiles: 1, utils.ActionProfiles: 1, }, true) if err != nil { @@ -876,9 +860,6 @@ func TestDataDBReloadIfaceAsDurationError(t *testing.T) { utils.MetaIndexes: { Replicate: false, Remote: false}, - utils.MetaRateProfiles: { - Replicate: false, - Remote: false}, utils.MetaActionProfiles: { Replicate: false, Remote: false}, @@ -1024,9 +1005,6 @@ func TestDataDBReloadError(t *testing.T) { utils.MetaIndexes: { Replicate: false, Remote: false}, - utils.MetaRateProfiles: { - Replicate: false, - Remote: false}, utils.MetaActionProfiles: { Replicate: false, Remote: false}, diff --git a/services/datadb_test.go b/services/datadb_test.go index 232d98b23..8d66fbbd5 100644 --- a/services/datadb_test.go +++ b/services/datadb_test.go @@ -141,9 +141,6 @@ func TestDataDBCoverage(t *testing.T) { utils.MetaIndexes: { Replicate: false, Remote: false}, - utils.MetaRateProfiles: { - Replicate: false, - Remote: false}, utils.MetaActionProfiles: { Replicate: false, Remote: false}, diff --git a/services/rates.go b/services/rates.go deleted file mode 100644 index a6c6e708e..000000000 --- a/services/rates.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package services - -import ( - "sync" - - v1 "github.com/cgrates/cgrates/apier/v1" - "github.com/cgrates/cgrates/cores" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/rates" - "github.com/cgrates/cgrates/servmanager" - "github.com/cgrates/cgrates/utils" - - //"github.com/cgrates/cgrates/apier/v1" - "github.com/cgrates/rpcclient" -) - -// NewRateService constructs RateService -func NewRateService(cfg *config.CGRConfig, - cacheS *engine.CacheS, filterSChan chan *engine.FilterS, - dmS *DataDBService, server *cores.Server, - intConnChan chan rpcclient.ClientConnector, anz *AnalyzerService, - srvDep map[string]*sync.WaitGroup) servmanager.Service { - return &RateService{ - cfg: cfg, - cacheS: cacheS, - filterSChan: filterSChan, - dmS: dmS, - server: server, - intConnChan: intConnChan, - rldChan: make(chan struct{}), - anz: anz, - srvDep: srvDep, - } -} - -// RateService is the service structure for RateS -type RateService struct { - sync.RWMutex - - cfg *config.CGRConfig - filterSChan chan *engine.FilterS - dmS *DataDBService - cacheS *engine.CacheS - server *cores.Server - - rldChan chan struct{} - stopChan chan struct{} - - rateS *rates.RateS - rpc *v1.RateSv1 - intConnChan chan rpcclient.ClientConnector - anz *AnalyzerService - srvDep map[string]*sync.WaitGroup -} - -// ServiceName returns the service name -func (rs *RateService) ServiceName() string { - return utils.RateS -} - -// ShouldRun returns if the service should be running -func (rs *RateService) ShouldRun() (should bool) { - return rs.cfg.RateSCfg().Enabled -} - -// IsRunning returns if the service is running -func (rs *RateService) IsRunning() bool { - rs.RLock() - defer rs.RUnlock() - return rs.rateS != nil -} - -// Reload handles the change of config -func (rs *RateService) Reload() (err error) { - rs.rldChan <- struct{}{} - return -} - -// Shutdown stops the service -func (rs *RateService) Shutdown() (err error) { - rs.Lock() - defer rs.Unlock() - close(rs.stopChan) - rs.rateS.Shutdown() //we don't verify the error because shutdown never returns an err - rs.rateS = nil - <-rs.intConnChan - return -} - -// Start should handle the service start -func (rs *RateService) Start() (err error) { - if rs.IsRunning() { - return utils.ErrServiceAlreadyRunning - } - - <-rs.cacheS.GetPrecacheChannel(utils.CacheRateProfiles) - <-rs.cacheS.GetPrecacheChannel(utils.CacheRateProfilesFilterIndexes) - <-rs.cacheS.GetPrecacheChannel(utils.CacheRateFilterIndexes) - - fltrS := <-rs.filterSChan - rs.filterSChan <- fltrS - - dbchan := rs.dmS.GetDMChan() - dm := <-dbchan - dbchan <- dm - rs.Lock() - rs.rateS = rates.NewRateS(rs.cfg, fltrS, dm) - rs.Unlock() - - rs.stopChan = make(chan struct{}) - go rs.rateS.ListenAndServe(rs.stopChan, rs.rldChan) - - rs.rpc = v1.NewRateSv1(rs.rateS) - if !rs.cfg.DispatcherSCfg().Enabled { - rs.server.RpcRegister(rs.rpc) - } - - rs.intConnChan <- rs.anz.GetInternalCodec(rs.rpc, utils.RateS) - return -} diff --git a/services/rates_it_test.go b/services/rates_it_test.go deleted file mode 100644 index 52f7e38f2..000000000 --- a/services/rates_it_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// +build integration - -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ -package services - -import ( - "path" - "sync" - "testing" - "time" - - "github.com/cgrates/rpcclient" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/cores" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/servmanager" - "github.com/cgrates/cgrates/utils" -) - -func TestRateSReload(t *testing.T) { - cfg := config.NewDefaultCGRConfig() - - utils.Logger, _ = utils.Newlogger(utils.MetaSysLog, cfg.GeneralCfg().NodeID) - utils.Logger.SetLogLevel(7) - filterSChan := make(chan *engine.FilterS, 1) - filterSChan <- nil - shdChan := utils.NewSyncedChan() - shdWg := new(sync.WaitGroup) - server := cores.NewServer(nil) - srvMngr := servmanager.NewServiceManager(cfg, shdChan, shdWg, nil) - srvDep := map[string]*sync.WaitGroup{utils.DataDB: new(sync.WaitGroup)} - db := NewDataDBService(cfg, nil, srvDep) - chS := engine.NewCacheS(cfg, nil, nil) - close(chS.GetPrecacheChannel(utils.CacheRateProfiles)) - close(chS.GetPrecacheChannel(utils.CacheRateProfilesFilterIndexes)) - close(chS.GetPrecacheChannel(utils.CacheRateFilterIndexes)) - anz := NewAnalyzerService(cfg, server, filterSChan, shdChan, make(chan rpcclient.ClientConnector, 1), srvDep) - rS := NewRateService(cfg, chS, filterSChan, db, server, make(chan rpcclient.ClientConnector, 1), anz, srvDep) - srvMngr.AddServices(rS, - NewLoaderService(cfg, db, filterSChan, server, make(chan rpcclient.ClientConnector, 1), nil, anz, srvDep), db) - if err := srvMngr.StartServices(); err != nil { - t.Error(err) - } - if rS.IsRunning() { - t.Errorf("Expected service to be down") - } - var reply string - if err := cfg.V1ReloadConfig(&config.ReloadArgs{ - Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "rates"), - Section: config.RateSJson, - }, &reply); err != nil { - t.Error(err) - } else if reply != utils.OK { - t.Errorf("Expecting OK ,received %s", reply) - } - time.Sleep(10 * time.Millisecond) //need to switch to gorutine - if !rS.IsRunning() { - t.Errorf("Expected service to be running") - } - err := rS.Start() - if err == nil || err != utils.ErrServiceAlreadyRunning { - t.Errorf("\nExpecting <%+v>,\n Received <%+v>", utils.ErrServiceAlreadyRunning, err) - } - err = rS.Reload() - if err != nil { - t.Errorf("\nExpecting ,\n Received <%+v>", err) - } - cfg.RateSCfg().Enabled = false - cfg.GetReloadChan(config.RateSJson) <- struct{}{} - time.Sleep(10 * time.Millisecond) - if rS.IsRunning() { - t.Errorf("Expected service to be down") - } - shdChan.CloseOnce() - time.Sleep(10 * time.Millisecond) -} diff --git a/services/rates_test.go b/services/rates_test.go deleted file mode 100644 index ddbd81f01..000000000 --- a/services/rates_test.go +++ /dev/null @@ -1,78 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ -package services - -import ( - "reflect" - "sync" - "testing" - - "github.com/cgrates/cgrates/rates" - - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/cores" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" - "github.com/cgrates/rpcclient" -) - -//TestRateSCoverage for cover testing -func TestRateSCoverage(t *testing.T) { - cfg := config.NewDefaultCGRConfig() - filterSChan := make(chan *engine.FilterS, 1) - filterSChan <- nil - shdChan := utils.NewSyncedChan() - server := cores.NewServer(nil) - srvDep := map[string]*sync.WaitGroup{utils.DataDB: new(sync.WaitGroup)} - db := NewDataDBService(cfg, nil, srvDep) - chS := engine.NewCacheS(cfg, nil, nil) - anz := NewAnalyzerService(cfg, server, filterSChan, shdChan, make(chan rpcclient.ClientConnector, 1), srvDep) - rS := NewRateService(cfg, chS, filterSChan, db, server, make(chan rpcclient.ClientConnector, 1), anz, srvDep) - - if rS.IsRunning() { - t.Errorf("Expected service to be down") - } - rS2 := RateService{ - cfg: cfg, - filterSChan: filterSChan, - dmS: db, - cacheS: chS, - server: server, - stopChan: make(chan struct{}), - intConnChan: make(chan rpcclient.ClientConnector, 1), - anz: anz, - srvDep: srvDep, - rateS: &rates.RateS{}, - } - if !rS2.IsRunning() { - t.Errorf("Expected service to be running") - } - serviceName := rS2.ServiceName() - if !reflect.DeepEqual(serviceName, utils.RateS) { - t.Errorf("\nExpecting <%+v>,\n Received <%+v>", utils.RateS, serviceName) - } - shouldRun := rS2.ShouldRun() - if !reflect.DeepEqual(shouldRun, false) { - t.Errorf("\nExpecting ,\n Received <%+v>", shouldRun) - } - rS2.intConnChan <- chS - rS2.Shutdown() - if rS.IsRunning() { - t.Errorf("Expected service to be down") - } -} diff --git a/services/stordb_it_test.go b/services/stordb_it_test.go index 367fd1a50..85098cc8c 100644 --- a/services/stordb_it_test.go +++ b/services/stordb_it_test.go @@ -197,7 +197,6 @@ func TestStorDBReloadVersion1(t *testing.T) { utils.TpRatingProfile: 1, utils.TpChargers: 1, utils.TpDispatchers: 1, - utils.TpRateProfiles: 1, utils.TpActionProfiles: 1, }, true) @@ -277,7 +276,6 @@ func TestStorDBReloadVersion2(t *testing.T) { utils.TpRatingProfile: 1, utils.TpChargers: 1, utils.TpDispatchers: 1, - utils.TpRateProfiles: 1, utils.TpActionProfiles: 1, }, true) @@ -354,7 +352,6 @@ func TestStorDBReloadVersion3(t *testing.T) { utils.TpRatingProfile: 1, utils.TpChargers: 1, utils.TpDispatchers: 1, - utils.TpRateProfiles: 1, utils.TpActionProfiles: 1, }, true) diff --git a/utils/accountprofile.go b/utils/accountprofile.go new file mode 100644 index 000000000..98e5c0dd8 --- /dev/null +++ b/utils/accountprofile.go @@ -0,0 +1,514 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package utils + +import ( + "sort" + "time" + + "github.com/ericlagergren/decimal" +) + +// AccountProfile represents one Account on a Tenant +type AccountProfile struct { + Tenant string + ID string // Account identificator, unique within the tenant + FilterIDs []string + ActivationInterval *ActivationInterval + Weights DynamicWeights + Opts map[string]interface{} + Balances map[string]*Balance + ThresholdIDs []string +} + +// BalancesAltered detects altering of the Balances by comparing the Balance values with the ones from backup +func (ap *AccountProfile) BalancesAltered(abb AccountBalancesBackup) (altred bool) { + if len(ap.Balances) != len(abb) { + return true + } + for blncID, blnc := range ap.Balances { + if bkpVal, has := abb[blncID]; !has { + return true + } else if blnc.Units.Big.Cmp(bkpVal) != 0 { + return true + } + } + return +} + +func (ap *AccountProfile) RestoreFromBackup(abb AccountBalancesBackup) { + for blncID, val := range abb { + ap.Balances[blncID].Units.Big = val + } +} + +// AccountBalancesBackup returns a backup of all balance values +func (ap *AccountProfile) AccountBalancesBackup() (abb AccountBalancesBackup) { + if ap.Balances != nil { + abb = make(AccountBalancesBackup) + for blncID, blnc := range ap.Balances { + abb[blncID] = new(decimal.Big).Copy(blnc.Units.Big) + } + } + return +} + +// AccountBalanceBackups is used to create balance snapshots as backups +type AccountBalancesBackup map[string]*decimal.Big + +// NewDefaultBalance returns a balance with default costIncrements +func NewDefaultBalance(id string) *Balance { + const torFltr = "*string:~*req.ToR:" + return &Balance{ + ID: id, + Type: MetaConcrete, + Units: NewDecimal(0, 0), + CostIncrements: []*CostIncrement{ + { + FilterIDs: []string{torFltr + MetaVoice}, + Increment: NewDecimal(int64(time.Second), 0), + RecurrentFee: NewDecimal(0, 0), + }, + { + FilterIDs: []string{torFltr + MetaData}, + Increment: NewDecimal(1024*1024, 0), + RecurrentFee: NewDecimal(0, 0), + }, + { + FilterIDs: []string{torFltr + MetaSMS}, + Increment: NewDecimal(1, 0), + RecurrentFee: NewDecimal(0, 0), + }, + }, + } +} + +// Balance represents one Balance inside an Account +type Balance struct { + ID string // Balance identificator, unique within an Account + FilterIDs []string + Weights DynamicWeights + Type string + Units *Decimal + UnitFactors []*UnitFactor + Opts map[string]interface{} + CostIncrements []*CostIncrement + AttributeIDs []string +} + +// CostIncrement enforces cost calculation to specific balance increments +type CostIncrement struct { + FilterIDs []string + Increment *Decimal + FixedFee *Decimal + RecurrentFee *Decimal +} + +// Clone returns a copy of the CostIncrement +func (cI *CostIncrement) Clone() (cIcln *CostIncrement) { + cIcln = new(CostIncrement) + if cI.FilterIDs != nil { + cIcln.FilterIDs = make([]string, len(cI.FilterIDs)) + for i, fID := range cI.FilterIDs { + cIcln.FilterIDs[i] = fID + } + } + if cI.Increment != nil { + cIcln.Increment = cI.Increment.Clone() + } + if cI.FixedFee != nil { + cIcln.FixedFee = cI.FixedFee.Clone() + } + if cI.RecurrentFee != nil { + cIcln.RecurrentFee = cI.RecurrentFee.Clone() + } + return +} + +//Clone return a copy of the UnitFactor +func (uF *UnitFactor) Clone() (untFct *UnitFactor) { + untFct = new(UnitFactor) + if uF.FilterIDs != nil { + untFct.FilterIDs = make([]string, len(uF.FilterIDs)) + for i, value := range uF.FilterIDs { + untFct.FilterIDs[i] = value + } + } + if uF.Factor != nil { + untFct.Factor = uF.Factor.Clone() + } + return +} + +// UnitFactor is a multiplicator for the usage received +type UnitFactor struct { + FilterIDs []string + Factor *Decimal +} + +// Equals compares two UnitFactors +func (uF *UnitFactor) Equals(nUf *UnitFactor) (eq bool) { + if uF.FilterIDs == nil && nUf.FilterIDs != nil || + uF.FilterIDs != nil && nUf.FilterIDs == nil || + len(uF.FilterIDs) != len(nUf.FilterIDs) { + return + } + for i := range uF.FilterIDs { + if uF.FilterIDs[i] != nUf.FilterIDs[i] { + return + } + } + if uF.Factor == nil && nUf.Factor != nil || + uF.Factor != nil && nUf.Factor == nil { + return + } + if uF.Factor == nil && nUf.Factor == nil { + return true + } + return uF.Factor.Compare(nUf.Factor) == 0 +} + +// TenantID returns the combined Tenant:ID +func (aP *AccountProfile) TenantID() string { + return ConcatenatedKey(aP.Tenant, aP.ID) +} + +// Clone returns a clone of the Account +func (aP *AccountProfile) Clone() (acnt *AccountProfile) { + acnt = &AccountProfile{ + Tenant: aP.Tenant, + ID: aP.ID, + ActivationInterval: aP.ActivationInterval.Clone(), + Weights: aP.Weights.Clone(), + } + if aP.FilterIDs != nil { + acnt.FilterIDs = make([]string, len(aP.FilterIDs)) + for i, value := range aP.FilterIDs { + acnt.FilterIDs[i] = value + } + } + if aP.Opts != nil { + acnt.Opts = make(map[string]interface{}) + for key, value := range aP.Opts { + acnt.Opts[key] = value + } + } + if aP.Balances != nil { + acnt.Balances = make(map[string]*Balance, len(aP.Balances)) + for i, value := range aP.Balances { + acnt.Balances[i] = value.Clone() + } + } + if aP.ThresholdIDs != nil { + acnt.ThresholdIDs = make([]string, len(aP.ThresholdIDs)) + for i, value := range aP.ThresholdIDs { + acnt.ThresholdIDs[i] = value + } + } + return +} + +//Clone returns a clone of the ActivationInterval +func (aI *ActivationInterval) Clone() *ActivationInterval { + if aI == nil { + return nil + } + return &ActivationInterval{ + ActivationTime: aI.ActivationTime, + ExpiryTime: aI.ExpiryTime, + } +} + +//Clone return a clone of the Balance +func (bL *Balance) Clone() (blnc *Balance) { + blnc = &Balance{ + ID: bL.ID, + Weights: bL.Weights.Clone(), + Type: bL.Type, + } + if bL.FilterIDs != nil { + blnc.FilterIDs = make([]string, len(bL.FilterIDs)) + for i, value := range bL.FilterIDs { + blnc.FilterIDs[i] = value + } + } + if bL.Units != nil { + blnc.Units = bL.Units.Clone() + } + if bL.UnitFactors != nil { + blnc.UnitFactors = make([]*UnitFactor, len(bL.UnitFactors)) + for i, value := range bL.UnitFactors { + blnc.UnitFactors[i] = value.Clone() + } + } + if bL.Opts != nil { + blnc.Opts = make(map[string]interface{}) + for key, value := range bL.Opts { + blnc.Opts[key] = value + } + } + if bL.CostIncrements != nil { + blnc.CostIncrements = make([]*CostIncrement, len(bL.CostIncrements)) + for i, value := range bL.CostIncrements { + blnc.CostIncrements[i] = value.Clone() + } + } + if bL.AttributeIDs != nil { + blnc.AttributeIDs = make([]string, len(bL.AttributeIDs)) + for i, value := range bL.AttributeIDs { + blnc.AttributeIDs[i] = value + } + } + return +} + +// AccountProfileWithWeight attaches static weight to AccountProfile +type AccountProfileWithWeight struct { + *AccountProfile + Weight float64 + LockID string +} + +// AccountProfilesWithWeight is a sortable list of AccountProfileWithWeight +type AccountProfilesWithWeight []*AccountProfileWithWeight + +// Sort is part of sort interface, sort based on Weight +func (aps AccountProfilesWithWeight) Sort() { + sort.Slice(aps, func(i, j int) bool { return aps[i].Weight > aps[j].Weight }) +} + +// AccountProfiles returns the list of AccountProfiles +func (apWws AccountProfilesWithWeight) AccountProfiles() (aps []*AccountProfile) { + if apWws != nil { + aps = make([]*AccountProfile, len(apWws)) + for i, apWw := range apWws { + aps[i] = apWw.AccountProfile + } + } + return +} + +// LockIDs returns the list of LockIDs +func (apWws AccountProfilesWithWeight) LockIDs() (lkIDs []string) { + if apWws != nil { + lkIDs = make([]string, len(apWws)) + for i, apWw := range apWws { + lkIDs[i] = apWw.LockID + } + } + return +} + +func (apWws AccountProfilesWithWeight) TenantIDs() (tntIDs []string) { + if apWws != nil { + tntIDs = make([]string, len(apWws)) + for i, apWw := range apWws { + tntIDs[i] = apWw.AccountProfile.TenantID() + } + } + return +} + +// BalanceWithWeight attaches static Weight to Balance +type BalanceWithWeight struct { + *Balance + Weight float64 +} + +// BalancesWithWeight is a sortable list of BalanceWithWeight +type BalancesWithWeight []*BalanceWithWeight + +// Sort is part of sort interface, sort based on Weight +func (blcs BalancesWithWeight) Sort() { + sort.Slice(blcs, func(i, j int) bool { return blcs[i].Weight > blcs[j].Weight }) +} + +// Balances returns the list of Balances +func (bWws BalancesWithWeight) Balances() (blncs []*Balance) { + if bWws != nil { + blncs = make([]*Balance, len(bWws)) + for i, bWw := range bWws { + blncs[i] = bWw.Balance + } + } + return +} + +// APIAccountProfileWithOpts is used in API calls +type APIAccountProfileWithOpts struct { + *APIAccountProfile + APIOpts map[string]interface{} +} + +type AccountProfileWithAPIOpts struct { + *AccountProfile + APIOpts map[string]interface{} +} + +// ArgsAccountForEvent arguments used for process event +type ArgsAccountsForEvent struct { + *CGREvent + AccountIDs []string +} + +type ReplyMaxUsage struct { + AccountID string + MaxUsage time.Duration +} + +// APIAccountProfile represents one APIAccount on a Tenant +type APIAccountProfile struct { + Tenant string + ID string + FilterIDs []string + ActivationInterval *ActivationInterval + Weights string + Opts map[string]interface{} + Balances map[string]*APIBalance + ThresholdIDs []string +} + +// AsAccountProfile convert APIAccountProfile struct to AccountProfile struct +func (ext *APIAccountProfile) AsAccountProfile() (profile *AccountProfile, err error) { + profile = &AccountProfile{ + Tenant: ext.Tenant, + ID: ext.ID, + FilterIDs: ext.FilterIDs, + ActivationInterval: ext.ActivationInterval, + Opts: ext.Opts, + ThresholdIDs: ext.ThresholdIDs, + } + if ext.Weights != EmptyString { + if profile.Weights, err = NewDynamicWeightsFromString(ext.Weights, ";", "&"); err != nil { + return nil, err + } + } + if len(ext.Balances) != 0 { + profile.Balances = make(map[string]*Balance, len(ext.Balances)) + for i, bal := range ext.Balances { + if profile.Balances[i], err = bal.AsBalance(); err != nil { + return nil, err + } + } + } + return +} + +// APIBalance represents one APIBalance inside an APIAccount +type APIBalance struct { + ID string // Balance identificator, unique within an Account + FilterIDs []string + Weights string + Type string + Units float64 + UnitFactors []*APIUnitFactor + Opts map[string]interface{} + CostIncrements []*APICostIncrement + AttributeIDs []string +} + +// AsBalance convert APIBalance struct to Balance struct +func (ext *APIBalance) AsBalance() (balance *Balance, err error) { + balance = &Balance{ + ID: ext.ID, + FilterIDs: ext.FilterIDs, + Type: ext.Type, + Units: NewDecimalFromFloat64(ext.Units), + Opts: ext.Opts, + AttributeIDs: ext.AttributeIDs, + } + if ext.Weights != EmptyString { + if balance.Weights, err = NewDynamicWeightsFromString(ext.Weights, ";", "&"); err != nil { + return nil, err + } + } + if len(ext.UnitFactors) != 0 { + balance.UnitFactors = make([]*UnitFactor, len(ext.UnitFactors)) + for i, uFct := range ext.UnitFactors { + balance.UnitFactors[i] = uFct.AsUnitFactor() + } + } + if len(ext.CostIncrements) != 0 { + balance.CostIncrements = make([]*CostIncrement, len(ext.CostIncrements)) + for i, cIncr := range ext.CostIncrements { + balance.CostIncrements[i] = cIncr.AsCostIncrement() + } + } + return + +} + +// APICostIncrement represent one CostIncrement inside an APIBalance +type APICostIncrement struct { + FilterIDs []string + Increment *float64 + FixedFee *float64 + RecurrentFee *float64 +} + +// AsCostIncrement convert APICostIncrement struct to CostIncrement struct +func (ext *APICostIncrement) AsCostIncrement() (cIncr *CostIncrement) { + cIncr = &CostIncrement{ + FilterIDs: ext.FilterIDs, + } + if ext.Increment != nil { + cIncr.Increment = NewDecimalFromFloat64(*ext.Increment) + } + if ext.FixedFee != nil { + cIncr.FixedFee = NewDecimalFromFloat64(*ext.FixedFee) + } + if ext.RecurrentFee != nil { + cIncr.RecurrentFee = NewDecimalFromFloat64(*ext.RecurrentFee) + } + return +} + +// APIUnitFactor represent one UnitFactor inside an APIBalance +type APIUnitFactor struct { + FilterIDs []string + Factor float64 +} + +// AsUnitFactor convert APIUnitFactor struct to UnitFactor struct +func (ext *APIUnitFactor) AsUnitFactor() *UnitFactor { + return &UnitFactor{ + FilterIDs: ext.FilterIDs, + Factor: NewDecimalFromFloat64(ext.Factor), + } +} + +type ArgsActSetBalance struct { + Tenant string + AccountID string + Diktats []*BalDiktat + Reset bool + APIOpts map[string]interface{} +} + +type BalDiktat struct { + Path string + Value string +} + +type ArgsActRemoveBalances struct { + Tenant string + AccountID string + BalanceIDs []string + APIOpts map[string]interface{} +} diff --git a/utils/accountprofile_test.go b/utils/accountprofile_test.go new file mode 100644 index 000000000..84de5b5b9 --- /dev/null +++ b/utils/accountprofile_test.go @@ -0,0 +1,750 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package utils + +import ( + "reflect" + "testing" + "time" + + "github.com/ericlagergren/decimal" +) + +func TestCloneBalance(t *testing.T) { + expBlc := &Balance{ + ID: "TEST_ID1", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Weights: DynamicWeights{ + { + Weight: 1.1, + }, + }, + Type: "*abstract", + Opts: map[string]interface{}{ + "Destination": 10, + }, + CostIncrements: []*CostIncrement{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Increment: &Decimal{decimal.New(1, 1)}, + FixedFee: &Decimal{decimal.New(75, 1)}, + RecurrentFee: &Decimal{decimal.New(20, 1)}, + }, + }, + AttributeIDs: []string{"attr1", "attr2"}, + UnitFactors: []*UnitFactor{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Factor: &Decimal{decimal.New(20, 2)}, + }, + }, + Units: &Decimal{decimal.New(125, 3)}, + } + if rcv := expBlc.Clone(); !reflect.DeepEqual(rcv, expBlc) { + t.Errorf("Expected %+v \n, received %+v", ToJSON(expBlc), ToJSON(rcv)) + } + + expBlc.Opts = nil + if rcv := expBlc.Clone(); !reflect.DeepEqual(rcv, expBlc) { + t.Errorf("Expected %+v \n, received %+v", ToJSON(expBlc), ToJSON(rcv)) + } +} + +func TestCloneAccountProfile(t *testing.T) { + actPrf := &AccountProfile{ + Tenant: "cgrates.org", + ID: "Profile_id1", + FilterIDs: []string{"*string:~*req.Account:1001"}, + ActivationInterval: &ActivationInterval{ + ActivationTime: time.Date(2020, 7, 21, 10, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, 7, 22, 10, 0, 0, 0, time.UTC), + }, + Weights: DynamicWeights{ + { + Weight: 2.4, + }, + }, + Opts: map[string]interface{}{ + "Destination": 10, + }, + Balances: map[string]*Balance{ + "VoiceBalance": { + ID: "VoiceBalance", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Weights: DynamicWeights{ + { + Weight: 1.1, + }, + }, + Type: "*abstract", + Opts: map[string]interface{}{ + "Destination": 10, + }, + CostIncrements: []*CostIncrement{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Increment: &Decimal{decimal.New(1, 1)}, + FixedFee: &Decimal{decimal.New(75, 1)}, + RecurrentFee: &Decimal{decimal.New(20, 1)}, + }, + }, + AttributeIDs: []string{"attr1", "attr2"}, + UnitFactors: []*UnitFactor{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Factor: &Decimal{decimal.New(20, 2)}, + }, + }, + Units: &Decimal{decimal.New(125, 3)}, + }, + }, + ThresholdIDs: []string{"*none"}, + } + if rcv := actPrf.Clone(); !reflect.DeepEqual(rcv, actPrf) { + t.Errorf("Expected %+v, received %+v", ToJSON(actPrf), ToJSON(rcv)) + } + + actPrf.Opts = nil + actPrf.ActivationInterval = nil + if rcv := actPrf.Clone(); !reflect.DeepEqual(rcv, actPrf) { + t.Errorf("Expected %+v \n, received %+v", ToJSON(actPrf), ToJSON(rcv)) + } +} + +func TestTenantIDAccountProfile(t *testing.T) { + actPrf := &AccountProfile{ + Tenant: "cgrates.org", + ID: "test_ID1", + } + exp := "cgrates.org:test_ID1" + if rcv := actPrf.TenantID(); rcv != exp { + t.Errorf("Expected %+v, received %+v", exp, rcv) + } +} + +func TestAccountProfileAsAccountProfile(t *testing.T) { + apiAccPrf := &APIAccountProfile{ + Tenant: "cgrates.org", + ID: "test_ID1", + Opts: map[string]interface{}{}, + Balances: map[string]*APIBalance{ + "VoiceBalance": { + ID: "VoiceBalance", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Weights: ";1.2", + Type: "*abstract", + Opts: map[string]interface{}{ + "Destination": 10, + }, + Units: 0, + }, + }, + Weights: ";10", + } + expected := &AccountProfile{ + Tenant: "cgrates.org", + ID: "test_ID1", + Opts: map[string]interface{}{}, + Balances: map[string]*Balance{ + "VoiceBalance": { + ID: "VoiceBalance", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Weights: DynamicWeights{ + { + Weight: 1.2, + }, + }, + Type: "*abstract", + Opts: map[string]interface{}{ + "Destination": 10, + }, + Units: NewDecimal(0, 0), + }, + }, + Weights: DynamicWeights{ + { + Weight: 10, + }, + }, + } + if rcv, err := apiAccPrf.AsAccountProfile(); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expected %+v, received %+v", ToJSON(expected), ToJSON(rcv)) + } +} + +func TestAsAccountProfileError(t *testing.T) { + apiAccPrf := &APIAccountProfile{ + Tenant: "cgrates.org", + ID: "test_ID1", + Opts: map[string]interface{}{}, + Balances: map[string]*APIBalance{ + "MonetaryBalance": { + Weights: ";10", + }, + }, + Weights: "10", + } + expectedErr := "invalid DynamicWeight format for string <10>" + if _, err := apiAccPrf.AsAccountProfile(); err == nil || err.Error() != expectedErr { + t.Errorf("Expected %+v, received %+v", expectedErr, err) + } + + apiAccPrf.Weights = ";10" + apiAccPrf.Balances["MonetaryBalance"].Weights = "10" + expectedErr = "invalid DynamicWeight format for string <10>" + if _, err := apiAccPrf.AsAccountProfile(); err == nil || err.Error() != expectedErr { + t.Errorf("Expected %+v, received %+v", expectedErr, err) + } +} + +func TestAPIBalanceAsBalance(t *testing.T) { + blc := &APIBalance{ + ID: "VoiceBalance", + CostIncrements: []*APICostIncrement{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Increment: Float64Pointer(1), + FixedFee: Float64Pointer(10), + RecurrentFee: Float64Pointer(35), + }, + }, + Weights: ";10", + UnitFactors: []*APIUnitFactor{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Factor: 20, + }, + }, + } + expected := &Balance{ + ID: "VoiceBalance", + CostIncrements: []*CostIncrement{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Increment: NewDecimal(1, 0), + FixedFee: NewDecimal(10, 0), + RecurrentFee: NewDecimal(35, 0), + }, + }, + Weights: DynamicWeights{ + { + Weight: 10, + }, + }, + UnitFactors: []*UnitFactor{ + { + FilterIDs: []string{"*string:~*req.Account:1001"}, + Factor: NewDecimal(20, 0), + }, + }, + Units: NewDecimal(0, 0), + } + if rcv, err := blc.AsBalance(); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(rcv, expected) { + t.Errorf("Expected %+v \n, received %+v", ToJSON(expected), ToJSON(rcv)) + } + +} + +func TestAccountProfileBalancesAlteredCompareLength(t *testing.T) { + actPrf := &AccountProfile{ + Balances: map[string]*Balance{ + "testString": {}, + "testString2": {}, + }, + } + + actBk := map[string]*decimal.Big{ + "testString": {}, + } + + result := actPrf.BalancesAltered(actBk) + if result != true { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", true, result) + } + +} + +func TestAccountProfileBalancesAlteredCheckKeys(t *testing.T) { + actPrf := &AccountProfile{ + Balances: map[string]*Balance{ + "testString": {}, + }, + } + + actBk := map[string]*decimal.Big{ + "testString2": {}, + } + + result := actPrf.BalancesAltered(actBk) + if result != true { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", true, result) + } + +} + +func TestAccountProfileBalancesAlteredCompareValues(t *testing.T) { + actPrf := &AccountProfile{ + Balances: map[string]*Balance{ + "testString": { + Units: &Decimal{decimal.New(1, 1)}, + }, + }, + } + + actBk := map[string]*decimal.Big{ + "testString": {}, + } + + result := actPrf.BalancesAltered(actBk) + if result != true { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", true, result) + } + +} + +func TestAccountProfileBalancesAlteredFalse(t *testing.T) { + actPrf := &AccountProfile{} + + actBk := AccountBalancesBackup{} + + result := actPrf.BalancesAltered(actBk) + if result != false { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", false, result) + } + +} + +func TestAPRestoreFromBackup(t *testing.T) { + actPrf := &AccountProfile{ + Balances: map[string]*Balance{ + "testString": { + Units: &Decimal{}, + }, + }, + } + + actBk := AccountBalancesBackup{ + "testString": decimal.New(1, 1), + } + + actPrf.RestoreFromBackup(actBk) + for key, value := range actBk { + if actPrf.Balances[key].Units.Big != value { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", actPrf.Balances[key].Units.Big, value) + } + } +} + +func TestAPAccountBalancesBackup(t *testing.T) { + actPrf := &AccountProfile{ + Balances: map[string]*Balance{ + "testKey": { + Units: &Decimal{decimal.New(1234, 3)}, + }, + }, + } + + actBk := actPrf.AccountBalancesBackup() + for key, value := range actBk { + if actPrf.Balances[key].Units.Big.Cmp(value) != 0 { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", actPrf.Balances[key].Units.Big, value) + } + } +} + +func TestAPNewDefaultBalance(t *testing.T) { + + const torFltr = "*string:~*req.ToR:" + id := "testID" + + expected := &Balance{ + ID: id, + Type: MetaConcrete, + Units: NewDecimal(0, 0), + CostIncrements: []*CostIncrement{ + { + FilterIDs: []string{torFltr + MetaVoice}, + Increment: NewDecimal(int64(time.Second), 0), + RecurrentFee: NewDecimal(0, 0), + }, + { + FilterIDs: []string{torFltr + MetaData}, + Increment: NewDecimal(1024*1024, 0), + RecurrentFee: NewDecimal(0, 0), + }, + { + FilterIDs: []string{torFltr + MetaSMS}, + Increment: NewDecimal(1, 0), + RecurrentFee: NewDecimal(0, 0), + }, + }, + } + + received := NewDefaultBalance(id) + + if !reflect.DeepEqual(received, expected) { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) + } +} + +func TestAPApsSort(t *testing.T) { + + apS := AccountProfilesWithWeight{ + { + Weight: 2, + }, + { + Weight: 1, + }, + { + Weight: 3, + }, + } + expected := AccountProfilesWithWeight{ + { + Weight: 3, + }, + { + Weight: 2, + }, + { + Weight: 1, + }, + } + + apS.Sort() + if !reflect.DeepEqual(apS, expected) { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", ToJSON(expected), ToJSON(apS)) + } +} + +func TestAPAccountProfiles(t *testing.T) { + + apS := AccountProfilesWithWeight{ + { + AccountProfile: &AccountProfile{ + Tenant: "testTenant1", + ID: "testID1", + FilterIDs: []string{"testFID1", "testFID2"}, + ActivationInterval: &ActivationInterval{ + ActivationTime: time.Date(2020, time.April, 12, 0, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, time.April, 12, 10, 0, 0, 0, time.UTC), + }, + Weights: nil, + Balances: map[string]*Balance{ + "testBalance1": { + ID: "testBalance1", + Type: MetaAbstract, + Units: &Decimal{decimal.New(0, 0)}, + }, + }, + }, + Weight: 23, + LockID: "testString1", + }, + { + AccountProfile: &AccountProfile{ + Tenant: "testTenant2", + ID: "testID2", + FilterIDs: []string{"testFID1", "testFID2"}, + ActivationInterval: &ActivationInterval{ + ActivationTime: time.Date(2020, time.April, 12, 0, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, time.April, 12, 10, 0, 0, 0, time.UTC), + }, + Weights: nil, + Balances: map[string]*Balance{ + "testBalance2": { + ID: "testBalance2", + Type: MetaAbstract, + Units: &Decimal{decimal.New(0, 0)}, + }, + }, + }, + Weight: 15, + LockID: "testString2", + }, + } + + expected := make([]*AccountProfile, 0) + for i := range apS { + expected = append(expected, apS[i].AccountProfile) + } + received := apS.AccountProfiles() + + if !reflect.DeepEqual(received, expected) { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", ToJSON(expected), ToJSON(received)) + } +} + +func TestAPLockIDs(t *testing.T) { + apS := AccountProfilesWithWeight{ + { + AccountProfile: &AccountProfile{ + Tenant: "testTenant1", + ID: "testID1", + FilterIDs: []string{"testFID1", "testFID2"}, + ActivationInterval: &ActivationInterval{ + ActivationTime: time.Date(2020, time.April, 12, 0, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, time.April, 12, 10, 0, 0, 0, time.UTC), + }, + Weights: nil, + Balances: map[string]*Balance{ + "testBalance1": { + ID: "testBalance1", + Type: MetaAbstract, + Units: &Decimal{decimal.New(0, 0)}, + }, + }, + }, + Weight: 23, + LockID: "testString1", + }, + { + AccountProfile: &AccountProfile{ + Tenant: "testTenant2", + ID: "testID2", + FilterIDs: []string{"testFID1", "testFID2"}, + ActivationInterval: &ActivationInterval{ + ActivationTime: time.Date(2020, time.April, 12, 0, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, time.April, 12, 10, 0, 0, 0, time.UTC), + }, + Weights: nil, + Balances: map[string]*Balance{ + "testBalance2": { + ID: "testBalance2", + Type: MetaAbstract, + Units: &Decimal{decimal.New(0, 0)}, + }, + }, + }, + Weight: 15, + LockID: "testString2", + }, + } + + expected := make([]string, 0) + for i := range apS { + expected = append(expected, apS[i].LockID) + } + received := apS.LockIDs() + + if !reflect.DeepEqual(received, expected) { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) + } +} + +func TestAPTenantIDs(t *testing.T) { + apS := AccountProfilesWithWeight{ + { + AccountProfile: &AccountProfile{ + Tenant: "testTenant1", + ID: "testID1", + FilterIDs: []string{"testFID1", "testFID2"}, + ActivationInterval: &ActivationInterval{ + ActivationTime: time.Date(2020, time.April, 12, 0, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, time.April, 12, 10, 0, 0, 0, time.UTC), + }, + Weights: nil, + Balances: map[string]*Balance{ + "testBalance1": { + ID: "testBalance1", + Type: MetaAbstract, + Units: &Decimal{decimal.New(0, 0)}, + }, + }, + }, + Weight: 23, + LockID: "testString1", + }, + { + AccountProfile: &AccountProfile{ + Tenant: "testTenant2", + ID: "testID2", + FilterIDs: []string{"testFID1", "testFID2"}, + ActivationInterval: &ActivationInterval{ + ActivationTime: time.Date(2020, time.April, 12, 0, 0, 0, 0, time.UTC), + ExpiryTime: time.Date(2020, time.April, 12, 10, 0, 0, 0, time.UTC), + }, + Weights: nil, + Balances: map[string]*Balance{ + "testBalance2": { + ID: "testBalance2", + Type: MetaAbstract, + Units: &Decimal{decimal.New(0, 0)}, + }, + }, + }, + Weight: 15, + LockID: "testString2", + }, + } + + expected := make([]string, 0) + for _, val := range apS { + id := val.AccountProfile.Tenant + tenant := val.AccountProfile.ID + expected = append(expected, ConcatenatedKey(id, tenant)) + } + received := apS.TenantIDs() + + if !reflect.DeepEqual(received, expected) { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) + } +} + +func TestAPBlcsSort(t *testing.T) { + + blncS := BalancesWithWeight{ + { + Weight: 2, + }, + { + Weight: 1, + }, + { + Weight: 3, + }, + } + expected := BalancesWithWeight{ + { + Weight: 3, + }, + { + Weight: 2, + }, + { + Weight: 1, + }, + } + + blncS.Sort() + if !reflect.DeepEqual(blncS, expected) { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", ToJSON(expected), ToJSON(blncS)) + } +} + +func TestAPBalances(t *testing.T) { + blncS := BalancesWithWeight{ + { + Balance: &Balance{ + ID: "testID1", + FilterIDs: []string{"testFID1", "testFID2"}, + Type: MetaAbstract, + Units: &Decimal{decimal.New(1234, 3)}, + Weights: nil, + UnitFactors: []*UnitFactor{ + { + Factor: NewDecimal(1, 1), + }, + }, + Opts: map[string]interface{}{ + MetaBalanceLimit: -1.0, + }, + CostIncrements: []*CostIncrement{ + { + Increment: NewDecimal(int64(time.Duration(time.Second)), 0), + RecurrentFee: NewDecimal(0, 0), + }, + }, + AttributeIDs: []string{"testString1"}, + }, + Weight: 23, + }, + { + Balance: &Balance{ + ID: "testID2", + FilterIDs: []string{"testFID3", "testFID4"}, + Type: MetaAbstract, + Units: &Decimal{decimal.New(1234, 3)}, + Weights: nil, + UnitFactors: []*UnitFactor{ + { + Factor: NewDecimal(1, 1), + }, + }, + Opts: map[string]interface{}{ + MetaBalanceLimit: -1.0, + }, + CostIncrements: []*CostIncrement{ + { + Increment: NewDecimal(int64(time.Duration(time.Second)), 0), + RecurrentFee: NewDecimal(0, 0), + }, + }, + AttributeIDs: []string{"testString3"}, + }, + Weight: 23, + }, + } + + expected := make([]*Balance, 0) + for i := range blncS { + expected = append(expected, blncS[i].Balance) + } + received := blncS.Balances() + + if !reflect.DeepEqual(received, expected) { + t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", ToJSON(expected), ToJSON(received)) + } +} + +func TestEqualsUnitFactor(t *testing.T) { + uf1 := &UnitFactor{ + FilterIDs: []string{"*string:~*req.Account:1003"}, + Factor: NewDecimal(10, 0), + } + uf2 := &UnitFactor{ + FilterIDs: []string{"*string:~*req.Account:1003"}, + Factor: NewDecimal(10, 0), + } + if !uf1.Equals(uf2) { + t.Errorf("Unexpected equal result") + } + + uf1.FilterIDs = []string{"*string:~*req.Account:1004"} + if uf1.Equals(uf2) { + t.Errorf("Unexpected equal result") + } + uf1.FilterIDs = nil + + if uf1.Equals(uf2) { + t.Errorf("Unexpected equal result") + } + uf1.FilterIDs = []string{"*string:~*req.Account:1003"} + + uf1.Factor = NewDecimal(100, 0) + if uf1.Equals(uf2) { + t.Errorf("Unexpected equal result") + } + + uf1.Factor = nil + uf2.Factor = nil + if !uf1.Equals(uf2) { + t.Errorf("Unexpected equal result") + } + + uf2.Factor = NewDecimal(10, 0) + if uf1.Equals(uf2) { + t.Errorf("Unexpected equal result") + } +} diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 79c56abff..e804303e5 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -932,17 +932,15 @@ func (attr *ArgRSv1ResourceUsage) Clone() *ArgRSv1ResourceUsage { } type ArgsComputeFilterIndexIDs struct { - Tenant string - Context string - AttributeIDs []string - ResourceIDs []string - StatIDs []string - RouteIDs []string - ThresholdIDs []string - ChargerIDs []string - DispatcherIDs []string - RateProfileIDs []string - ActionProfileIDs []string + Tenant string + Context string + AttributeIDs []string + ResourceIDs []string + StatIDs []string + RouteIDs []string + ThresholdIDs []string + ChargerIDs []string + DispatcherIDs []string } type ArgsComputeFilterIndexes struct { @@ -955,9 +953,6 @@ type ArgsComputeFilterIndexes struct { ThresholdS bool ChargerS bool DispatcherS bool - RateS bool - AccountS bool - ActionS bool } // AsActivationTime converts TPActivationInterval into ActivationInterval @@ -1299,39 +1294,37 @@ type ArgsGetCacheItemWithAPIOpts struct { func NewAttrReloadCacheWithOpts() *AttrReloadCacheWithAPIOpts { return &AttrReloadCacheWithAPIOpts{ ArgsCache: map[string][]string{ - DestinationIDs: nil, - ReverseDestinationIDs: nil, - RatingPlanIDs: nil, - RatingProfileIDs: nil, - ActionIDs: nil, - ActionPlanIDs: nil, - AccountActionPlanIDs: nil, - ActionTriggerIDs: nil, - SharedGroupIDs: nil, - ResourceProfileIDs: nil, - ResourceIDs: nil, - StatsQueueIDs: nil, - StatsQueueProfileIDs: nil, - ThresholdIDs: nil, - ThresholdProfileIDs: nil, - FilterIDs: nil, - RouteProfileIDs: nil, - AttributeProfileIDs: nil, - ChargerProfileIDs: nil, - DispatcherProfileIDs: nil, - DispatcherHostIDs: nil, - RateProfileIDs: nil, - TimingIDs: nil, - AttributeFilterIndexIDs: nil, - ResourceFilterIndexIDs: nil, - StatFilterIndexIDs: nil, - ThresholdFilterIndexIDs: nil, - RouteFilterIndexIDs: nil, - ChargerFilterIndexIDs: nil, - DispatcherFilterIndexIDs: nil, - RateProfilesFilterIndexIDs: nil, - RateFilterIndexIDs: nil, - FilterIndexIDs: nil, + DestinationIDs: nil, + ReverseDestinationIDs: nil, + RatingPlanIDs: nil, + RatingProfileIDs: nil, + ActionIDs: nil, + ActionPlanIDs: nil, + AccountActionPlanIDs: nil, + ActionTriggerIDs: nil, + SharedGroupIDs: nil, + ResourceProfileIDs: nil, + ResourceIDs: nil, + StatsQueueIDs: nil, + StatsQueueProfileIDs: nil, + ThresholdIDs: nil, + ThresholdProfileIDs: nil, + FilterIDs: nil, + RouteProfileIDs: nil, + AttributeProfileIDs: nil, + ChargerProfileIDs: nil, + DispatcherProfileIDs: nil, + DispatcherHostIDs: nil, + TimingIDs: nil, + AttributeFilterIndexIDs: nil, + ResourceFilterIndexIDs: nil, + StatFilterIndexIDs: nil, + ThresholdFilterIndexIDs: nil, + RouteFilterIndexIDs: nil, + ChargerFilterIndexIDs: nil, + DispatcherFilterIndexIDs: nil, + RateFilterIndexIDs: nil, + FilterIndexIDs: nil, }, } } @@ -1455,36 +1448,6 @@ type AttrsExecuteActionPlans struct { APIOpts map[string]interface{} } -type TPRateProfile struct { - TPid string - Tenant string - ID string - FilterIDs []string - ActivationInterval *TPActivationInterval - Weights string - MinCost float64 - MaxCost float64 - MaxCostStrategy string - Rates map[string]*TPRate -} - -type TPRate struct { - ID string // RateID - FilterIDs []string // RateFilterIDs - ActivationTimes string - Weights string // RateWeight will decide the winner per interval start - Blocker bool // RateBlocker will make this rate recurrent, deactivating further intervals - IntervalRates []*TPIntervalRate -} - -type TPIntervalRate struct { - IntervalStart string - FixedFee float64 - RecurrentFee float64 // RateValue - Unit string - Increment string -} - type ArgExportCDRs struct { ExporterIDs []string // exporterIDs is used to said which exporter are using to export the cdrs Verbose bool // verbose is used to inform the user about the positive and negative exported cdrs diff --git a/utils/apitpdata_test.go b/utils/apitpdata_test.go index f9a90c667..9ceaf2f6b 100644 --- a/utils/apitpdata_test.go +++ b/utils/apitpdata_test.go @@ -1016,39 +1016,37 @@ func TestCDRsFilterPrepare(t *testing.T) { func TestNewAttrReloadCacheWithOpts(t *testing.T) { newAttrReloadCache := &AttrReloadCacheWithAPIOpts{ ArgsCache: map[string][]string{ - DestinationIDs: nil, - ReverseDestinationIDs: nil, - RatingPlanIDs: nil, - RatingProfileIDs: nil, - ActionIDs: nil, - ActionPlanIDs: nil, - AccountActionPlanIDs: nil, - ActionTriggerIDs: nil, - SharedGroupIDs: nil, - ResourceProfileIDs: nil, - ResourceIDs: nil, - StatsQueueIDs: nil, - StatsQueueProfileIDs: nil, - ThresholdIDs: nil, - ThresholdProfileIDs: nil, - FilterIDs: nil, - RouteProfileIDs: nil, - AttributeProfileIDs: nil, - ChargerProfileIDs: nil, - DispatcherProfileIDs: nil, - DispatcherHostIDs: nil, - RateProfileIDs: nil, - TimingIDs: nil, - AttributeFilterIndexIDs: nil, - ResourceFilterIndexIDs: nil, - StatFilterIndexIDs: nil, - ThresholdFilterIndexIDs: nil, - RouteFilterIndexIDs: nil, - ChargerFilterIndexIDs: nil, - DispatcherFilterIndexIDs: nil, - RateProfilesFilterIndexIDs: nil, - RateFilterIndexIDs: nil, - FilterIndexIDs: nil, + DestinationIDs: nil, + ReverseDestinationIDs: nil, + RatingPlanIDs: nil, + RatingProfileIDs: nil, + ActionIDs: nil, + ActionPlanIDs: nil, + AccountActionPlanIDs: nil, + ActionTriggerIDs: nil, + SharedGroupIDs: nil, + ResourceProfileIDs: nil, + ResourceIDs: nil, + StatsQueueIDs: nil, + StatsQueueProfileIDs: nil, + ThresholdIDs: nil, + ThresholdProfileIDs: nil, + FilterIDs: nil, + RouteProfileIDs: nil, + AttributeProfileIDs: nil, + ChargerProfileIDs: nil, + DispatcherProfileIDs: nil, + DispatcherHostIDs: nil, + TimingIDs: nil, + AttributeFilterIndexIDs: nil, + ResourceFilterIndexIDs: nil, + StatFilterIndexIDs: nil, + ThresholdFilterIndexIDs: nil, + RouteFilterIndexIDs: nil, + ChargerFilterIndexIDs: nil, + DispatcherFilterIndexIDs: nil, + RateFilterIndexIDs: nil, + FilterIndexIDs: nil, }, } eMap := NewAttrReloadCacheWithOpts() diff --git a/utils/consts.go b/utils/consts.go index 8dd7243d2..075342722 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -54,8 +54,7 @@ var ( CacheChargerProfiles, CacheActionProfiles, CacheDispatcherProfiles, CacheDispatcherHosts, CacheResourceFilterIndexes, CacheStatFilterIndexes, CacheThresholdFilterIndexes, CacheRouteFilterIndexes, CacheAttributeFilterIndexes, CacheChargerFilterIndexes, CacheDispatcherFilterIndexes, CacheLoadIDs, - CacheRatingProfilesTmp, CacheRateProfiles, CacheRateProfilesFilterIndexes, CacheRateFilterIndexes, - CacheActionProfilesFilterIndexes, CacheReverseFilterIndexes, + CacheRatingProfilesTmp, CacheReverseFilterIndexes, CacheActionPlans, CacheAccountActionPlans, CacheAccounts}) storDBPartition = NewStringSet([]string{CacheTBLTPTimings, CacheTBLTPDestinations, CacheTBLTPRates, CacheTBLTPDestinationRates, @@ -63,65 +62,57 @@ var ( CacheTBLTPActionPlans, CacheTBLTPActionTriggers, CacheTBLTPAccountActions, CacheTBLTPResources, CacheTBLTPStats, CacheTBLTPThresholds, CacheTBLTPFilters, CacheSessionCostsTBL, CacheCDRsTBL, CacheTBLTPRoutes, CacheTBLTPAttributes, CacheTBLTPChargers, CacheTBLTPDispatchers, - CacheTBLTPDispatcherHosts, CacheTBLTPRateProfiles, CacheTBLTPActionProfiles}) + CacheTBLTPDispatcherHosts}) // CachePartitions enables creation of cache partitions CachePartitions = JoinStringSet(extraDBPartition, dataDBPartition, storDBPartition) CacheInstanceToPrefix = map[string]string{ - CacheDestinations: DestinationPrefix, - CacheReverseDestinations: ReverseDestinationPrefix, - CacheRatingPlans: RatingPlanPrefix, - CacheRatingProfiles: RatingProfilePrefix, - CacheActions: ActionPrefix, - CacheActionPlans: ActionPlanPrefix, - CacheAccountActionPlans: AccountActionPlansPrefix, - CacheActionTriggers: ActionTriggerPrefix, - CacheSharedGroups: SharedGroupPrefix, - CacheResourceProfiles: ResourceProfilesPrefix, - CacheResources: ResourcesPrefix, - CacheTimings: TimingsPrefix, - CacheStatQueueProfiles: StatQueueProfilePrefix, - CacheStatQueues: StatQueuePrefix, - CacheThresholdProfiles: ThresholdProfilePrefix, - CacheThresholds: ThresholdPrefix, - CacheFilters: FilterPrefix, - CacheRouteProfiles: RouteProfilePrefix, - CacheAttributeProfiles: AttributeProfilePrefix, - CacheChargerProfiles: ChargerProfilePrefix, - CacheDispatcherProfiles: DispatcherProfilePrefix, - CacheDispatcherHosts: DispatcherHostPrefix, - CacheRateProfiles: RateProfilePrefix, - CacheActionProfiles: ActionProfilePrefix, - CacheResourceFilterIndexes: ResourceFilterIndexes, - CacheStatFilterIndexes: StatFilterIndexes, - CacheThresholdFilterIndexes: ThresholdFilterIndexes, - CacheRouteFilterIndexes: RouteFilterIndexes, - CacheAttributeFilterIndexes: AttributeFilterIndexes, - CacheChargerFilterIndexes: ChargerFilterIndexes, - CacheDispatcherFilterIndexes: DispatcherFilterIndexes, - CacheRateProfilesFilterIndexes: RateProfilesFilterIndexPrfx, - CacheActionProfilesFilterIndexes: ActionProfilesFilterIndexPrfx, + CacheDestinations: DestinationPrefix, + CacheReverseDestinations: ReverseDestinationPrefix, + CacheRatingPlans: RatingPlanPrefix, + CacheRatingProfiles: RatingProfilePrefix, + CacheActions: ActionPrefix, + CacheActionPlans: ActionPlanPrefix, + CacheAccountActionPlans: AccountActionPlansPrefix, + CacheActionTriggers: ActionTriggerPrefix, + CacheSharedGroups: SharedGroupPrefix, + CacheResourceProfiles: ResourceProfilesPrefix, + CacheResources: ResourcesPrefix, + CacheTimings: TimingsPrefix, + CacheStatQueueProfiles: StatQueueProfilePrefix, + CacheStatQueues: StatQueuePrefix, + CacheThresholdProfiles: ThresholdProfilePrefix, + CacheThresholds: ThresholdPrefix, + CacheFilters: FilterPrefix, + CacheRouteProfiles: RouteProfilePrefix, + CacheAttributeProfiles: AttributeProfilePrefix, + CacheChargerProfiles: ChargerProfilePrefix, + CacheDispatcherProfiles: DispatcherProfilePrefix, + CacheDispatcherHosts: DispatcherHostPrefix, + CacheResourceFilterIndexes: ResourceFilterIndexes, + CacheStatFilterIndexes: StatFilterIndexes, + CacheThresholdFilterIndexes: ThresholdFilterIndexes, + CacheRouteFilterIndexes: RouteFilterIndexes, + CacheAttributeFilterIndexes: AttributeFilterIndexes, + CacheChargerFilterIndexes: ChargerFilterIndexes, + CacheDispatcherFilterIndexes: DispatcherFilterIndexes, CacheLoadIDs: LoadIDPrefix, CacheAccounts: AccountPrefix, - CacheRateFilterIndexes: RateFilterIndexPrfx, CacheReverseFilterIndexes: FilterIndexPrfx, MetaAPIBan: MetaAPIBan, // special case as it is not in a DB } CachePrefixToInstance map[string]string // will be built on init CacheIndexesToPrefix = map[string]string{ // used by match index to get all the ids when index selects is disabled and for compute indexes - CacheThresholdFilterIndexes: ThresholdProfilePrefix, - CacheResourceFilterIndexes: ResourceProfilesPrefix, - CacheStatFilterIndexes: StatQueueProfilePrefix, - CacheRouteFilterIndexes: RouteProfilePrefix, - CacheAttributeFilterIndexes: AttributeProfilePrefix, - CacheChargerFilterIndexes: ChargerProfilePrefix, - CacheDispatcherFilterIndexes: DispatcherProfilePrefix, - CacheRateProfilesFilterIndexes: RateProfilePrefix, - CacheRateFilterIndexes: RatePrefix, - CacheActionProfilesFilterIndexes: ActionProfilePrefix, - CacheReverseFilterIndexes: FilterPrefix, + CacheThresholdFilterIndexes: ThresholdProfilePrefix, + CacheResourceFilterIndexes: ResourceProfilesPrefix, + CacheStatFilterIndexes: StatQueueProfilePrefix, + CacheRouteFilterIndexes: RouteProfilePrefix, + CacheAttributeFilterIndexes: AttributeProfilePrefix, + CacheChargerFilterIndexes: ChargerProfilePrefix, + CacheDispatcherFilterIndexes: DispatcherProfilePrefix, + CacheReverseFilterIndexes: FilterPrefix, } CacheInstanceToCacheIndex = map[string]string{ @@ -132,7 +123,6 @@ var ( CacheAttributeProfiles: CacheAttributeFilterIndexes, CacheChargerProfiles: CacheChargerFilterIndexes, CacheDispatcherProfiles: CacheDispatcherFilterIndexes, - CacheRateProfiles: CacheRateProfilesFilterIndexes, CacheActionProfiles: CacheActionProfilesFilterIndexes, CacheFilters: CacheReverseFilterIndexes, // CacheRates: CacheRateFilterIndexes, @@ -167,7 +157,6 @@ var ( TBLTPChargers: CacheTBLTPChargers, TBLTPDispatchers: CacheTBLTPDispatchers, TBLTPDispatcherHosts: CacheTBLTPDispatcherHosts, - TBLTPRateProfiles: CacheTBLTPRateProfiles, TBLTPActionProfiles: CacheTBLTPActionProfiles, } // ProtectedSFlds are the fields that sessions should not alter @@ -194,21 +183,17 @@ var ( ChargerProfileIDs: ChargerProfilePrefix, DispatcherProfileIDs: DispatcherProfilePrefix, DispatcherHostIDs: DispatcherHostPrefix, - RateProfileIDs: RateProfilePrefix, ActionProfileIDs: ActionProfilePrefix, - TimingIDs: TimingsPrefix, - AttributeFilterIndexIDs: AttributeFilterIndexes, - ResourceFilterIndexIDs: ResourceFilterIndexes, - StatFilterIndexIDs: StatFilterIndexes, - ThresholdFilterIndexIDs: ThresholdFilterIndexes, - RouteFilterIndexIDs: RouteFilterIndexes, - ChargerFilterIndexIDs: ChargerFilterIndexes, - DispatcherFilterIndexIDs: DispatcherFilterIndexes, - RateProfilesFilterIndexIDs: RateProfilesFilterIndexPrfx, - RateFilterIndexIDs: RateFilterIndexPrfx, - ActionProfilesFilterIndexIDs: ActionProfilesFilterIndexPrfx, - FilterIndexIDs: FilterIndexPrfx, + TimingIDs: TimingsPrefix, + AttributeFilterIndexIDs: AttributeFilterIndexes, + ResourceFilterIndexIDs: ResourceFilterIndexes, + StatFilterIndexIDs: StatFilterIndexes, + ThresholdFilterIndexIDs: ThresholdFilterIndexes, + RouteFilterIndexIDs: RouteFilterIndexes, + ChargerFilterIndexIDs: ChargerFilterIndexes, + DispatcherFilterIndexIDs: DispatcherFilterIndexes, + FilterIndexIDs: FilterIndexPrfx, } CacheInstanceToArg map[string]string ArgCacheToInstance = map[string]string{ @@ -233,21 +218,16 @@ var ( ChargerProfileIDs: CacheChargerProfiles, DispatcherProfileIDs: CacheDispatcherProfiles, DispatcherHostIDs: CacheDispatcherHosts, - RateProfileIDs: CacheRateProfiles, - ActionProfileIDs: CacheActionProfiles, - TimingIDs: CacheTimings, - AttributeFilterIndexIDs: CacheAttributeFilterIndexes, - ResourceFilterIndexIDs: CacheResourceFilterIndexes, - StatFilterIndexIDs: CacheStatFilterIndexes, - ThresholdFilterIndexIDs: CacheThresholdFilterIndexes, - RouteFilterIndexIDs: CacheRouteFilterIndexes, - ChargerFilterIndexIDs: CacheChargerFilterIndexes, - DispatcherFilterIndexIDs: CacheDispatcherFilterIndexes, - RateProfilesFilterIndexIDs: CacheRateProfilesFilterIndexes, - RateFilterIndexIDs: CacheRateFilterIndexes, - FilterIndexIDs: CacheReverseFilterIndexes, - ActionProfilesFilterIndexIDs: CacheActionProfilesFilterIndexes, + TimingIDs: CacheTimings, + AttributeFilterIndexIDs: CacheAttributeFilterIndexes, + ResourceFilterIndexIDs: CacheResourceFilterIndexes, + StatFilterIndexIDs: CacheStatFilterIndexes, + ThresholdFilterIndexIDs: CacheThresholdFilterIndexes, + RouteFilterIndexIDs: CacheRouteFilterIndexes, + ChargerFilterIndexIDs: CacheChargerFilterIndexes, + DispatcherFilterIndexIDs: CacheDispatcherFilterIndexes, + FilterIndexIDs: CacheReverseFilterIndexes, } ConcurrentReqsLimit int ConcurrentReqsStrategy string @@ -397,7 +377,6 @@ const ( AttributeProfilePrefix = "alp_" ChargerProfilePrefix = "cpp_" DispatcherProfilePrefix = "dpp_" - RateProfilePrefix = "rtp_" ActionProfilePrefix = "acp_" DispatcherHostPrefix = "dph_" ThresholdProfilePrefix = "thp_" @@ -556,7 +535,6 @@ const ( Filters = "Filters" DispatcherProfiles = "DispatcherProfiles" DispatcherHosts = "DispatcherHosts" - RateProfiles = "RateProfiles" ActionProfiles = "ActionProfiles" MetaEveryMinute = "*every_minute" MetaHourly = "*hourly" @@ -705,7 +683,6 @@ const ( SortingParameters = "SortingParameters" RouteAccountIDs = "RouteAccountIDs" RouteRatingplanIDs = "RouteRatingplanIDs" - RouteRateProfileIDs = "RouteRateProfileIDs" RouteStatIDs = "RouteStatIDs" RouteWeight = "RouteWeight" RouteParameters = "RouteParameters" @@ -913,7 +890,6 @@ const ( MetaRounding = "*rounding" StatsNA = -1.0 InvalidUsage = -1 - RateProfileMatched = "RateProfileMatched" InvalidDuration = time.Duration(-1) ActionS = "ActionS" Schedule = "Schedule" @@ -989,8 +965,6 @@ const ( MetaAttributeProfiles = "*attribute_profiles" MetaIndexes = "*indexes" MetaDispatcherProfiles = "*dispatcher_profiles" - MetaRateProfiles = "*rate_profiles" - MetaRateProfileRates = "*rate_profile_rates" MetaChargerProfiles = "*charger_profiles" MetaSharedGroups = "*shared_groups" MetaThresholds = "*thresholds" @@ -1122,7 +1096,6 @@ const ( MetaTpSharedGroups = "*tp_shared_groups" MetaTpRatingProfiles = "*tp_rating_profiles" MetaTpActionProfiles = "*tp_action_profiles" - MetaTpRateProfiles = "*tp_rate_profiles" MetaTpResources = "*tp_resources" MetaTpRates = "*tp_rates" MetaTpTimings = "*tp_timings" @@ -1165,7 +1138,6 @@ const ( TpDispatchers = "TpDispatchers" TpDispatcherProfiles = "TpDispatcherProfiles" TpDispatcherHosts = "TpDispatcherHosts" - TpRateProfiles = "TpRateProfiles" TpActionProfiles = "TpActionProfiles" ) @@ -1255,7 +1227,6 @@ const ( ReplicatorSv1GetAttributeProfile = "ReplicatorSv1.GetAttributeProfile" ReplicatorSv1GetChargerProfile = "ReplicatorSv1.GetChargerProfile" ReplicatorSv1GetDispatcherProfile = "ReplicatorSv1.GetDispatcherProfile" - ReplicatorSv1GetRateProfile = "ReplicatorSv1.GetRateProfile" ReplicatorSv1GetActionProfile = "ReplicatorSv1.GetActionProfile" ReplicatorSv1GetDispatcherHost = "ReplicatorSv1.GetDispatcherHost" ReplicatorSv1GetItemLoadIDs = "ReplicatorSv1.GetItemLoadIDs" @@ -1281,7 +1252,6 @@ const ( ReplicatorSv1SetAttributeProfile = "ReplicatorSv1.SetAttributeProfile" ReplicatorSv1SetChargerProfile = "ReplicatorSv1.SetChargerProfile" ReplicatorSv1SetDispatcherProfile = "ReplicatorSv1.SetDispatcherProfile" - ReplicatorSv1SetRateProfile = "ReplicatorSv1.SetRateProfile" ReplicatorSv1SetActionProfile = "ReplicatorSv1.SetActionProfile" ReplicatorSv1SetDispatcherHost = "ReplicatorSv1.SetDispatcherHost" ReplicatorSv1SetLoadIDs = "ReplicatorSv1.SetLoadIDs" @@ -1306,7 +1276,6 @@ const ( ReplicatorSv1RemoveAttributeProfile = "ReplicatorSv1.RemoveAttributeProfile" ReplicatorSv1RemoveChargerProfile = "ReplicatorSv1.RemoveChargerProfile" ReplicatorSv1RemoveDispatcherProfile = "ReplicatorSv1.RemoveDispatcherProfile" - ReplicatorSv1RemoveRateProfile = "ReplicatorSv1.RemoveRateProfile" ReplicatorSv1RemoveActionProfile = "ReplicatorSv1.RemoveActionProfile" ReplicatorSv1RemoveDispatcherHost = "ReplicatorSv1.RemoveDispatcherHost" ReplicatorSv1GetIndexes = "ReplicatorSv1.GetIndexes" @@ -1480,14 +1449,6 @@ const ( APIerSv1GetAccount = "APIerSv1.GetAccount" APIerSv1GetAttributeProfileIDsCount = "APIerSv1.GetAttributeProfileIDsCount" APIerSv1GetMaxUsage = "APIerSv1.GetMaxUsage" - APIerSv1GetTPActionProfile = "APIerSv1.GetTPActionProfile" - APIerSv1SetTPActionProfile = "APIerSv1.SetTPActionProfile" - APIerSv1GetTPActionProfileIDs = "APIerSv1.GetTPActionProfileIDs" - APIerSv1RemoveTPActionProfile = "APIerSv1.RemoveTPActionProfile" - APIerSv1GetTPRateProfile = "APIerSv1.GetTPRateProfile" - APIerSv1SetTPRateProfile = "APIerSv1.SetTPRateProfile" - APIerSv1GetTPRateProfileIds = "APIerSv1.GetTPRateProfileIds" - APIerSv1RemoveTPRateProfile = "APIerSv1.RemoveTPRateProfile" ) // APIerSv1 TP APIs @@ -1731,17 +1692,6 @@ const ( RegistrarSv1UnregisterRPCHosts = "RegistrarSv1.UnregisterRPCHosts" ) -// RateProfile APIs -const ( - APIerSv1SetRateProfile = "APIerSv1.SetRateProfile" - APIerSv1GetRateProfile = "APIerSv1.GetRateProfile" - APIerSv1GetRateProfileIDs = "APIerSv1.GetRateProfileIDs" - APIerSv1GetRateProfileIDsCount = "APIerSv1.GetRateProfileIDsCount" - APIerSv1RemoveRateProfile = "APIerSv1.RemoveRateProfile" - APIerSv1SetRateProfileRates = "APIerSv1.SetRateProfileRates" - APIerSv1RemoveRateProfileRates = "APIerSv1.RemoveRateProfileRates" -) - // AnalyzerS APIs const ( AnalyzerSv1 = "AnalyzerSv1" @@ -1866,7 +1816,6 @@ const ( ChargersCsv = "Chargers.csv" DispatcherProfilesCsv = "DispatcherProfiles.csv" DispatcherHostsCsv = "DispatcherHosts.csv" - RateProfilesCsv = "RateProfiles.csv" ActionProfilesCsv = "ActionProfiles.csv" ) @@ -1896,67 +1845,61 @@ const ( OldSMCosts = "sm_costs" TBLTPDispatchers = "tp_dispatcher_profiles" TBLTPDispatcherHosts = "tp_dispatcher_hosts" - TBLTPRateProfiles = "tp_rate_profiles" TBLTPActionProfiles = "tp_action_profiles" ) // Cache Name const ( - CacheDestinations = "*destinations" - CacheReverseDestinations = "*reverse_destinations" - CacheRatingPlans = "*rating_plans" - CacheRatingProfiles = "*rating_profiles" - CacheActions = "*actions" - CacheActionPlans = "*action_plans" - CacheAccountActionPlans = "*account_action_plans" - CacheActionTriggers = "*action_triggers" - CacheSharedGroups = "*shared_groups" - CacheResources = "*resources" - CacheResourceProfiles = "*resource_profiles" - CacheTimings = "*timings" - CacheEventResources = "*event_resources" - CacheStatQueueProfiles = "*statqueue_profiles" - CacheStatQueues = "*statqueues" - CacheThresholdProfiles = "*threshold_profiles" - CacheThresholds = "*thresholds" - CacheFilters = "*filters" - CacheRouteProfiles = "*route_profiles" - CacheAttributeProfiles = "*attribute_profiles" - CacheChargerProfiles = "*charger_profiles" - CacheDispatcherProfiles = "*dispatcher_profiles" - CacheDispatcherHosts = "*dispatcher_hosts" - CacheDispatchers = "*dispatchers" - CacheDispatcherRoutes = "*dispatcher_routes" - CacheDispatcherLoads = "*dispatcher_loads" - CacheRateProfiles = "*rate_profiles" - CacheActionProfiles = "*action_profiles" - CacheResourceFilterIndexes = "*resource_filter_indexes" - CacheStatFilterIndexes = "*stat_filter_indexes" - CacheThresholdFilterIndexes = "*threshold_filter_indexes" - CacheRouteFilterIndexes = "*route_filter_indexes" - CacheAttributeFilterIndexes = "*attribute_filter_indexes" - CacheChargerFilterIndexes = "*charger_filter_indexes" - CacheDispatcherFilterIndexes = "*dispatcher_filter_indexes" - CacheDiameterMessages = "*diameter_messages" - CacheRPCResponses = "*rpc_responses" - CacheClosedSessions = "*closed_sessions" - CacheRateProfilesFilterIndexes = "*rate_profile_filter_indexes" - CacheActionProfilesFilterIndexes = "*action_profile_filter_indexes" - CacheRateFilterIndexes = "*rate_filter_indexes" - MetaPrecaching = "*precaching" - MetaReady = "*ready" - CacheLoadIDs = "*load_ids" - CacheRPCConnections = "*rpc_connections" - CacheCDRIDs = "*cdr_ids" - CacheRatingProfilesTmp = "*tmp_rating_profiles" - CacheUCH = "*uch" - CacheSTIR = "*stir" - CacheEventCharges = "*event_charges" - CacheReverseFilterIndexes = "*reverse_filter_indexes" - CacheAccounts = "*accounts" - CacheVersions = "*versions" - CacheCapsEvents = "*caps_events" - CacheReplicationHosts = "*replication_hosts" + CacheDestinations = "*destinations" + CacheReverseDestinations = "*reverse_destinations" + CacheRatingPlans = "*rating_plans" + CacheRatingProfiles = "*rating_profiles" + CacheActions = "*actions" + CacheActionPlans = "*action_plans" + CacheAccountActionPlans = "*account_action_plans" + CacheActionTriggers = "*action_triggers" + CacheSharedGroups = "*shared_groups" + CacheResources = "*resources" + CacheResourceProfiles = "*resource_profiles" + CacheTimings = "*timings" + CacheEventResources = "*event_resources" + CacheStatQueueProfiles = "*statqueue_profiles" + CacheStatQueues = "*statqueues" + CacheThresholdProfiles = "*threshold_profiles" + CacheThresholds = "*thresholds" + CacheFilters = "*filters" + CacheRouteProfiles = "*route_profiles" + CacheAttributeProfiles = "*attribute_profiles" + CacheChargerProfiles = "*charger_profiles" + CacheDispatcherProfiles = "*dispatcher_profiles" + CacheDispatcherHosts = "*dispatcher_hosts" + CacheDispatchers = "*dispatchers" + CacheDispatcherRoutes = "*dispatcher_routes" + CacheDispatcherLoads = "*dispatcher_loads" + CacheResourceFilterIndexes = "*resource_filter_indexes" + CacheStatFilterIndexes = "*stat_filter_indexes" + CacheThresholdFilterIndexes = "*threshold_filter_indexes" + CacheRouteFilterIndexes = "*route_filter_indexes" + CacheAttributeFilterIndexes = "*attribute_filter_indexes" + CacheChargerFilterIndexes = "*charger_filter_indexes" + CacheDispatcherFilterIndexes = "*dispatcher_filter_indexes" + CacheDiameterMessages = "*diameter_messages" + CacheRPCResponses = "*rpc_responses" + CacheClosedSessions = "*closed_sessions" + MetaPrecaching = "*precaching" + MetaReady = "*ready" + CacheLoadIDs = "*load_ids" + CacheRPCConnections = "*rpc_connections" + CacheCDRIDs = "*cdr_ids" + CacheRatingProfilesTmp = "*tmp_rating_profiles" + CacheUCH = "*uch" + CacheSTIR = "*stir" + CacheEventCharges = "*event_charges" + CacheReverseFilterIndexes = "*reverse_filter_indexes" + CacheAccounts = "*accounts" + CacheVersions = "*versions" + CacheCapsEvents = "*caps_events" + CacheReplicationHosts = "*replication_hosts" // storDB CacheTBLTPTimings = "*tp_timings" @@ -1981,7 +1924,6 @@ const ( CacheTBLTPChargers = "*tp_chargers" CacheTBLTPDispatchers = "*tp_dispatcher_profiles" CacheTBLTPDispatcherHosts = "*tp_dispatcher_hosts" - CacheTBLTPRateProfiles = "*tp_rate_profiles" CacheTBLTPActionProfiles = "*tp_action_profiles" ) @@ -1995,8 +1937,6 @@ const ( DispatcherFilterIndexes = "dfi_" ActionPlanIndexes = "api_" RouteFilterIndexes = "rti_" - RateProfilesFilterIndexPrfx = "rpi_" - RateFilterIndexPrfx = "rri_" ActionProfilesFilterIndexPrfx = "aci_" FilterIndexPrfx = "fii_" ) @@ -2606,42 +2546,38 @@ const ( // ArgCache constats const ( - DestinationIDs = "DestinationIDs" - ReverseDestinationIDs = "ReverseDestinationIDs" - RatingPlanIDs = "RatingPlanIDs" - RatingProfileIDs = "RatingProfileIDs" - ActionIDs = "ActionIDs" - ActionPlanIDs = "ActionPlanIDs" - AccountActionPlanIDs = "AccountActionPlanIDs" - ActionTriggerIDs = "ActionTriggerIDs" - SharedGroupIDs = "SharedGroupIDs" - ResourceProfileIDs = "ResourceProfileIDs" - ResourceIDs = "ResourceIDs" - StatsQueueIDs = "StatsQueueIDs" - StatsQueueProfileIDs = "StatsQueueProfileIDs" - ThresholdIDs = "ThresholdIDs" - ThresholdProfileIDs = "ThresholdProfileIDs" - FilterIDs = "FilterIDs" - RouteProfileIDs = "RouteProfileIDs" - AttributeProfileIDs = "AttributeProfileIDs" - ChargerProfileIDs = "ChargerProfileIDs" - DispatcherProfileIDs = "DispatcherProfileIDs" - DispatcherHostIDs = "DispatcherHostIDs" - DispatcherRoutesIDs = "DispatcherRoutesIDs" - RateProfileIDs = "RateProfileIDs" - ActionProfileIDs = "ActionProfileIDs" - TimingIDs = "TimingIDs" - AttributeFilterIndexIDs = "AttributeFilterIndexIDs" - ResourceFilterIndexIDs = "ResourceFilterIndexIDs" - StatFilterIndexIDs = "StatFilterIndexIDs" - ThresholdFilterIndexIDs = "ThresholdFilterIndexIDs" - RouteFilterIndexIDs = "RouteFilterIndexIDs" - ChargerFilterIndexIDs = "ChargerFilterIndexIDs" - DispatcherFilterIndexIDs = "DispatcherFilterIndexIDs" - RateProfilesFilterIndexIDs = "RateProfilesFilterIndexIDs" - RateFilterIndexIDs = "RateFilterIndexIDs" - ActionProfilesFilterIndexIDs = "ActionProfilesFilterIndexIDs" - FilterIndexIDs = "FilterIndexIDs" + DestinationIDs = "DestinationIDs" + ReverseDestinationIDs = "ReverseDestinationIDs" + RatingPlanIDs = "RatingPlanIDs" + RatingProfileIDs = "RatingProfileIDs" + ActionIDs = "ActionIDs" + ActionPlanIDs = "ActionPlanIDs" + AccountActionPlanIDs = "AccountActionPlanIDs" + ActionTriggerIDs = "ActionTriggerIDs" + SharedGroupIDs = "SharedGroupIDs" + ResourceProfileIDs = "ResourceProfileIDs" + ResourceIDs = "ResourceIDs" + StatsQueueIDs = "StatsQueueIDs" + StatsQueueProfileIDs = "StatsQueueProfileIDs" + ThresholdIDs = "ThresholdIDs" + ThresholdProfileIDs = "ThresholdProfileIDs" + FilterIDs = "FilterIDs" + RouteProfileIDs = "RouteProfileIDs" + AttributeProfileIDs = "AttributeProfileIDs" + ChargerProfileIDs = "ChargerProfileIDs" + DispatcherProfileIDs = "DispatcherProfileIDs" + DispatcherHostIDs = "DispatcherHostIDs" + DispatcherRoutesIDs = "DispatcherRoutesIDs" + ActionProfileIDs = "ActionProfileIDs" + TimingIDs = "TimingIDs" + AttributeFilterIndexIDs = "AttributeFilterIndexIDs" + ResourceFilterIndexIDs = "ResourceFilterIndexIDs" + StatFilterIndexIDs = "StatFilterIndexIDs" + ThresholdFilterIndexIDs = "ThresholdFilterIndexIDs" + RouteFilterIndexIDs = "RouteFilterIndexIDs" + ChargerFilterIndexIDs = "ChargerFilterIndexIDs" + DispatcherFilterIndexIDs = "DispatcherFilterIndexIDs" + FilterIndexIDs = "FilterIndexIDs" ) // Poster and Event reader constants diff --git a/utils/eventcharges.go b/utils/eventcharges.go deleted file mode 100644 index 2151bc10c..000000000 --- a/utils/eventcharges.go +++ /dev/null @@ -1,253 +0,0 @@ -/* -Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package utils - -import ( - "errors" -) - -// NewEventChargers instantiates the EventChargers in a central place -func NewEventCharges() (ec *EventCharges) { - ec = &EventCharges{ - Accounting: make(map[string]*AccountCharge), - Rating: make(map[string]*RateSInterval), - } - return -} - -// EventCharges records the charges applied to an Event -type EventCharges struct { - Abstracts *Decimal // total abstract units charged - Concretes *Decimal // total concrete units charged - - ChargingIntervals []*ChargingInterval - - Accounting map[string]*AccountCharge - Rating map[string]*RateSInterval -} - -// Merge will merge the event charges into existing -func (ec *EventCharges) Merge(eCs ...*EventCharges) { - for _, nEc := range eCs { - if ec.Abstracts != nil { - ec.Abstracts = &Decimal{SumBig(ec.Abstracts.Big, nEc.Abstracts.Big)} - } else { // initial - ec.Abstracts = nEc.Abstracts - } - if ec.Concretes != nil { - ec.Concretes = &Decimal{SumBig(ec.Concretes.Big, nEc.Concretes.Big)} - } else { // initial - ec.Concretes = nEc.Concretes - } - ec.AppendChargingIntervals(ec.ChargingIntervals...) - } -} - -// SyncIDs will repopulate Accounting, UnitFactors and Rating IDs if they equal the references in ec -func (ec *EventCharges) SyncIDs(eCs ...*EventCharges) { - for _, nEc := range eCs { - for _, cIl := range nEc.ChargingIntervals { - for _, cIcrm := range cIl.Increments { - - nEcAcntChrg := nEc.Accounting[cIcrm.AccountChargeID] - - // Rating - if nEcAcntChrg.RatingID != EmptyString { - if rtID := ec.RatingID(nEc.Rating[nEcAcntChrg.RatingID]); rtID != EmptyString && - rtID != nEcAcntChrg.RatingID { - nEc.Rating[rtID] = ec.Rating[rtID] - delete(nEc.Rating, nEcAcntChrg.RatingID) - nEcAcntChrg.RatingID = rtID - } - } - - // AccountCharges - for i, chrgID := range nEc.Accounting[cIcrm.AccountChargeID].JoinedChargeIDs { - if acntChrgID := ec.AccountChargeID(nEc.Accounting[chrgID]); acntChrgID != chrgID { - // matched the AccountChargeID with an existing one in reference ec, replace in nEc - nEc.Accounting[acntChrgID] = ec.Accounting[acntChrgID] - delete(nEc.Accounting, chrgID) - nEc.Accounting[cIcrm.AccountChargeID].JoinedChargeIDs[i] = acntChrgID - } - } - if acntChrgID := ec.AccountChargeID(nEcAcntChrg); acntChrgID != EmptyString && - acntChrgID != cIcrm.AccountChargeID { - // matched the AccountChargeID with an existing one in reference ec, replace in nEc - nEc.Accounting[acntChrgID] = ec.Accounting[cIcrm.AccountChargeID] - delete(nEc.Accounting, cIcrm.AccountChargeID) - cIcrm.AccountChargeID = acntChrgID - } - - } - } - } -} - -// AppendChargingIntervals will add new charging intervals to the existing. -// if possible, the existing last one in ec will be compressed -func (ec *EventCharges) AppendChargingIntervals(cIls ...*ChargingInterval) { - for i, cIl := range cIls { - if i == 0 && len(ec.ChargingIntervals) == 0 { - ec.ChargingIntervals = []*ChargingInterval{cIl} - continue - } - - if ec.ChargingIntervals[len(ec.ChargingIntervals)-1].CompressEquals(cIl) { - ec.ChargingIntervals[len(ec.ChargingIntervals)-1].CompressFactor += 1 - continue - } - ec.ChargingIntervals = append(ec.ChargingIntervals, cIl) - } -} - -// AsExtEventCharges converts EventCharges to ExtEventCharges -func (ec *EventCharges) AsExtEventCharges() (eEc *ExtEventCharges, err error) { - eEc = new(ExtEventCharges) - if ec.Abstracts != nil { - if flt, ok := ec.Abstracts.Big.Float64(); !ok { - return nil, errors.New("cannot convert decimal Abstracts to float64") - } else { - eEc.Abstracts = &flt - } - } - if ec.Concretes != nil { - if flt, ok := ec.Concretes.Big.Float64(); !ok { - return nil, errors.New("cannot convert decimal Concretes to float64") - } else { - eEc.Concretes = &flt - } - } - // add here code for the rest of the fields - return -} - -// RatingID returns the ID of the matching RateSInterval within ec.Rating -func (ec *EventCharges) RatingID(rIl *RateSInterval) (rID string) { - for ecID, ecRtIl := range ec.Rating { - if ecRtIl.Equals(rIl) { - return ecID - } - } - return -} - -// AccountChargeID returns the ID of the matching AccountCharge within ec.Accounting -func (ec *EventCharges) AccountChargeID(ac *AccountCharge) (acID string) { - for ecID, ecAc := range ec.Accounting { - if ecAc.Equals(ac) { - return ecID - } - } - return -} - -// ExtEventCharges is a generic EventCharges used in APIs -type ExtEventCharges struct { - Abstracts *float64 - Concretes *float64 -} - -type ChargingInterval struct { - Increments []*ChargingIncrement // specific increments applied to this interval - CompressFactor int -} - -// CompressEquals compares two ChargingIntervals for aproximate equality, ignoring compress field -func (cIl *ChargingInterval) CompressEquals(nCil *ChargingInterval) (eq bool) { - if len(cIl.Increments) != len(nCil.Increments) { - return - } - for i, chIr := range cIl.Increments { - if !chIr.CompressEquals(nCil.Increments[i]) { - return - } - } - return true -} - -// ChargingIncrement represents one unit charged inside an interval -type ChargingIncrement struct { - Units *Decimal // Can differ from AccountCharge due to JoinedCharging - AccountChargeID string // Account charging information - CompressFactor int -} - -func (cI *ChargingIncrement) CompressEquals(chIh *ChargingIncrement) (eq bool) { - if cI.Units == nil && chIh.Units != nil || - cI.Units != nil && chIh.Units == nil { - return - } - return cI.Units.Compare(chIh.Units) == 0 && - cI.AccountChargeID == chIh.AccountChargeID -} - -// AccountCharge represents one Account charge -type AccountCharge struct { - AccountID string - BalanceID string - Units *Decimal - BalanceLimit *Decimal // the minimum balance value accepted - UnitFactorID string // identificator in ChargingUnitFactors - AttributeIDs []string // list of attribute profiles matched - RatingID string // identificator in cost increments - JoinedChargeIDs []string // identificator of extra account charges -} - -// Equals compares two AccountCharges -func (ac *AccountCharge) Equals(nAc *AccountCharge) (eq bool) { - if ac.AttributeIDs == nil && nAc.AttributeIDs != nil || - ac.AttributeIDs != nil && nAc.AttributeIDs == nil || - len(ac.AttributeIDs) != len(nAc.AttributeIDs) { - return - } - for i := range ac.AttributeIDs { - if ac.AttributeIDs[i] != nAc.AttributeIDs[i] { - return - } - } - if ac.JoinedChargeIDs == nil && nAc.JoinedChargeIDs != nil || - ac.JoinedChargeIDs != nil && nAc.JoinedChargeIDs == nil || - len(ac.JoinedChargeIDs) != len(nAc.JoinedChargeIDs) { - return - } - for i := range ac.JoinedChargeIDs { - if ac.JoinedChargeIDs[i] != nAc.JoinedChargeIDs[i] { - return - } - } - if ac.AccountID != nAc.AccountID || - ac.BalanceID != nAc.BalanceID || - ac.UnitFactorID != nAc.UnitFactorID || - ac.RatingID != nAc.RatingID { - return - } - if ac.Units == nil && nAc.Units != nil || - ac.Units != nil && nAc.Units == nil { - return - } - if ac.BalanceLimit == nil && nAc.BalanceLimit != nil || - ac.BalanceLimit != nil && nAc.BalanceLimit == nil { - return - } - if ac.Units == nil && nAc.Units == nil || - ac.BalanceLimit == nil && nAc.BalanceLimit == nil { - return true - } - return ac.Units.Compare(nAc.Units) == 0 && ac.BalanceLimit.Compare(nAc.BalanceLimit) == 0 -} diff --git a/utils/eventcharges_test.go b/utils/eventcharges_test.go deleted file mode 100644 index e1ba878d7..000000000 --- a/utils/eventcharges_test.go +++ /dev/null @@ -1,366 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package utils - -import ( - "reflect" - "testing" - - "github.com/ericlagergren/decimal" -) - -func TestECNewEventCharges(t *testing.T) { - expected := &EventCharges{ - Accounting: make(map[string]*AccountCharge), - Rating: make(map[string]*RateSInterval), - } - received := NewEventCharges() - - if !reflect.DeepEqual(expected, received) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } -} - -func TestECMergeAbstractsEmpty(t *testing.T) { - ec1 := &EventCharges{ - Abstracts: &Decimal{decimal.New(1, 1)}, - Concretes: &Decimal{decimal.New(1, 1)}, - } - - ec2 := &EventCharges{ - Abstracts: &Decimal{decimal.New(2, 1)}, - Concretes: &Decimal{decimal.New(2, 1)}, - } - - received := &EventCharges{} - expected := &EventCharges{ - Abstracts: &Decimal{decimal.New(3, 1)}, - Concretes: &Decimal{decimal.New(3, 1)}, - } - received.Merge(ec1, ec2) - - if !reflect.DeepEqual(expected, received) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } -} - -func TestECMergeAbstracts(t *testing.T) { - ec1 := &EventCharges{ - Abstracts: &Decimal{decimal.New(1, 1)}, - Concretes: &Decimal{decimal.New(1, 1)}, - } - - ec2 := &EventCharges{ - Abstracts: &Decimal{decimal.New(2, 1)}, - Concretes: &Decimal{decimal.New(2, 1)}, - } - - received := &EventCharges{ - Abstracts: &Decimal{decimal.New(3, 1)}, - Concretes: &Decimal{decimal.New(3, 1)}, - } - expected := &EventCharges{ - Abstracts: &Decimal{decimal.New(6, 1)}, - Concretes: &Decimal{decimal.New(6, 1)}, - } - - received.Merge(ec1, ec2) - - if !reflect.DeepEqual(expected, received) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } -} - -func TestECAsExtEventChargesEmpty(t *testing.T) { - ec := &EventCharges{ - Abstracts: nil, - Concretes: nil, - } - - expected := &ExtEventCharges{ - Abstracts: nil, - Concretes: nil, - } - received, err := ec.AsExtEventCharges() - if err != nil { - t.Error(err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } - -} - -func TestECAsExtEventChargesSuccess(t *testing.T) { - ec := &EventCharges{ - Abstracts: &Decimal{ - decimal.New(1234, 3), - }, - Concretes: &Decimal{ - decimal.New(4321, 5), - }, - } - - expected := &ExtEventCharges{ - Abstracts: Float64Pointer(1.234), - Concretes: Float64Pointer(0.04321), - } - received, err := ec.AsExtEventCharges() - if err != nil { - t.Errorf("\nExpected: %v,\nReceived: %v", nil, err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf( - "\nExpected: <%v>,\nReceived: <%v>", - ToJSON(expected), - ToJSON(received), - ) - } -} - -func TestECAsExtEventChargesFailAbstracts(t *testing.T) { - v, _ := new(decimal.Big).SetString("900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993") - - ec := &EventCharges{ - Abstracts: &Decimal{v}, - Concretes: &Decimal{decimal.New(1234, 3)}, - } - - expected := "cannot convert decimal Abstracts to float64" - _, err := ec.AsExtEventCharges() - - if err == nil || err.Error() != expected { - t.Errorf("\nExpected: %v,\nReceived: %v", expected, err) - } -} - -func TestECAsExtEventChargesFailConcretes(t *testing.T) { - v, _ := new(decimal.Big).SetString("900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993900719925474099390071992547409939007199254740993") - - ec := &EventCharges{ - Abstracts: &Decimal{decimal.New(1234, 3)}, - Concretes: &Decimal{v}, - } - - expected := "cannot convert decimal Concretes to float64" - _, err := ec.AsExtEventCharges() - - if err == nil || err.Error() != expected { - t.Errorf("\nExpected: %v,\nReceived: %v", expected, err) - } -} - -func TestEqualsAccountCharge(t *testing.T) { - accCharge1 := &AccountCharge{ - AccountID: "AccountID1", - BalanceID: "BalanceID1", - Units: NewDecimal(20, 0), - BalanceLimit: NewDecimal(40, 0), - UnitFactorID: "UF1", - AttributeIDs: []string{"ID1", "ID2"}, - RatingID: "RatingID1", - JoinedChargeIDs: []string{"chID1"}, - } - accCharge2 := &AccountCharge{ - AccountID: "AccountID1", - BalanceID: "BalanceID1", - Units: NewDecimal(20, 0), - BalanceLimit: NewDecimal(40, 0), - UnitFactorID: "UF1", - AttributeIDs: []string{"ID1", "ID2"}, - RatingID: "RatingID1", - JoinedChargeIDs: []string{"chID1"}, - } - if !accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are not equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - - // not equal for AccountID - accCharge1.AccountID = "test" - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge1.AccountID = "AccountID1" - - accCharge2.AccountID = "test" - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge2.AccountID = "AccountID1" - - // not equal for BalanceID - accCharge1.BalanceID = "test" - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge1.BalanceID = "AccountID1" - - accCharge2.BalanceID = "test" - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge2.BalanceID = "AccountID1" - - // not equal for BalanceLimit - accCharge1.BalanceLimit = NewDecimal(35, 0) - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge1.BalanceLimit = NewDecimal(40, 0) - - accCharge2.BalanceLimit = NewDecimal(35, 0) - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge2.BalanceLimit = NewDecimal(40, 0) - - // not equal for Units - accCharge1.Units = NewDecimal(35, 0) - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge1.Units = NewDecimal(20, 0) - - accCharge2.Units = NewDecimal(35, 0) - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge2.Units = NewDecimal(20, 0) - - // not equal for AttributeIDs - accCharge1.AttributeIDs = []string{"ID1"} - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge1.AttributeIDs = []string{"ID1", "ID2"} - - accCharge2.AttributeIDs = []string{"ID1"} - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge2.AttributeIDs = []string{"ID1", "ID2"} - - // not equal for JoinedChargeIDs - accCharge1.JoinedChargeIDs = []string{} - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge1.JoinedChargeIDs = []string{"chID1"} - - accCharge2.JoinedChargeIDs = []string{} - if accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - accCharge2.JoinedChargeIDs = []string{"chID1"} - - //both units and BalanceLimit are nil will be equal - accCharge1.Units = nil - accCharge2.Units = nil - if !accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are not equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } - - accCharge1.BalanceLimit = nil - accCharge2.BalanceLimit = nil - if !accCharge1.Equals(accCharge2) { - t.Errorf("Charge %+v and %+v are not equal", ToJSON(accCharge1), ToJSON(accCharge2)) - } -} - -func TestCompressEqualsChargingInterval(t *testing.T) { - chIn1 := &ChargingInterval{ - Increments: []*ChargingIncrement{ - { - Units: NewDecimal(10, 0), - AccountChargeID: "CHARGER1", - CompressFactor: 1, - }, - }, - CompressFactor: 2, - } - chIn2 := &ChargingInterval{ - Increments: []*ChargingIncrement{ - { - Units: NewDecimal(10, 0), - AccountChargeID: "CHARGER1", - CompressFactor: 1, - }, - }, - CompressFactor: 4, - } - - // compressEquals is not looking for compress factor - if !chIn1.CompressEquals(chIn2) { - t.Errorf("Intervals %+v and %+v are not equal", ToJSON(chIn1), ToJSON(chIn2)) - } - - //same thing in ChargingIncrements - chIn1.Increments[0].CompressFactor = 2 - if !chIn1.CompressEquals(chIn2) { - t.Errorf("Intervals %+v and %+v are not equal", ToJSON(chIn1), ToJSON(chIn2)) - } - - //not equals for AccountChargeID - chIn1.Increments[0].AccountChargeID = "Changed_Charger" - if chIn1.CompressEquals(chIn2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(chIn1), ToJSON(chIn2)) - } - chIn1.Increments[0].AccountChargeID = "CHARGER1" - - chIn2.Increments[0].AccountChargeID = "Changed_Charger" - if chIn1.CompressEquals(chIn2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(chIn1), ToJSON(chIn2)) - } - chIn2.Increments[0].AccountChargeID = "CHARGER1" - - //not equals for Units - chIn1.Increments[0].Units = NewDecimal(30, 0) - if chIn1.CompressEquals(chIn2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(chIn1), ToJSON(chIn2)) - } - chIn1.Increments[0].Units = NewDecimal(10, 0) - - chIn2.Increments[0].Units = NewDecimal(30, 0) - if chIn1.CompressEquals(chIn2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(chIn1), ToJSON(chIn2)) - } - chIn2.Increments[0].Units = NewDecimal(10, 0) - - //not equals by the length of increments - chIn1 = &ChargingInterval{ - Increments: []*ChargingIncrement{ - { - Units: NewDecimal(10, 0), - AccountChargeID: "CHARGER1", - CompressFactor: 1, - }, - { - Units: NewDecimal(12, 0), - AccountChargeID: "CHARGER2", - CompressFactor: 6, - }, - }, - CompressFactor: 0, - } - if chIn1.CompressEquals(chIn2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(chIn1), ToJSON(chIn2)) - } -} diff --git a/utils/librates.go b/utils/librates.go deleted file mode 100644 index 13b55a82f..000000000 --- a/utils/librates.go +++ /dev/null @@ -1,387 +0,0 @@ -/* -Real-time Online/Offline Charging System (OerS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package utils - -import ( - "fmt" - "sort" - "time" - - "github.com/cgrates/cron" - "github.com/ericlagergren/decimal" -) - -// RateProfile represents the configuration of a Rate profile -type RateProfile struct { - Tenant string - ID string - FilterIDs []string - ActivationInterval *ActivationInterval - Weights DynamicWeights - MinCost *Decimal - MaxCost *Decimal - MaxCostStrategy string - Rates map[string]*Rate -} - -func (rp *RateProfile) TenantID() string { - return ConcatenatedKey(rp.Tenant, rp.ID) -} - -func (rp *RateProfile) Compile() (err error) { - for _, rtP := range rp.Rates { - rtP.uID = ConcatenatedKey(rp.Tenant, rp.ID, rtP.ID) - if err = rtP.Compile(); err != nil { - return - } - } - return -} - -// Rate defines rate related information used within a RateProfile -type Rate struct { - ID string // RateID - FilterIDs []string // RateFilterIDs - ActivationTimes string // ActivationTimes is a cron formatted time interval - Weights DynamicWeights // RateWeight will decide the winner per interval start - Blocker bool // RateBlocker will make this rate recurrent, deactivating further intervals - IntervalRates []*IntervalRate - - sched cron.Schedule // compiled version of activation times as cron.Schedule interface - uID string -} - -// UID returns system wide unique identifier -func (rt *Rate) UID() string { - return rt.uID -} - -type IntervalRate struct { - IntervalStart *Decimal // Starting point when the Rate kicks in - FixedFee *Decimal - RecurrentFee *Decimal - Unit *Decimal // RateUnit - Increment *Decimal // RateIncrement -} - -func (rt *Rate) Compile() (err error) { - aTime := rt.ActivationTimes - if aTime == EmptyString { - aTime = "* * * * *" - } - if rt.sched, err = cron.ParseStandard(aTime); err != nil { - return - } - return -} - -// RunTimes returns the set of activation and deactivation times for this rate on the interval between >=sTime and , sTime: <%+v>, eTime: <%+v>", - rt, sTime, eTime)) - return nil, ErrMaxIterationsReached -} - -// RateProfileWithAPIOpts is used in replicatorV1 for dispatcher -type RateProfileWithAPIOpts struct { - *RateProfile - APIOpts map[string]interface{} -} - -// RateSInterval is used by RateS to integrate Rate info for one charging interval -type RateSInterval struct { - IntervalStart *Decimal - Increments []*RateSIncrement - CompressFactor int64 - - cost *decimal.Big // unexported total interval cost -} - -type RateSIncrement struct { - IncrementStart *Decimal - Rate *Rate - IntervalRateIndex int - CompressFactor int64 - Usage *Decimal - - cost *decimal.Big // unexported total increment cost -} - -// Equals compares two RateSIntervals -func (rIl *RateSInterval) Equals(nRil *RateSInterval) (eq bool) { - if rIl.IntervalStart == nil && nRil.IntervalStart != nil || - rIl.IntervalStart != nil && nRil.IntervalStart == nil || - len(rIl.Increments) != len(nRil.Increments) { - return - } - if rIl.IntervalStart.Compare(nRil.IntervalStart) != 0 || - rIl.CompressFactor != nRil.CompressFactor { - return - } - for i, rtIn := range rIl.Increments { - if !rtIn.Equals(nRil.Increments[i]) { - return - } - } - return true -} - -func (rI *RateSIncrement) Equals(rtIn *RateSIncrement) (eq bool) { - if rI.Usage == nil && rtIn.Usage != nil || - rI.Usage != nil && rtIn.Usage == nil || - rI.IncrementStart == nil && rtIn.IncrementStart != nil || - rI.IncrementStart != nil && rtIn.IncrementStart == nil { - return - } - return rI.Usage.Compare(rtIn.Usage) == 0 && - rI.IncrementStart.Compare(rtIn.IncrementStart) == 0 && - rI.CompressFactor == rtIn.CompressFactor && - rI.IntervalRateIndex == rtIn.IntervalRateIndex && - rI.Rate.UID() == rtIn.Rate.UID() -} - -// RateProfileCost is the cost returned by RateS at cost queries -type RateProfileCost struct { - ID string // RateProfileID - Cost float64 - MinCost float64 - MaxCost float64 - MaxCostStrategy string - RateSIntervals []*RateSInterval - Altered []string -} - -// CorrectCost should be called in final phase of cost calculation -// in order to apply further correction like Min/MaxCost or rounding -func (rPc *RateProfileCost) CorrectCost(rndDec *int, rndMtd string) { - if rPc.MinCost != 0 && rPc.Cost < rPc.MinCost { - rPc.Cost = rPc.MinCost - rPc.Altered = append(rPc.Altered, MinCost) - } - if rPc.MaxCost != 0 && rPc.Cost > rPc.MaxCost { - rPc.Cost = rPc.MaxCost - rPc.Altered = append(rPc.Altered, MaxCost) - } - if rndDec != nil { - rPc.Cost = Round(rPc.Cost, *rndDec, rndMtd) - rPc.Altered = append(rPc.Altered, RoundingDecimals) - } -} - -// Sort will sort the IntervalRates from each Rate based on IntervalStart -func (rpp *RateProfile) Sort() { - for _, rate := range rpp.Rates { - sort.Slice(rate.IntervalRates, func(i, j int) bool { - return rate.IntervalRates[i].IntervalStart.Compare(rate.IntervalRates[j].IntervalStart) == -1 - }) - } -} - -// CompressEquals compares two RateSIntervals for Compress function -func (rIv *RateSInterval) CompressEquals(rIv2 *RateSInterval) (eq bool) { - if len(rIv.Increments) != len(rIv2.Increments) { - return - } - for i, rIcr := range rIv.Increments { - if !rIcr.CompressEquals(rIv2.Increments[i]) { - return - } - } - return true -} - -func (rIv *RateSInterval) Cost() *decimal.Big { - if rIv.cost == nil { - rIv.cost = new(decimal.Big) - for _, incrm := range rIv.Increments { - rIv.cost = SumBig(rIv.cost, incrm.Cost()) - } - } - return rIv.cost -} - -// CompressEquals compares two RateSIncrement for Compress function -func (rIcr *RateSIncrement) CompressEquals(rIcr2 *RateSIncrement) (eq bool) { - return rIcr.Rate.UID() == rIcr2.Rate.UID() && - rIcr.IntervalRateIndex == rIcr2.IntervalRateIndex && - rIcr.Usage.Big.Cmp(rIcr2.Usage.Big) == 0 -} - -// Cost computes the Cost on RateSIncrement -func (rIcr *RateSIncrement) Cost() *decimal.Big { - if rIcr.cost == nil { - icrRt := rIcr.Rate.IntervalRates[rIcr.IntervalRateIndex] - if rIcr.Usage.Compare(NewDecimal(-1, 0)) == 0 { // FixedFee - rIcr.cost = icrRt.FixedFee.Big - } else { - rIcr.cost = icrRt.RecurrentFee.Big - if icrRt.Unit != icrRt.Increment { - rIcr.cost = DivideBig( - MultiplyBig(rIcr.cost, icrRt.Increment.Big), - icrRt.Unit.Big) - } - if rIcr.CompressFactor != 1 { - rIcr.cost = MultiplyBig( - rIcr.cost, - new(decimal.Big).SetUint64(uint64(rIcr.CompressFactor))) - } - } - } - return rIcr.cost -} - -// CostForIntervals sums the costs for all intervals -func CostForIntervals(rtIvls []*RateSInterval) (cost *decimal.Big) { - cost = new(decimal.Big) - for _, rtIvl := range rtIvls { - cost = SumBig(cost, rtIvl.Cost()) - } - return -} - -// CompressIntervals will compress intervals which equal -func CompressIntervals(rtIvls []*RateSInterval) { -} - -func (ext *APIRateProfile) AsRateProfile() (rp *RateProfile, err error) { - rp = &RateProfile{ - Tenant: ext.Tenant, - ID: ext.ID, - FilterIDs: ext.FilterIDs, - ActivationInterval: ext.ActivationInterval, - MaxCostStrategy: ext.MaxCostStrategy, - } - if ext.Weights != EmptyString { - if rp.Weights, err = NewDynamicWeightsFromString(ext.Weights, ";", "&"); err != nil { - return nil, err - } - } - if ext.MinCost != nil { - rp.MinCost = NewDecimalFromFloat64(*ext.MinCost) - } - if ext.MaxCost != nil { - rp.MaxCost = NewDecimalFromFloat64(*ext.MaxCost) - } - if len(ext.Rates) != 0 { - rp.Rates = make(map[string]*Rate) - for key, extRate := range ext.Rates { - if rp.Rates[key], err = extRate.AsRate(); err != nil { - return - } - } - } - if err = rp.Compile(); err != nil { - return - } - return -} - -type APIRateProfile struct { - Tenant string - ID string - FilterIDs []string - ActivationInterval *ActivationInterval - Weights string - MinCost *float64 - MaxCost *float64 - MaxCostStrategy string - Rates map[string]*APIRate -} - -type APIRateProfileWithAPIOpts struct { - *APIRateProfile - APIOpts map[string]interface{} -} - -func (ext *APIRate) AsRate() (rate *Rate, err error) { - rate = &Rate{ - ID: ext.ID, - FilterIDs: ext.FilterIDs, - ActivationTimes: ext.ActivationTimes, - Blocker: ext.Blocker, - } - if ext.Weights != EmptyString { - if rate.Weights, err = NewDynamicWeightsFromString(ext.Weights, ";", "&"); err != nil { - return nil, err - } - } - if len(ext.IntervalRates) != 0 { - rate.IntervalRates = make([]*IntervalRate, len(ext.IntervalRates)) - for i, iRate := range ext.IntervalRates { - if rate.IntervalRates[i], err = iRate.AsIntervalRate(); err != nil { - return - } - } - } - return -} - -type APIRate struct { - ID string // RateID - FilterIDs []string // RateFilterIDs - ActivationTimes string // ActivationTimes is a cron formatted time interval - Weights string // RateWeight will decide the winner per interval start - Blocker bool // RateBlocker will make this rate recurrent, deactivating further intervals - IntervalRates []*APIIntervalRate -} - -func (ext *APIIntervalRate) AsIntervalRate() (iRate *IntervalRate, err error) { - iRate = new(IntervalRate) - if iRate.IntervalStart, err = NewDecimalFromUsage(ext.IntervalStart); err != nil { - return - } - if ext.FixedFee != nil { - iRate.FixedFee = NewDecimalFromFloat64(*ext.FixedFee) - } - if ext.RecurrentFee != nil { - iRate.RecurrentFee = NewDecimalFromFloat64(*ext.RecurrentFee) - } - if ext.Unit != nil { - iRate.Unit = NewDecimalFromFloat64(*ext.Unit) - } - if ext.Increment != nil { - iRate.Increment = NewDecimalFromFloat64(*ext.Increment) - } - return -} - -type APIIntervalRate struct { - IntervalStart string - FixedFee *float64 - RecurrentFee *float64 - Unit *float64 // RateUnit - Increment *float64 // RateIncrement -} diff --git a/utils/librates_test.go b/utils/librates_test.go deleted file mode 100644 index 0967a1fad..000000000 --- a/utils/librates_test.go +++ /dev/null @@ -1,1723 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package utils - -import ( - "reflect" - "testing" - "time" - - "github.com/cgrates/cron" - "github.com/ericlagergren/decimal" -) - -func TestLibratesTenantID(t *testing.T) { - rp := &RateProfile{ - Tenant: "tenant", - ID: "testID", - } - expected := rp.Tenant + ":" + rp.ID - received := rp.TenantID() - if received != expected { - t.Errorf("\nExpected: <%v>,\nReceived: <%v>", expected, received) - } -} - -func TestLibratesCompilerp(t *testing.T) { - // empty struct - rp := &RateProfile{} - err := rp.Compile() - if err != nil { - t.Errorf("\nExpected: <%v>, \nReceived: <%v>", nil, err) - } - - // non-empty - fail := "shouldfail" - rp.ID = "test" - rp.Tenant = "tenant" - rp.Rates = map[string]*Rate{ - "testKey1": { - ID: "ID1", - ActivationTimes: fail, - }, - "testKey2": { - ID: "ID2", - }, - } - - expected := "expected exactly 5 fields, found 1: [" + fail + "]" - err = rp.Compile() - - if err == nil || err.Error() != expected { - t.Errorf("\nExpected: <%v>, \nReceived: <%v>", expected, err) - } -} - -func TestLibratesUID(t *testing.T) { - rt := &Rate{ - uID: "testString", - } - - expected := "testString" - received := rt.UID() - - if received != expected { - t.Errorf("\nExpected: %q, \nReceived: %q", expected, received) - } - -} - -func TestLibratesCompilert(t *testing.T) { - rt := &Rate{ - ActivationTimes: EmptyString, - } - - err := rt.Compile() - - if err != nil { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", nil, err) - } -} - -func TestLibratesRunTimes(t *testing.T) { - var ( - sTime time.Time - eTime time.Time - verbosity int - ) - - // memory leak test - verbosity = 0 - - rt := &Rate{} - - received, err := rt.RunTimes(sTime, eTime, verbosity) - var expected [][]time.Time - - if err == nil || err != ErrMaxIterationsReached { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", ErrMaxIterationsReached, err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } - - // aTime after eTime test - schd, err := cron.ParseStandard("* * * * *") - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - - rt.sched = schd - verbosity = 10 - eTime = sTime.Add(10 * time.Minute) - - received, err = rt.RunTimes(sTime, eTime, verbosity) - - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } - - // eTime before iTime test - schd, err = cron.ParseStandard("* * 12 3 *") - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - - rt.sched = schd - sTime, err = time.Parse(time.RFC3339, "2022-03-11T15:04:05Z") - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - eTime = sTime.Add(24 * time.Hour) - - if received, err = rt.RunTimes(sTime, eTime, verbosity); err != nil { - t.Error(err) - } - - aT1, err := time.Parse(time.RFC3339, "2022-03-12T00:00:00Z") - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - - aT2, err := time.Parse(time.RFC3339, "2022-03-13T00:00:00Z") - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - - aTsl := make([]time.Time, 0) - aTsl = append(aTsl, aT1, aT2) - expected = append(expected, aTsl) - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } - - //eTime after iTime - schd, err = cron.ParseStandard("* * 12 3 *") - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - - rt.sched = schd - sTime, err = time.Parse(time.RFC3339, "2022-03-11T15:04:05Z") - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - eTime = sTime.Add(48 * time.Hour) - - received, err = rt.RunTimes(sTime, eTime, verbosity) - - if err != nil { - t.Errorf("\ndidn't expect error, got %v", err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } -} - -func TestLibratesCorrectCost(t *testing.T) { - - //CorrectCost does nothing - rPc := &RateProfileCost{ - Cost: 1.234, - MinCost: 1, - MaxCost: 2, - Altered: []string{}, - } - - expected := &RateProfileCost{ - Cost: 1.234, - MinCost: 1, - MaxCost: 2, - Altered: []string{}, - } - rPc.CorrectCost(nil, "") - - if !reflect.DeepEqual(rPc, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) - } - - //CorrectCost rounds the cost - expected = &RateProfileCost{ - Cost: 1.24, - MinCost: 1, - MaxCost: 2, - Altered: []string{RoundingDecimals}, - } - - rPc.CorrectCost(IntPointer(2), MetaRoundingUp) - - if !reflect.DeepEqual(rPc, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) - } - - //CorrectCost assigns MaxCost to Cost when Cost > MaxCost - - expected = &RateProfileCost{ - Cost: 2, - MinCost: 1, - MaxCost: 2, - Altered: []string{RoundingDecimals, MaxCost}, - } - rPc.Cost = 2.34 - rPc.CorrectCost(nil, "") - - if !reflect.DeepEqual(rPc, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) - } - - //CorrectCost assigns MinCost to Cost when Cost < MinCost - - expected = &RateProfileCost{ - Cost: 1, - MinCost: 1, - MaxCost: 2, - Altered: []string{RoundingDecimals, MaxCost, MinCost}, - } - rPc.Cost = 0.12 - rPc.CorrectCost(nil, "") - - if !reflect.DeepEqual(rPc, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, rPc) - } -} - -func TestRateProfileSort(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rPrf := &RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - Rates: map[string]*Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_Custom": { - ID: "RT_Custom", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(int64(time.Second), 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Second), 0), - RecurrentFee: NewDecimal(19, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(15*time.Second), 0), - RecurrentFee: NewDecimal(4, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(10*time.Second), 0), - RecurrentFee: NewDecimal(27, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(int64(10*time.Second), 0), - RecurrentFee: NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(18, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(18*time.Second), 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - exp := &RateProfile{ - Tenant: "cgrates.org", - ID: "RP1", - Rates: map[string]*Rate{ - "RT_WEEK": { - ID: "RT_WEEK", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_WEEKEND": { - ID: "RT_WEEKEND", - Weights: DynamicWeights{ - { - Weight: 10, - }, - }, - ActivationTimes: "* * * * 0,6", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(int64(10*time.Second), 0), - RecurrentFee: NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(18*time.Second), 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(18, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_Custom": { - ID: "RT_Custom", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * 1-5", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(int64(time.Second), 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Second), 0), - RecurrentFee: NewDecimal(19, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(10*time.Second), 0), - RecurrentFee: NewDecimal(27, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(15*time.Second), 0), - RecurrentFee: NewDecimal(4, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - "RT_CHRISTMAS": { - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(6, 2), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - }, - }, - } - rPrf.Sort() - if !reflect.DeepEqual(rPrf, exp) { - t.Errorf("Expected: %v,\n received: %v", ToJSON(exp), ToJSON(rPrf)) - } -} - -func TestRateProfileCompile(t *testing.T) { - rt := &RateProfile{ - Rates: map[string]*Rate{ - "randomVal1": { - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - }, - }, - Tenant: "cgrates.org", - ID: "RTP1", - } - expectedATime, err := cron.ParseStandard("* * 24 12 *") - if err != nil { - t.Fatal(err) - } - expRt := &RateProfile{ - Rates: map[string]*Rate{ - "randomVal1": { - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - sched: expectedATime, - uID: ConcatenatedKey(rt.Tenant, rt.ID, "RT_CHRISTMAS"), - }, - }, - Tenant: "cgrates.org", - ID: "RTP1", - } - if err := rt.Compile(); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rt, expRt) { - t.Errorf("Expected %+v, received %+v", ToJSON(expRt), ToJSON(rt)) - } -} - -func TestRateUID(t *testing.T) { - rt := &RateProfile{ - Rates: map[string]*Rate{ - "randomVal1": { - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - uID: "randomID", - }, - }, - } - expected := "randomID" - if newID := rt.Rates["randomVal1"].UID(); !reflect.DeepEqual(newID, expected) { - t.Errorf("Expected %+v, received %+v", expected, newID) - } -} - -func TestRateProfileCompileError(t *testing.T) { - rt := &RateProfile{ - Rates: map[string]*Rate{ - "randomVal": { - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * * *", - }, - }, - } - expectedErr := "expected exactly 5 fields, found 4: [* * * *]" - if err := rt.Compile(); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v ", expectedErr, err) - } -} - -func TestRateCompileChristmasTime(t *testing.T) { - rt := &Rate{ - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - } - expTime, err := cron.ParseStandard("* * 24 12 *") - if err != nil { - t.Error(err) - } - expectedRt := &Rate{ - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - sched: expTime, - } - if err := rt.Compile(); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expectedRt, rt) { - t.Errorf("Expected %+v, received %+v", expectedRt, rt) - } -} - -func TestRateCompileEmptyActivationTime(t *testing.T) { - rt := &Rate{ - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: EmptyString, - } - expTime, err := cron.ParseStandard("* * * * *") - if err != nil { - t.Error(err) - } - expectedRt := &Rate{ - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: EmptyString, - sched: expTime, - } - if err := rt.Compile(); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(rt, expectedRt) { - t.Errorf("Expected %+v, received %+v", expectedRt, rt) - } -} - -func TestRateProfileRunTimes(t *testing.T) { - rt := &Rate{ - ID: "RATE0", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - }, - }, - } - rt.Compile() - - sTime := time.Date(2020, time.June, 28, 18, 56, 05, 0, time.UTC) - eTime := sTime.Add(2 * time.Minute) - eRTimes := [][]time.Time{ - {time.Date(2020, time.June, 28, 18, 56, 0, 0, time.UTC), - time.Time{}}, - } - - if rTimes, err := rt.RunTimes(sTime, eTime, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eRTimes, rTimes) { - t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) - } - - rt = &Rate{ - ID: "RT_CHRISTMAS", - Weights: DynamicWeights{ - { - Weight: 30, - }, - }, - ActivationTimes: "* * 24 12 *", - } - rt.Compile() - - // sTime and eTime inside the activation interval - sTime = time.Date(2020, 12, 24, 12, 0, 0, 0, time.UTC) - eTime = sTime.Add(time.Hour) - eRTimes = [][]time.Time{ - {time.Date(2020, 12, 24, 12, 0, 0, 0, time.UTC), time.Date(2020, 12, 25, 0, 0, 0, 0, time.UTC)}, - } - if rTimes, err := rt.RunTimes(sTime, eTime, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eRTimes, rTimes) { - t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) - } - // sTime smaller than activation time, eTime equals aTime - sTime = time.Date(2020, 12, 23, 23, 0, 0, 0, time.UTC) - eTime = sTime.Add(time.Hour) - eRTimes = nil // cannot cover full interval - if rTimes, err := rt.RunTimes(sTime, eTime, 10); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eRTimes, rTimes) { - t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) - } - - // sTime smaller than activation time but first aTime inside, eTime inside activation interval - sTime = time.Date(2020, 12, 23, 23, 59, 59, 0, time.UTC) - eTime = sTime.Add(time.Hour) - eRTimes = [][]time.Time{ - {time.Date(2020, 12, 24, 0, 0, 0, 0, time.UTC), time.Date(2020, 12, 25, 0, 0, 0, 0, time.UTC)}, - } - if rTimes, err := rt.RunTimes(sTime, eTime, 1000000); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eRTimes, rTimes) { - t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) - } - - // sTime way before aTime, eTime inside aInterval - sTime = time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC) - eTime = time.Date(2021, 12, 24, 0, 1, 0, 0, time.UTC) - eRTimes = [][]time.Time{ - {time.Date(2021, 12, 24, 0, 0, 0, 0, time.UTC), time.Date(2021, 12, 25, 0, 0, 0, 0, time.UTC)}, - } - if rTimes, err := rt.RunTimes(sTime, eTime, 1000000); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(eRTimes, rTimes) { - t.Errorf("expecting: %+v, received: %+v", eRTimes, rTimes) - } -} - -func TestRateProfileRunTimesMaxIterations(t *testing.T) { - rt := &Rate{ - ID: "RATE0", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - }, - }, - ActivationTimes: "* * 24 12 *", - } - err := rt.Compile() - if err != nil { - t.Error(err) - } - sTime := time.Date(2020, 12, 24, 23, 30, 0, 0, time.UTC) - eTime := time.Date(2021, 12, 25, 23, 30, 0, 0, time.UTC) - expectedErr := "maximum iterations reached" - if _, err := rt.RunTimes(sTime, eTime, 2); err == nil || err.Error() != expectedErr { - t.Errorf("Expected %+v, received %+v", expectedErr, err) - } -} - -func TestRateProfileRunTimesPassingActivationTIme(t *testing.T) { - rt := &Rate{ - ID: "RATE0", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - }, - }, - ActivationTimes: "* * 24 * *", - } - err := rt.Compile() - if err != nil { - t.Error(err) - } - sTime := time.Date(2020, 12, 23, 0, 0, 0, 0, time.UTC) - eTime := time.Date(2020, 12, 27, 0, 0, 0, 0, time.UTC) - expectedTime := [][]time.Time{ - {time.Date(2020, 12, 24, 0, 0, 0, 0, time.UTC), time.Date(2020, 12, 25, 0, 0, 0, 0, time.UTC)}, - } - if rTimes, err := rt.RunTimes(sTime, eTime, 2); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expectedTime, rTimes) { - t.Errorf("Expected %+v, received %+v", expectedTime, rTimes) - } -} - -func TestCostForIntervals(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rt0 := &Rate{ - ID: "RATE0", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - Unit: minDecimal, - Increment: minDecimal, - RecurrentFee: NewDecimal(24, 1), - }, - { - IntervalStart: NewDecimal(int64(60*time.Second), 0), - Unit: minDecimal, - Increment: secDecimal, - RecurrentFee: NewDecimal(24, 1), - }, - }, - } - rt0.Compile() - rt1 := &Rate{ - ID: "RATE1", - IntervalRates: []*IntervalRate{ - { - - IntervalStart: NewDecimal(0, 0), - Unit: minDecimal, - Increment: secDecimal, - RecurrentFee: NewDecimal(12, 1), - }, - { - - IntervalStart: NewDecimal(int64(2*time.Minute), 0), - Unit: minDecimal, - Increment: secDecimal, - RecurrentFee: NewDecimal(6, 1), - }, - }, - } - rt1.Compile() - rtIvls := []*RateSInterval{ - { - IntervalStart: NewDecimal(0, 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rt0, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: NewDecimal(int64(time.Minute), 0), - Usage: NewDecimal(int64(30*time.Second), 0), - Rate: rt0, - IntervalRateIndex: 1, - CompressFactor: 30, - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: NewDecimal(int64(90*time.Second), 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(int64(90*time.Second), 0), - Usage: NewDecimal(int64(30*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 30, - }, - { - IncrementStart: NewDecimal(int64(2*time.Minute), 0), - Usage: NewDecimal(int64(10*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 10, - }, - }, - CompressFactor: 1, - }, - } - eDcml, _ := new(decimal.Big).SetFloat64(4.3).Float64() - if cost, _ := CostForIntervals(rtIvls).Float64(); cost != eDcml { - t.Errorf("eDcml: %f, received: %+v", eDcml, cost) - } -} - -func TestCostForIntervalsWIthFixedFee(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rt0 := &Rate{ - ID: "RATE0", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - FixedFee: NewDecimal(4, 1), - RecurrentFee: NewDecimal(24, 1), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(60*time.Second), 0), - RecurrentFee: NewDecimal(24, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rt0.Compile() - rt1 := &Rate{ - ID: "RATE1", - IntervalRates: []*IntervalRate{ - { - - IntervalStart: NewDecimal(0, 0), - FixedFee: NewDecimal(2, 1), - RecurrentFee: NewDecimal(12, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - { - IntervalStart: NewDecimal(int64(2*time.Minute), 0), - RecurrentFee: NewDecimal(6, 1), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rt1.Compile() - rtIvls := []*RateSInterval{ - { - IntervalStart: NewDecimal(0, 0), - Increments: []*RateSIncrement{ - { // cost 0,4 - IncrementStart: NewDecimal(0, 0), - Rate: rt0, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: NewDecimal(-1, 0), - }, - { // cost 2,4 - IncrementStart: NewDecimal(0, 0), - Rate: rt0, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: NewDecimal(int64(time.Minute), 0), - }, - { // cost 1,2 - IncrementStart: NewDecimal(int64(time.Minute), 0), - Rate: rt0, - IntervalRateIndex: 1, - CompressFactor: 30, - Usage: NewDecimal(int64(30*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - { - IntervalStart: NewDecimal(int64(90*time.Second), 0), - Increments: []*RateSIncrement{ - { // cost 0,2 - IncrementStart: NewDecimal(int64(90*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 1, - Usage: NewDecimal(-1, 0), - }, - { // cost 0,6 - IncrementStart: NewDecimal(int64(90*time.Second), 0), - Rate: rt1, - IntervalRateIndex: 0, - CompressFactor: 30, - Usage: NewDecimal(int64(30*time.Second), 0), - }, - { // cost 0,1 - IncrementStart: NewDecimal(int64(2*time.Minute), 0), - Rate: rt1, - IntervalRateIndex: 1, - CompressFactor: 10, - Usage: NewDecimal(int64(10*time.Second), 0), - }, - }, - CompressFactor: 1, - }, - } - eDcml, _ := new(decimal.Big).SetFloat64(4.9).Float64() - if cost, _ := CostForIntervals(rtIvls).Float64(); cost != eDcml { - t.Errorf("eDcml: %f, received: %+v", eDcml, cost) - } -} - -func TestRateProfileCostCorrectCost(t *testing.T) { - rPrfCost := &RateProfileCost{ - ID: "Test1", - Cost: 0.234, - } - rPrfCost.CorrectCost(IntPointer(2), MetaRoundingUp) - if rPrfCost.Cost != 0.24 { - t.Errorf("Expected: %+v, received: %+v", 0.24, rPrfCost.Cost) - } - if !reflect.DeepEqual(rPrfCost.Altered, []string{RoundingDecimals}) { - t.Errorf("Expected: %+v, received: %+v", []string{RoundingDecimals}, rPrfCost.Altered) - } - -} - -func TestRateProfileCostCorrectCostMinCost(t *testing.T) { - testRPC := &RateProfileCost{ - Cost: 0.5, - MinCost: 1.5, - } - testRPC.CorrectCost(IntPointer(2), "") - if testRPC.Cost != 1.5 { - t.Errorf("\nExpecting: <1.5>,\n Received: <%+v>", testRPC.Cost) - } -} - -func TestRateProfileCostCorrectCostMaxCost(t *testing.T) { - testRPC := &RateProfileCost{ - Cost: 2.5, - MaxCost: 1.5, - } - testRPC.CorrectCost(IntPointer(2), "") - if testRPC.Cost != 1.5 { - t.Errorf("\nExpecting: <1.5>,\n Received: <%+v>", testRPC.Cost) - } -} - -func TestRateSIncrementCompressEquals(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(6, 3), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - uID: "testUID", - } - inCr1 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - } - inCr2 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - } - result := inCr1.CompressEquals(inCr2) - if result != true { - t.Errorf("\nExpecting: ,\n Received: <%+v>", result) - } -} - -func TestRateSIncrementCompressEqualsCase1(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rate1 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - uID: "ID", - } - rate2 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - uID: "ID2", - } - inCr1 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - } - inCr2 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate2, - IntervalRateIndex: 0, - CompressFactor: 1, - } - result := inCr1.CompressEquals(inCr2) - if result != false { - t.Errorf("\nExpecting: ,\n Received: <%+v>", result) - } -} -func TestRateSIncrementCompressEqualsCase2(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rate1 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - } - inCr1 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - } - inCr2 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 1, - } - result := inCr1.CompressEquals(inCr2) - if result != false { - t.Errorf("\nExpecting: ,\n Received: <%+v>", result) - } -} - -func TestRateSIncrementCompressEqualsCase3(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - rate1 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - } - inCr1 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Second), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 1, - } - inCr2 := &RateSIncrement{ - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 1, - } - result := inCr1.CompressEquals(inCr2) - if result != false { - t.Errorf("\nExpecting: ,\n Received: <%+v>", result) - } -} - -func TestRateSIntervalCompressEqualsCase1(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(6, 3), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rateSintrv1 := &RateSInterval{ - IntervalStart: NewDecimal(0, 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: NewDecimal(int64(time.Minute), 0), - Usage: NewDecimal(int64(time.Minute+10*time.Second), 0), - Rate: rate1, - IntervalRateIndex: 1, - CompressFactor: 70, - }, - }, - CompressFactor: 1, - } - - rateSintrv2 := &RateSInterval{ - IntervalStart: NewDecimal(0, 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - }, - CompressFactor: 1, - } - result := rateSintrv1.CompressEquals(rateSintrv2) - if result != false { - t.Errorf("\nExpecting ,\nReceived <%+v>", result) - } -} - -func TestRateSIntervalCompressEqualsCase2(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - secDecimal, err := NewDecimalFromUsage("1s") - if err != nil { - t.Error(err) - } - rate1 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(6, 3), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rate2 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - { - IntervalStart: NewDecimal(int64(time.Minute), 0), - RecurrentFee: NewDecimal(6, 3), - Unit: minDecimal, - Increment: secDecimal, - }, - }, - } - rateSintrv1 := &RateSInterval{ - IntervalStart: NewDecimal(0, 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Second), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - }, - CompressFactor: 1, - } - - rateSintrv2 := &RateSInterval{ - IntervalStart: NewDecimal(1, 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate2, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate2, - IntervalRateIndex: 2, - CompressFactor: 1, - }, - }, - CompressFactor: 0, - } - result := rateSintrv1.CompressEquals(rateSintrv2) - if result != false { - t.Errorf("\nExpecting ,\nReceived <%+v>", result) - } -} - -func TestRateSIntervalCompressEqualsCase3(t *testing.T) { - minDecimal, err := NewDecimalFromUsage("1m") - if err != nil { - t.Error(err) - } - - rate1 := &Rate{ - ID: "RATE1", - Weights: DynamicWeights{ - { - Weight: 0, - }, - }, - ActivationTimes: "* * * * *", - IntervalRates: []*IntervalRate{ - { - IntervalStart: NewDecimal(0, 0), - RecurrentFee: NewDecimal(12, 2), - Unit: minDecimal, - Increment: minDecimal, - }, - }, - } - rateSintrv1 := &RateSInterval{ - IntervalStart: NewDecimal(0, 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(0, 0), - Usage: NewDecimal(int64(time.Minute), 0), - Rate: rate1, - IntervalRateIndex: 0, - CompressFactor: 1, - }, - }, - CompressFactor: 1, - } - - rateSintrv2 := &RateSInterval{ - IntervalStart: NewDecimal(0, 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(0, 0), - Rate: rate1, - Usage: NewDecimal(int64(time.Minute), 0), - IntervalRateIndex: 0, - CompressFactor: 1, - }, - }, - CompressFactor: 1, - } - result := rateSintrv1.CompressEquals(rateSintrv2) - if result != true { - t.Errorf("\nExpecting ,\nReceived <%+v>", result) - } -} - -func TestLibratesAsRateProfile(t *testing.T) { - // Invalid DynamicWeights string - ext := &APIRateProfile{ - Weights: "testWeight", - } - rp := &RateProfile{ - Tenant: ext.Tenant, - ID: ext.ID, - FilterIDs: ext.FilterIDs, - ActivationInterval: ext.ActivationInterval, - MaxCostStrategy: ext.MaxCostStrategy, - } - - received, err := ext.AsRateProfile() - experr := "invalid DynamicWeight format for string " - - if err == nil || err.Error() != experr { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", experr, err) - } - - if received != nil { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", nil, received) - } - - // No changes - ext.Weights = EmptyString - - expected := rp - received, err = ext.AsRateProfile() - - if err != nil { - t.Errorf("\nExpected nil, got <%+v>", err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } - - // assign MinCost to rp - ext.MinCost = Float64Pointer(1) - - expected.MinCost = NewDecimal(1, 0) - received, err = ext.AsRateProfile() - - if err != nil { - t.Errorf("\nExpected nil, got <%+v>", err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } - - // assign MaxCost to rp - ext.MaxCost = Float64Pointer(2) - - expected.MaxCost = NewDecimal(2, 0) - received, err = ext.AsRateProfile() - - if err != nil { - t.Errorf("\nExpected nil, got <%+v>", err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>", expected, received) - } -} - -func TestLibratesAsRateProfileNon0Len(t *testing.T) { - id := "testID" - ext := &APIRateProfile{ - Rates: map[string]*APIRate{ - "testKey": { - ID: id, - Weights: "testWeight", - }, - }, - } - rp := &RateProfile{ - Tenant: ext.Tenant, - ID: ext.ID, - FilterIDs: ext.FilterIDs, - ActivationInterval: ext.ActivationInterval, - MaxCostStrategy: ext.MaxCostStrategy, - } - - expected := rp - expected.Rates = map[string]*Rate{ - "testKey": nil, - } - received, err := ext.AsRateProfile() - - if err.Error() != "invalid DynamicWeight format for string " { - t.Errorf("\nExpected nil, got <%+v>", err) - } - - if !reflect.DeepEqual(received, expected) { - t.Errorf("\nExpected: <%v>, \nReceived: <%v>", expected, received) - } -} - -func TestRatesIntervalEquals(t *testing.T) { - rtInt1 := &RateSInterval{ - IntervalStart: NewDecimal(int64(10*time.Second), 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(int64(time.Second), 0), - IntervalRateIndex: 1, - Rate: &Rate{ - uID: "newID", - }, - CompressFactor: 2, - Usage: NewDecimal(int64(5*time.Second), 0), - }, - }, - CompressFactor: 2, - } - rtInt2 := &RateSInterval{ - IntervalStart: NewDecimal(int64(10*time.Second), 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(int64(time.Second), 0), - IntervalRateIndex: 1, - Rate: &Rate{ - uID: "newID", - }, - CompressFactor: 2, - Usage: NewDecimal(int64(5*time.Second), 0), - }, - }, - CompressFactor: 2, - } - - // equals is looking for compressFactor - if !rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are not equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } - - // not equals for IntervalStart - rtInt1.IntervalStart = NewDecimal(int64(20*time.Second), 0) - if rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } - rtInt1.IntervalStart = NewDecimal(int64(10*time.Second), 0) - - rtInt2.IntervalStart = NewDecimal(int64(20*time.Second), 0) - if rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } - rtInt2.IntervalStart = NewDecimal(int64(10*time.Second), 0) - - // not equals for CompressFactor - rtInt1.CompressFactor = 5 - if rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } - rtInt1.CompressFactor = 2 - - rtInt2.CompressFactor = 8 - if rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } - rtInt2.CompressFactor = 2 - - //not equals for Increments and their length - rtInt1.Increments[0].Usage = NewDecimal(int64(90*time.Second), 0) - if rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } - rtInt1.Increments[0].Usage = NewDecimal(int64(5*time.Second), 0) - - rtInt2.Increments[0].Usage = NewDecimal(int64(80*time.Second), 0) - if rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } - rtInt2.Increments[0].Usage = NewDecimal(int64(5*time.Second), 0) - - rtInt1 = &RateSInterval{ - IntervalStart: NewDecimal(int64(10*time.Second), 0), - Increments: []*RateSIncrement{ - { - IncrementStart: NewDecimal(int64(time.Second), 0), - IntervalRateIndex: 1, - Rate: &Rate{ - uID: "newID", - }, - CompressFactor: 2, - Usage: NewDecimal(int64(5*time.Second), 0), - }, - { - IncrementStart: NewDecimal(int64(time.Second), 0), - Usage: NewDecimal(int64(5*time.Second), 0), - }, - }, - CompressFactor: 2, - } - if rtInt1.Equals(rtInt2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(rtInt1), ToJSON(rtInt2)) - } -} - -func TestRatesIncrementEquals(t *testing.T) { - incr1 := &RateSIncrement{ - IncrementStart: NewDecimal(int64(time.Second), 0), - IntervalRateIndex: 1, - Rate: &Rate{ - uID: "newID", - }, - CompressFactor: 2, - Usage: NewDecimal(int64(5*time.Second), 0), - } - incr2 := &RateSIncrement{ - IncrementStart: NewDecimal(int64(time.Second), 0), - IntervalRateIndex: 1, - Rate: &Rate{ - uID: "newID", - }, - CompressFactor: 2, - Usage: NewDecimal(int64(5*time.Second), 0), - } - - // equals is not looking for compress factor - if !incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are not equal", ToJSON(incr1), ToJSON(incr2)) - } - - // not equals by IncrementStart - incr1.IncrementStart = NewDecimal(int64(10*time.Second), 0) - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr1.IncrementStart = NewDecimal(int64(time.Second), 0) - - incr2.IncrementStart = NewDecimal(int64(10*time.Second), 0) - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr2.IncrementStart = NewDecimal(int64(time.Second), 0) - - // not equals by IntervalRateIndex - incr1.IntervalRateIndex = 5 - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr1.IntervalRateIndex = 1 - - incr2.IntervalRateIndex = 5 - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr2.IntervalRateIndex = 1 - - //not equals by RateUID - incr1.Rate.uID = "changed_uID" - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr1.Rate.uID = "newID" - - incr2.Rate.uID = "changed_uID" - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr2.Rate.uID = "newID" - - // not equals by CompressFactor - incr1.CompressFactor = 0 - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr1.CompressFactor = 2 - - incr2.CompressFactor = 9 - if incr1.Equals(incr2) { - t.Errorf("Intervals %+v and %+v are equal", ToJSON(incr1), ToJSON(incr2)) - } - incr2.CompressFactor = 2 -}