diff --git a/apier/v1/stats_it_test.go b/apier/v1/stats_it_test.go index 912d27b41..030596a10 100644 --- a/apier/v1/stats_it_test.go +++ b/apier/v1/stats_it_test.go @@ -90,6 +90,7 @@ var ( testV1STSProcessCDRStat, testV1STSOverWriteStats, testV1STSProcessStatWithThreshold2, + testV1STSSimulateAccountUpdate, testV1STSStopEngine, } ) @@ -1328,3 +1329,124 @@ func testV1STSV1GetStatQueuesForEventWithoutTenant(t *testing.T) { t.Errorf("expecting: %+v, received reply: %v", estats, reply) } } + +func testV1STSSimulateAccountUpdate(t *testing.T) { + statConfig = &engine.StatQueueWithCache{ + StatQueueProfile: &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "StatForAccountUpdate", + FilterIDs: []string{ + "*string:~*opts.*eventType:AccountUpdate", + "*string:~*asm.ID:testV1STSSimulateAccountUpdate", + }, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + }, + QueueLength: 100, + TTL: time.Duration(1) * time.Second, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaSum + utils.HashtagSep + "~*asm.BalanceSummaries.HolidayBalance.Value", + }, + }, + ThresholdIDs: []string{"*none"}, + Blocker: true, + Stored: true, + Weight: 50, + MinItems: 1, + }, + } + //set the custom statProfile + var result string + if err := stsV1Rpc.Call(utils.APIerSv1SetStatQueueProfile, statConfig, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Error("Unexpected reply returned", result) + } + //verify it + var reply *engine.StatQueueProfile + if err := stsV1Rpc.Call(utils.APIerSv1GetStatQueueProfile, + &utils.TenantID{Tenant: "cgrates.org", ID: "StatForAccountUpdate"}, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(statConfig.StatQueueProfile, reply) { + t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(statConfig.StatQueueProfile), utils.ToJSON(reply)) + } + //verify metrics + var metrics map[string]string + expectedMetrics := map[string]string{ + utils.MetaSum + utils.HashtagSep + "~*asm.BalanceSummaries.HolidayBalance.Value": utils.NOT_AVAILABLE, + } + + var reply2 []string + expected := []string{"StatForAccountUpdate"} + + attrSetBalance := &utils.AttrSetBalance{ + Tenant: "cgrates.org", + Account: "testV1STSSimulateAccountUpdate", + BalanceType: "*monetary", + Value: 1.5, + Balance: map[string]interface{}{ + utils.ID: "HolidayBalance", + }, + } + if err := stsV1Rpc.Call(utils.APIerSv1SetBalance, attrSetBalance, &result); err != nil { + t.Error("Got error on APIerSv1.SetBalance: ", err.Error()) + } else if result != utils.OK { + t.Errorf("Calling APIerSv1.SetBalance received: %s", result) + } + + var acnt *engine.Account + attrs := &utils.AttrGetAccount{ + Tenant: "cgrates.org", + Account: "testV1STSSimulateAccountUpdate", + } + if err := stsV1Rpc.Call(utils.APIerSv2GetAccount, attrs, &acnt); err != nil { + t.Error(err) + } + + acntUpdateEv := &engine.StatsArgsProcessEvent{ + CGREventWithOpts: &utils.CGREventWithOpts{ + CGREvent: &utils.CGREvent{ // hitting TH_ACNT_UPDATE_EV + Tenant: "cgrates.org", + ID: "SIMULATE_ACNT_UPDATE_EV", + Event: acnt.AsAccountSummary().AsMapInterface(), + }, + Opts: map[string]interface{}{ + utils.MetaEventType: utils.AccountUpdate, + }, + }, + } + + if err := stsV1Rpc.Call(utils.StatSv1ProcessEvent, &acntUpdateEv, &reply2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply2, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, reply2) + } + //verify metrics after first process + expectedMetrics = map[string]string{ + utils.MetaSum + utils.HashtagSep + "~*asm.BalanceSummaries.HolidayBalance.Value": "1.5", + } + if err := stsV1Rpc.Call(utils.StatSv1GetQueueStringMetrics, + &utils.TenantIDWithOpts{ + TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "StatForAccountUpdate"}}, &metrics); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics, metrics) { + t.Errorf("expecting: %+v, received reply: %s", expectedMetrics, metrics) + } + //second process + if err := stsV1Rpc.Call(utils.StatSv1ProcessEvent, &acntUpdateEv, &reply2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(reply2, expected) { + t.Errorf("Expecting: %+v, received: %+v", expected, reply2) + } + expectedMetrics = map[string]string{ + utils.MetaSum + utils.HashtagSep + "~*asm.BalanceSummaries.HolidayBalance.Value": "3", + } + if err := stsV1Rpc.Call(utils.StatSv1GetQueueStringMetrics, + &utils.TenantIDWithOpts{ + TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "StatForAccountUpdate"}}, &metrics); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics, metrics) { + t.Errorf("expecting: %+v, received reply: %s", expectedMetrics, metrics) + } +} diff --git a/engine/libstats.go b/engine/libstats.go index 7baa1145e..9fa8a6c40 100644 --- a/engine/libstats.go +++ b/engine/libstats.go @@ -249,7 +249,8 @@ func (sq *StatQueue) addStatEvent(tnt, evID string, filterS *FilterS, evNm utils }{evID, expTime}) var pass bool // recreate the request without *opts - req := utils.MapStorage{utils.MetaReq: evNm[utils.MetaReq]} + dDP := newDynamicDP(config.CgrConfig().FilterSCfg().ResourceSConns, config.CgrConfig().FilterSCfg().StatSConns, + config.CgrConfig().FilterSCfg().ApierSConns, tnt, utils.MapStorage{utils.MetaReq: evNm[utils.MetaReq]}) for metricID, metric := range sq.SQMetrics { if pass, err = filterS.Pass(tnt, metric.GetFilterIDs(), evNm); err != nil { @@ -257,7 +258,7 @@ func (sq *StatQueue) addStatEvent(tnt, evID string, filterS *FilterS, evNm utils } else if !pass { continue } - if err = metric.AddEvent(evID, req); err != nil { + if err = metric.AddEvent(evID, dDP); err != nil { utils.Logger.Warning(fmt.Sprintf(" metricID: %s, add eventID: %s, error: %s", metricID, evID, err.Error())) return