/* 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 TestRankingProfileTenantID(t *testing.T) { tests := []struct { name string profile RankingProfile expected string }{ { name: "Tenant and ID", profile: RankingProfile{Tenant: "cgrates.org", ID: "1"}, expected: "cgrates.org:1", }, { name: "Empty tenant", profile: RankingProfile{ID: "2"}, expected: ":2", }, { name: "Empty ID", profile: RankingProfile{Tenant: "cgrates.org"}, expected: "cgrates.org:", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := tc.profile.TenantID() if got != tc.expected { t.Errorf("TenantID() = %v, want %v", got, tc.expected) } }) } } func TestRankingProfileClone(t *testing.T) { original := &RankingProfile{ Tenant: "cgrates.org", ID: "ID1", Schedule: "@every 1sec", Sorting: "asc", } cloned := original.Clone() if cloned.Tenant != original.Tenant { t.Errorf("Expected Tenant %s, got %s", original.Tenant, cloned.Tenant) } if cloned.ID != original.ID { t.Errorf("Expected ID %s, got %s", original.ID, cloned.ID) } if cloned.Schedule != original.Schedule { t.Errorf("Expected Schedule %s, got %s", original.Schedule, cloned.Schedule) } if cloned.Sorting != original.Sorting { t.Errorf("Expected Sorting %s, got %s", original.Sorting, cloned.Sorting) } if cloned == original { t.Error("Clone should return a new instance, but it returned the same reference") } } func TestNewRankingFromProfile(t *testing.T) { profile := &RankingProfile{ Tenant: "cgrates.org", ID: "ID1", Sorting: "asc", MetricIDs: []string{"metric1", "metric2"}, SortingParameters: []string{"param1", "param2"}, } ranking := NewRankingFromProfile(profile) if ranking.Tenant != profile.Tenant { t.Errorf("Expected Tenant %s, got %s", profile.Tenant, ranking.Tenant) } if ranking.ID != profile.ID { t.Errorf("Expected ID %s, got %s", profile.ID, ranking.ID) } if ranking.Sorting != profile.Sorting { t.Errorf("Expected Sorting %s, got %s", profile.Sorting, ranking.Sorting) } if ranking.Metrics == nil { t.Error("Expected Metrics map to be initialized, but it is nil") } expectedMetricIDs := utils.NewStringSet(profile.MetricIDs) if !ranking.metricIDs.Equals(expectedMetricIDs) { t.Errorf("Expected metricIDs %v, got %v", expectedMetricIDs, ranking.metricIDs) } if len(ranking.SortingParameters) != len(profile.SortingParameters) { t.Errorf("Expected SortingParameters length %d, got %d", len(profile.SortingParameters), len(ranking.SortingParameters)) } for i, param := range profile.SortingParameters { if ranking.SortingParameters[i] != param { t.Errorf("Expected SortingParameters[%d] %s, got %s", i, param, ranking.SortingParameters[i]) } } if ranking.rkPrfl != profile { t.Error("Expected rkPrfl to reference the original profile") } } func TestRankingTenantID(t *testing.T) { r := &Ranking{ Tenant: "cgrates.org", ID: "1", } expectedTenantID := "cgrates.org:1" actualTenantID := r.TenantID() if actualTenantID != expectedTenantID { t.Errorf("Expected tenant ID %s, got %s", expectedTenantID, actualTenantID) } } func TestRanking_asRankingSummary(t *testing.T) { rk := &Ranking{ Tenant: "cgrates.org", ID: "ID1", LastUpdate: time.Now(), SortedStatIDs: []string{"stat1", "stat2", "stat3"}, } rkSummary := rk.asRankingSummary() if rkSummary.Tenant != rk.Tenant { t.Errorf("Expected Tenant %s, but got %s", rk.Tenant, rkSummary.Tenant) } if rkSummary.ID != rk.ID { t.Errorf("Expected ID %s, but got %s", rk.ID, rkSummary.ID) } if !rkSummary.LastUpdate.Equal(rk.LastUpdate) { t.Errorf("Expected LastUpdate %v, but got %v", rk.LastUpdate, rkSummary.LastUpdate) } if !reflect.DeepEqual(rkSummary.SortedStatIDs, rk.SortedStatIDs) { t.Errorf("Expected SortedStatIDs %v, but got %v", rk.SortedStatIDs, rkSummary.SortedStatIDs) } if &rkSummary.SortedStatIDs == &rk.SortedStatIDs { t.Errorf("Expected SortedStatIDs slice to be copied, not referenced") } } func TestRankingSortStats(t *testing.T) { metrics := map[string]map[string]float64{ "stat1": { "metric1": 5.0, "metric2": 10.0, }, "stat2": { "metric1": 3.0, "metric2": 12.0, }, "stat3": { "metric1": 7.0, "metric2": 8.0, }, } tests := []struct { name string sortingType string sortingParams []string expectedOrder []string expectError bool }{ { name: "Sort Descending by metric1", sortingType: utils.MetaDesc, sortingParams: []string{"metric1"}, expectedOrder: []string{"stat3", "stat1", "stat2"}, expectError: false, }, { name: "Sort Ascending by metric2", sortingType: utils.MetaAsc, sortingParams: []string{"metric2"}, expectedOrder: []string{"stat3", "stat1", "stat2"}, expectError: false, }, { name: "Unsupported sorting type", sortingType: "unsupported", sortingParams: []string{"metric1"}, expectedOrder: nil, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sortedStatIDs, err := rankingSortStats(tt.sortingType, tt.sortingParams, metrics) if tt.expectError { if err == nil { t.Errorf("expected error but got nil") } return } if err != nil { t.Errorf("unexpected error: %v", err) return } for i, id := range sortedStatIDs { if id != tt.expectedOrder[i] { t.Errorf("expected sorted statID %v at index %d, got %v", tt.expectedOrder[i], i, id) } } }) } }