diff --git a/engine/libtrends_test.go b/engine/libtrends_test.go index bf00c5f1c..645c8a674 100644 --- a/engine/libtrends_test.go +++ b/engine/libtrends_test.go @@ -90,3 +90,82 @@ func TestTrendGetTrendLabel(t *testing.T) { t.Errorf("Expecting: <%q> got <%q>", expct, lbl) } } + +func TestTrendCleanUp(t *testing.T) { + tests := []struct { + name string + ttl time.Duration + qLength int + runtimes int + want bool + }{ + { + name: "No Clean up", + ttl: 2 * time.Minute, + qLength: 10, + want: false, + runtimes: 5, + }, + { + name: "Clean up with TTL", + ttl: 1 * time.Second, + qLength: 10, + want: true, + runtimes: 3, + }, + { + name: "No clean up", + ttl: 1 * time.Second, + qLength: 10, + want: false, + runtimes: 3, + }, + { + name: "Clean up with queue length", + ttl: 1 * time.Second, + qLength: 2, + want: true, + runtimes: 2, + }, + { + name: "No clean up with negative ttl", + ttl: -1, + qLength: 2, + want: false, + runtimes: 2, + }, + } + now := time.Now() + t1 := now.Add(-time.Minute) + t2 := now.Add(-time.Second) + t3 := now.Add(time.Second) + t4 := now.Add(2 * time.Second) + t5 := now.Add(time.Minute) + trend := &Trend{ + tMux: new(sync.RWMutex), + Tenant: "cgrates.org", + ID: "TestTrendCleanUp", + + RunTimes: []time.Time{t1, t2, t3, t4, t5}, + Metrics: map[time.Time]map[string]*MetricWithTrend{ + t1: {utils.MetaACC: {utils.MetaACC, 10.1, -1.0, utils.NotAvailable}, utils.MetaTCC: {utils.MetaTCC, 10.1, -1.0, utils.NotAvailable}}, + t2: {utils.MetaACC: {utils.MetaACC, 15.1, 4.0, utils.MetaPositive}, utils.MetaTCC: {utils.MetaTCC, 25.1, 15.1, utils.MetaPositive}}, + t3: {utils.MetaACC: {utils.MetaACC, 12.1, -1.0, utils.NotAvailable}, utils.MetaTCC: {utils.MetaTCC, 34, -1.0, utils.NotAvailable}}, + t4: {utils.MetaACC: {utils.MetaACC, 19.1, 4.0, utils.MetaPositive}, utils.MetaTCC: {utils.MetaTCC, 48, 15.1, utils.MetaPositive}}, + t5: {utils.MetaACC: {utils.MetaACC, 117.1, -1.0, utils.NotAvailable}, utils.MetaTCC: {utils.MetaTCC, 56, -1.0, utils.NotAvailable}}, + }} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + altered := trend.cleanup(tt.ttl, tt.qLength) + if altered != tt.want { + t.Errorf("cleanup() = %v, want %v", altered, tt.want) + return + } + if len(trend.RunTimes) != tt.runtimes { + t.Errorf("runTimes length = %v, want %v", len(trend.RunTimes), tt.runtimes) + } + }) + + } +} diff --git a/engine/trends.go b/engine/trends.go index c8f7068e4..da59e20b5 100644 --- a/engine/trends.go +++ b/engine/trends.go @@ -41,7 +41,7 @@ func NewTrendS(dm *DataManager, cgrcfg: cgrcfg, crn: cron.New(), loopStopped: make(chan struct{}), - crnTQsMux: &sync.RWMutex{}, + crnTQsMux: new(sync.RWMutex), crnTQs: make(map[string]map[string]cron.EntryID), } } diff --git a/general_tests/trends_schedule_it_test.go b/general_tests/trends_schedule_it_test.go index 1983e67fe..cd2afef54 100644 --- a/general_tests/trends_schedule_it_test.go +++ b/general_tests/trends_schedule_it_test.go @@ -72,7 +72,7 @@ func TestTrendSchedule(t *testing.T) { tpFiles := map[string]string{ utils.TrendsCsv: `#Tenant[0],Id[1],Schedule[2],StatID[3],Metrics[4],TTL[5],QueueLength[6],MinItems[7],CorrelationType[8],Tolerance[9],Stored[10],ThresholdIDs[11] cgrates.org,TREND_1,@every 1s,Stats1_1,,-1,-1,1,*last,1,false, -cgrates.org,TREND_2,@every 1s,Stats1_2,,-1,-1,1,*last,1,false,`, +cgrates.org,TREND_2,@every 2s,Stats1_2,,-1,-1,1,*last,1,false,`, utils.StatsCsv: `#Tenant[0],Id[1],FilterIDs[2],ActivationInterval[3],QueueLength[4],TTL[5],MinItems[6],Metrics[7],MetricFilterIDs[8],Stored[9],Blocker[10],Weight[11],ThresholdIDs[12] cgrates.org,Stats1_1,*string:~*req.Account:1001,,,,,*tcc;*acd;*tcd,,,,, cgrates.org,Stats1_2,*string:~*req.Account:1002,,,,,*sum#~*req.Usage;*pdd,,,,,`} @@ -95,19 +95,21 @@ cgrates.org,Stats1_2,*string:~*req.Account:1002,,,,,*sum#~*req.Usage;*pdd,,,,,`} }) t.Run("ProcessStats", func(t *testing.T) { var reply []string - if err := client.Call(context.Background(), utils.StatSv1ProcessEvent, &utils.CGREvent{ - Tenant: "cgrates.org", - ID: fmt.Sprintf("event%d", 1), - Event: map[string]any{ - utils.AccountField: "1001", - utils.AnswerTime: time.Date(2024, 8, 22, 14, 25, 0, 0, time.UTC), - utils.Usage: time.Duration(rand.Intn(3600)+60) * time.Second, - utils.Cost: rand.Float64()*20 + 0.1, - utils.PDD: time.Duration(rand.Intn(20)+1) * time.Second, - }}, &reply); err != nil { - t.Error(err) + for i := range 2 { + i = i + 1 + if err := client.Call(context.Background(), utils.StatSv1ProcessEvent, &utils.CGREvent{ + Tenant: "cgrates.org", + ID: fmt.Sprintf("event%d", i), + Event: map[string]any{ + utils.AccountField: fmt.Sprintf("100%d", i), + utils.AnswerTime: time.Date(2024, 8, 22, 14, 25, 0, 0, time.UTC), + utils.Usage: time.Duration(rand.Intn(3600)+60) * time.Second, + utils.Cost: rand.Float64()*20 + float64(i/10), + utils.PDD: time.Duration(rand.Intn(10)+i) * time.Second, + }}, &reply); err != nil { + t.Error(err) + } } - }) time.Sleep(1 * time.Second) t.Run("TestGetTrend", func(t *testing.T) { @@ -117,21 +119,30 @@ cgrates.org,Stats1_2,*string:~*req.Account:1002,,,,,*sum#~*req.Usage;*pdd,,,,,`} } else if len(tr.RunTimes) != 1 && len(tr.Metrics) != 1 { t.Error("expected metrics to be calculated") } + + if err := client.Call(context.Background(), utils.TrendSv1GetTrend, &utils.ArgGetTrend{ID: "TREND_2", TenantWithAPIOpts: utils.TenantWithAPIOpts{Tenant: "cgrates.org"}}, &tr); err != nil { + t.Error(err) + } else if len(tr.RunTimes) != 0 && len(tr.Metrics) != 0 { + t.Error("expected no metrics to be calculated") + } }) t.Run("ProcessStats", func(t *testing.T) { var reply []string - if err := client.Call(context.Background(), utils.StatSv1ProcessEvent, &utils.CGREvent{ - Tenant: "cgrates.org", - ID: fmt.Sprintf("event%d", 2), - Event: map[string]any{ - utils.AccountField: "1001", - utils.AnswerTime: time.Date(2024, 9, 22, 14, 25, 0, 0, time.UTC), - utils.Usage: time.Duration(rand.Intn(3600)+60) * time.Second / 2, - utils.Cost: rand.Float64() * 30, - utils.PDD: time.Duration(rand.Intn(20)+4) * time.Second, - }}, &reply); err != nil { - t.Error(err) + for i := range 2 { + i = i + 1 + if err := client.Call(context.Background(), utils.StatSv1ProcessEvent, &utils.CGREvent{ + Tenant: "cgrates.org", + ID: fmt.Sprintf("event%d", i), + Event: map[string]any{ + utils.AccountField: fmt.Sprintf("100%d", i), + utils.AnswerTime: time.Date(2024, 9, 22, 14, 25, 0, 0, time.UTC), + utils.Usage: time.Duration(60) * time.Second / time.Duration(i), + utils.Cost: rand.Float64() * 30 * float64(i), + utils.PDD: time.Duration(rand.Intn(20)+i) * time.Second, + }}, &reply); err != nil { + t.Error(err) + } } }) @@ -149,5 +160,15 @@ cgrates.org,Stats1_2,*string:~*req.Account:1002,,,,,*sum#~*req.Usage;*pdd,,,,,`} } else if tr.Metrics[tr.RunTimes[1]]["*tcd"].TrendLabel != utils.MetaPositive { t.Error("expected TrendLabel to be positive") } + + if err := client.Call(context.Background(), utils.TrendSv1GetTrend, &utils.ArgGetTrend{ID: "TREND_2", TenantWithAPIOpts: utils.TenantWithAPIOpts{Tenant: "cgrates.org"}}, &tr); err != nil { + t.Error(err) + } else if len(tr.RunTimes) != 1 && len(tr.Metrics) != 1 { + t.Error("expected metrics to be calculated") + } else if tr.Metrics[tr.RunTimes[0]]["*sum#~*req.Usage"].TrendLabel != utils.NotAvailable { + t.Error("expected TrendLabel to be negative") + } else if tr.Metrics[tr.RunTimes[0]]["*pdd"].TrendLabel != utils.NotAvailable { + t.Error("expected TrendLabel to be positive") + } }) }