From 3d7c5ed2013424d83e8289b765372a2add7e8eb9 Mon Sep 17 00:00:00 2001 From: armirveliaj Date: Tue, 24 Sep 2024 10:51:14 -0400 Subject: [PATCH] Add coverage tests on engine --- engine/libtrends_test.go | 251 +++++++++++++++++++++++++++++++++++++++ engine/rankings_test.go | 126 ++++++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 engine/libtrends_test.go create mode 100644 engine/rankings_test.go diff --git a/engine/libtrends_test.go b/engine/libtrends_test.go new file mode 100644 index 000000000..b4fd03937 --- /dev/null +++ b/engine/libtrends_test.go @@ -0,0 +1,251 @@ +/* +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 engine + +import ( + "reflect" + "testing" + "time" + + "github.com/cgrates/cgrates/utils" +) + +func TestTrendProfileClone(t *testing.T) { + + original := &TrendProfile{ + Tenant: "cgrates.org", + ID: "ID", + Schedule: "Schedule", + StatID: "StatID", + Metrics: []string{"metric1", "metric2"}, + TTL: 10 * time.Minute, + QueueLength: 100, + MinItems: 10, + CorrelationType: "average", + Tolerance: 0.05, + Stored: true, + ThresholdIDs: []string{"thresh1", "thresh2"}, + } + + cloned := original.Clone() + + if cloned.Tenant != original.Tenant { + t.Errorf("Expected Tenant %s, but got %s", original.Tenant, cloned.Tenant) + } + if cloned.ID != original.ID { + t.Errorf("Expected ID %s, but got %s", original.ID, cloned.ID) + } + if cloned.Schedule != original.Schedule { + t.Errorf("Expected Schedule %s, but got %s", original.Schedule, cloned.Schedule) + } + if cloned.StatID != original.StatID { + t.Errorf("Expected StatID %s, but got %s", original.StatID, cloned.StatID) + } + if cloned.QueueLength != original.QueueLength { + t.Errorf("Expected QueueLength %d, but got %d", original.QueueLength, cloned.QueueLength) + } + if cloned.TTL != original.TTL { + t.Errorf("Expected TTL %v, but got %v", original.TTL, cloned.TTL) + } + if cloned.MinItems != original.MinItems { + t.Errorf("Expected MinItems %d, but got %d", original.MinItems, cloned.MinItems) + } + if cloned.CorrelationType != original.CorrelationType { + t.Errorf("Expected CorrelationType %s, but got %s", original.CorrelationType, cloned.CorrelationType) + } + if cloned.Tolerance != original.Tolerance { + t.Errorf("Expected Tolerance %f, but got %f", original.Tolerance, cloned.Tolerance) + } + if cloned.Stored != original.Stored { + t.Errorf("Expected Stored %v, but got %v", original.Stored, cloned.Stored) + } + + if !reflect.DeepEqual(cloned.Metrics, original.Metrics) { + t.Errorf("Expected Metrics %v, but got %v", original.Metrics, cloned.Metrics) + } + if !reflect.DeepEqual(cloned.ThresholdIDs, original.ThresholdIDs) { + t.Errorf("Expected ThresholdIDs %v, but got %v", original.ThresholdIDs, cloned.ThresholdIDs) + } + + if len(cloned.Metrics) > 0 && &cloned.Metrics[0] == &original.Metrics[0] { + t.Errorf("Metrics slice was not deep copied") + } + if len(cloned.ThresholdIDs) > 0 && &cloned.ThresholdIDs[0] == &original.ThresholdIDs[0] { + t.Errorf("ThresholdIDs slice was not deep copied") + } +} + +func TestTrendProfileTenantIDAndTrendProfileWithAPIOpts(t *testing.T) { + + tp := &TrendProfile{ + Tenant: "cgrates.org", + ID: "trend1", + Schedule: "*/5 * * * *", + StatID: "StatID", + Metrics: []string{"metric1", "metric2"}, + TTL: 10 * time.Minute, + QueueLength: 100, + MinItems: 10, + CorrelationType: "average", + Tolerance: 0.05, + Stored: true, + ThresholdIDs: []string{"thresh1", "thresh2"}, + } + + tenantID := tp.TenantID() + + expectedTenantID := "cgrates.org" + utils.ConcatenatedKeySep + "trend1" + if tenantID != expectedTenantID { + t.Errorf("Expected TenantID %s, but got %s", expectedTenantID, tenantID) + } + + apiOpts := map[string]any{ + "option1": "value1", + "option2": 42, + } + + tpWithAPIOpts := &TrendProfileWithAPIOpts{ + TrendProfile: tp, + APIOpts: apiOpts, + } + + if tpWithAPIOpts.Tenant != "cgrates.org" { + t.Errorf("Expected Tenant %s, but got %s", "cgrates.org", tpWithAPIOpts.Tenant) + } + if tpWithAPIOpts.ID != "trend1" { + t.Errorf("Expected ID %s, but got %s", "trend1", tpWithAPIOpts.ID) + } + + expectedAPIOpts := map[string]any{ + "option1": "value1", + "option2": 42, + } + if !reflect.DeepEqual(tpWithAPIOpts.APIOpts, expectedAPIOpts) { + t.Errorf("Expected APIOpts %v, but got %v", expectedAPIOpts, tpWithAPIOpts.APIOpts) + } + +} + +func TestIndexesAppendMetric(t *testing.T) { + + trend := &Trend{ + mLast: make(map[string]time.Time), + mCounts: make(map[string]int), + mTotals: make(map[string]float64), + } + + metric1 := &MetricWithTrend{ID: "metric1", Value: 5.0} + metric2 := &MetricWithTrend{ID: "metric2", Value: 3.0} + + rTime1 := time.Now() + rTime2 := rTime1.Add(10 * time.Minute) + + trend.indexesAppendMetric(metric1, rTime1) + trend.indexesAppendMetric(metric2, rTime2) + trend.indexesAppendMetric(metric1, rTime2) + + expectedMLast := map[string]time.Time{ + "metric1": rTime2, + "metric2": rTime2, + } + if !reflect.DeepEqual(trend.mLast, expectedMLast) { + t.Errorf("Expected mLast %v, but got %v", expectedMLast, trend.mLast) + } + + expectedMCounts := map[string]int{ + "metric1": 2, + "metric2": 1, + } + if !reflect.DeepEqual(trend.mCounts, expectedMCounts) { + t.Errorf("Expected mCounts %v, but got %v", expectedMCounts, trend.mCounts) + } + + expectedMTotals := map[string]float64{ + "metric1": 10.0, + "metric2": 3.0, + } + if !reflect.DeepEqual(trend.mTotals, expectedMTotals) { + t.Errorf("Expected mTotals %v, but got %v", expectedMTotals, trend.mTotals) + } +} + +func TestTrendTenantID(t *testing.T) { + trend := &Trend{ + Tenant: "cgrates.org", + ID: "ID", + RunTimes: []time.Time{ + time.Now(), + time.Now().Add(-1 * time.Hour), + }, + Metrics: map[time.Time]map[string]*MetricWithTrend{ + time.Now(): { + "metric1": {ID: "metric1", Value: 1.5}, + "metric2": {ID: "metric2", Value: 2.0}, + }, + time.Now().Add(-1 * time.Hour): { + "metric1": {ID: "metric1", Value: 1.0}, + }, + }, + CompressedMetrics: []byte{0x00, 0x01}, + mLast: map[string]time.Time{ + "metric1": time.Now(), + "metric2": time.Now().Add(-1 * time.Hour), + }, + mCounts: map[string]int{ + "metric1": 2, + "metric2": 1, + }, + mTotals: map[string]float64{ + "metric1": 2.5, + "metric2": 2.0, + }, + tP: &TrendProfile{ + Tenant: "cgrates.org", + ID: "trendProfileID", + Schedule: "0 * * * *", + StatID: "statID1", + QueueLength: 10, + TTL: 5 * time.Minute, + MinItems: 1, + CorrelationType: "average", + Tolerance: 0.1, + Stored: true, + ThresholdIDs: []string{"threshold1", "threshold2"}, + }, + } + + tenantID := trend.TenantID() + + expectedTenantID := "cgrates.org:ID" + if tenantID != expectedTenantID { + t.Errorf("Expected TenantID %v, but got %v", expectedTenantID, tenantID) + } + + if len(trend.RunTimes) != 2 { + t.Errorf("Expected 2 run times, but got %d", len(trend.RunTimes)) + } + + if len(trend.Metrics) != 2 { + t.Errorf("Expected 2 metrics time entries, but got %d", len(trend.Metrics)) + } + + if trend.tP.QueueLength != 10 { + t.Errorf("Expected QueueLength 10, but got %d", trend.tP.QueueLength) + } +} diff --git a/engine/rankings_test.go b/engine/rankings_test.go new file mode 100644 index 000000000..e4bd913bd --- /dev/null +++ b/engine/rankings_test.go @@ -0,0 +1,126 @@ +/* +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 engine + +import ( + "testing" + "time" + + "github.com/cgrates/cgrates/config" +) + +func TestTenantID(t *testing.T) { + rp := &RankingProfile{ + Tenant: "cgrates.org", + ID: "01", + QueryInterval: 5 * time.Minute, + StatIDs: []string{"stat1", "stat2"}, + MetricIDs: []string{"metric1"}, + Sorting: "asc", + SortingParameters: []string{"param1"}, + ThresholdIDs: []string{"threshold1"}, + } + + tenantID := rp.TenantID() + + expectedTenantID := "cgrates.org:01" + + if tenantID != expectedTenantID { + t.Errorf("TenantID() = %v; want %v", tenantID, expectedTenantID) + } +} + +func TestRankingProfileWithAPIOpts(t *testing.T) { + rp := &RankingProfile{ + Tenant: "cgrates.org", + ID: "ID", + QueryInterval: 5 * time.Minute, + StatIDs: []string{"stat1", "stat2"}, + MetricIDs: []string{"metric1"}, + Sorting: "asc", + SortingParameters: []string{"param1"}, + ThresholdIDs: []string{"threshold1"}, + } + + rpo := RankingProfileWithAPIOpts{ + RankingProfile: rp, + APIOpts: map[string]any{"option1": "value1"}, + } + + if rpo.APIOpts["option1"] != "value1" { + t.Errorf("APIOpts[option1] = %v; want %v", rpo.APIOpts["option1"], "value1") + } + + if rpo.Tenant != rp.Tenant { + t.Errorf("RankingProfile Tenant = %v; want %v", rpo.Tenant, rp.Tenant) + } + + if rpo.ID != rp.ID { + t.Errorf("RankingProfile ID = %v; want %v", rpo.ID, rp.ID) + } +} + +func TestRankingProfileLockKey(t *testing.T) { + tests := []struct { + tenant string + id string + expected string + }{ + {"cgrates.org", "01", "*ranking_profiles:cgrates.org:01"}, + {"cgrates.org", "02", "*ranking_profiles:cgrates.org:02"}, + {"cgrates.org", "03", "*ranking_profiles:cgrates.org:03"}, + } + + for _, test := range tests { + result := rankingProfileLockKey(test.tenant, test.id) + + if result != test.expected { + t.Errorf("rankingProfileLockKey(%q, %q) = %v; want %v", test.tenant, test.id, result, test.expected) + } + } +} + +func TestNewRankingService(t *testing.T) { + dm := &DataManager{} + cgrcfg := &config.CGRConfig{} + filterS := &FilterS{} + connMgr := &ConnManager{} + + rankingService := NewRankingService(dm, cgrcfg, filterS, connMgr) + + if rankingService == nil { + t.Fatal("NewRankingService() returned nil") + } + + if rankingService.dm != dm { + t.Errorf("Expected dm to be %v, got %v", dm, rankingService.dm) + } + + if rankingService.cfg != cgrcfg { + t.Errorf("Expected cfg to be %v, got %v", cgrcfg, rankingService.cfg) + } + + if rankingService.fltrS != filterS { + t.Errorf("Expected fltrS to be %v, got %v", filterS, rankingService.fltrS) + } + + if rankingService.connMgr != connMgr { + t.Errorf("Expected connMgr to be %v, got %v", connMgr, rankingService.connMgr) + } +}