/* 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see */ package config import ( "reflect" "testing" "time" "github.com/cgrates/cgrates/utils" ) func TestLoadFromJSONCfgs(t *testing.T) { tests := []struct { name string input *TrendsJsonCfg expected *TrendSCfg expectedErr bool }{ { name: "Test with MetaInternal in Stats_conns and EEs_conns", input: &TrendsJsonCfg{ Enabled: utils.BoolPointer(true), Stats_conns: &[]string{"conn1", utils.MetaInternal}, Thresholds_conns: &[]string{"thresh1"}, Scheduled_ids: map[string][]string{"tenant1": {"id1"}}, Store_interval: utils.StringPointer("1s"), Ees_conns: &[]string{"ees1", utils.MetaInternal}, Ees_exporter_ids: &[]string{"exporter1", "exporter2"}, }, expected: &TrendSCfg{ Enabled: true, StatSConns: []string{"conn1", utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)}, ThresholdSConns: []string{"thresh1"}, ScheduledIDs: map[string][]string{"tenant1": {"id1"}}, StoreInterval: time.Second, EEsConns: []string{"ees1", utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs)}, EEsExporterIDs: []string{"exporter1", "exporter2"}, }, }, { name: "Test with MetaInternal in Thresholds_conns", input: &TrendsJsonCfg{ Enabled: utils.BoolPointer(true), Stats_conns: &[]string{"conn1"}, Thresholds_conns: &[]string{"thresh1", utils.MetaInternal}, Scheduled_ids: map[string][]string{"tenant1": {"id1"}}, Store_interval: utils.StringPointer("2s"), Ees_conns: &[]string{"ees1"}, Ees_exporter_ids: &[]string{"exporter1"}, }, expected: &TrendSCfg{ Enabled: true, StatSConns: []string{"conn1"}, ThresholdSConns: []string{"thresh1", utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}, ScheduledIDs: map[string][]string{"tenant1": {"id1"}}, StoreInterval: 2 * time.Second, EEsConns: []string{"ees1"}, EEsExporterIDs: []string{"exporter1"}, }, }, { name: "Test without any connections or exporters", input: &TrendsJsonCfg{ Enabled: utils.BoolPointer(true), Stats_conns: nil, Thresholds_conns: nil, Scheduled_ids: nil, Store_interval: utils.StringPointer("0"), Ees_conns: nil, Ees_exporter_ids: nil, }, expected: &TrendSCfg{ Enabled: true, StatSConns: nil, ThresholdSConns: nil, ScheduledIDs: nil, StoreInterval: 0, EEsConns: nil, EEsExporterIDs: nil, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var trendCfg TrendSCfg err := trendCfg.loadFromJSONCfg(tt.input) if (err != nil) != tt.expectedErr { t.Errorf("Expected error: %v, but got: %v", tt.expectedErr, err) } if trendCfg.Enabled != tt.expected.Enabled { t.Errorf("Expected Enabled to be %v, but got: %v", tt.expected.Enabled, trendCfg.Enabled) } if len(trendCfg.StatSConns) != len(tt.expected.StatSConns) { t.Errorf("Expected StatSConns length to be %v, but got: %v", len(tt.expected.StatSConns), len(trendCfg.StatSConns)) } else { for i := range trendCfg.StatSConns { if trendCfg.StatSConns[i] != tt.expected.StatSConns[i] { t.Errorf("Expected StatSConns[%d] to be %v, but got: %v", i, tt.expected.StatSConns[i], trendCfg.StatSConns[i]) } } } if len(trendCfg.ThresholdSConns) != len(tt.expected.ThresholdSConns) { t.Errorf("Expected ThresholdSConns length to be %v, but got: %v", len(tt.expected.ThresholdSConns), len(trendCfg.ThresholdSConns)) } else { for i := range trendCfg.ThresholdSConns { if trendCfg.ThresholdSConns[i] != tt.expected.ThresholdSConns[i] { t.Errorf("Expected ThresholdSConns[%d] to be %v, but got: %v", i, tt.expected.ThresholdSConns[i], trendCfg.ThresholdSConns[i]) } } } if len(trendCfg.ScheduledIDs) != len(tt.expected.ScheduledIDs) { t.Errorf("Expected ScheduledIDs length to be %v, but got: %v", len(tt.expected.ScheduledIDs), len(trendCfg.ScheduledIDs)) } else { for key, ids := range tt.expected.ScheduledIDs { if len(trendCfg.ScheduledIDs[key]) != len(ids) { t.Errorf("Expected ScheduledIDs[%s] length to be %v, but got: %v", key, len(ids), len(trendCfg.ScheduledIDs[key])) } else { for i := range ids { if trendCfg.ScheduledIDs[key][i] != ids[i] { t.Errorf("Expected ScheduledIDs[%s][%d] to be %v, but got: %v", key, i, ids[i], trendCfg.ScheduledIDs[key][i]) } } } } } if trendCfg.StoreInterval != tt.expected.StoreInterval { t.Errorf("Expected StoreInterval to be %v, but got: %v", tt.expected.StoreInterval, trendCfg.StoreInterval) } if len(trendCfg.EEsConns) != len(tt.expected.EEsConns) { t.Errorf("Expected EEsConns length to be %v, but got: %v", len(tt.expected.EEsConns), len(trendCfg.EEsConns)) } else { for i := range trendCfg.EEsConns { if trendCfg.EEsConns[i] != tt.expected.EEsConns[i] { t.Errorf("Expected EEsConns[%d] to be %v, but got: %v", i, tt.expected.EEsConns[i], trendCfg.EEsConns[i]) } } } if len(trendCfg.EEsExporterIDs) != len(tt.expected.EEsExporterIDs) { t.Errorf("Expected EEsExporterIDs length to be %v, but got: %v", len(tt.expected.EEsExporterIDs), len(trendCfg.EEsExporterIDs)) } else { for i := range trendCfg.EEsExporterIDs { if trendCfg.EEsExporterIDs[i] != tt.expected.EEsExporterIDs[i] { t.Errorf("Expected EEsExporterIDs[%d] to be %v, but got: %v", i, tt.expected.EEsExporterIDs[i], trendCfg.EEsExporterIDs[i]) } } } }) } } func TestLoadFromJSONCfgStoreInterval(t *testing.T) { validInterval := "30" jsnCfgValid := &TrendsJsonCfg{ Store_interval: &validInterval, } trendCfg := &TrendSCfg{} err := trendCfg.loadFromJSONCfg(jsnCfgValid) if err != nil { t.Errorf("Expected no error, got: %v", err) } if trendCfg.StoreInterval != 30*time.Nanosecond { t.Errorf("Expected StoreInterval to be 30ns, but got: %v", trendCfg.StoreInterval) } invalidInterval := "invalid_duration" jsnCfgInvalid := &TrendsJsonCfg{ Store_interval: &invalidInterval, } trendCfg = &TrendSCfg{} err = trendCfg.loadFromJSONCfg(jsnCfgInvalid) if err == nil { t.Errorf("Expected an error, got none") } } func TestAsMapInterface(t *testing.T) { trendCfg := &TrendSCfg{ Enabled: true, StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats), "conn1"}, ThresholdSConns: []string{"thresh1", utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}, ScheduledIDs: map[string][]string{"tenant1": {"id1"}}, EEsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs), "conn2"}, EEsExporterIDs: []string{"exporter1", "exporter2"}, } expected := map[string]any{ utils.EnabledCfg: true, utils.StatSConnsCfg: []string{utils.MetaInternal, "conn1"}, utils.ThresholdSConnsCfg: []string{"thresh1", utils.MetaInternal}, utils.ScheduledIDsCfg: map[string][]string{"tenant1": {"id1"}}, utils.EEsConnsCfg: []string{utils.MetaInternal, "conn2"}, utils.EEsExporterIDsCfg: []string{"exporter1", "exporter2"}, } got := trendCfg.AsMapInterface() if got[utils.EnabledCfg] != expected[utils.EnabledCfg] { t.Errorf("Expected Enabled to be %v, but got: %v", expected[utils.EnabledCfg], got[utils.EnabledCfg]) } if len(got[utils.StatSConnsCfg].([]string)) != len(expected[utils.StatSConnsCfg].([]string)) { t.Errorf("Expected StatSConns length to be %v, but got: %v", len(expected[utils.StatSConnsCfg].([]string)), len(got[utils.StatSConnsCfg].([]string))) } else { for i, conn := range expected[utils.StatSConnsCfg].([]string) { if got[utils.StatSConnsCfg].([]string)[i] != conn { t.Errorf("Expected StatSConns[%d] to be %v, but got: %v", i, conn, got[utils.StatSConnsCfg].([]string)[i]) } } } if len(got[utils.ThresholdSConnsCfg].([]string)) != len(expected[utils.ThresholdSConnsCfg].([]string)) { t.Errorf("Expected ThresholdSConns length to be %v, but got: %v", len(expected[utils.ThresholdSConnsCfg].([]string)), len(got[utils.ThresholdSConnsCfg].([]string))) } else { for i, thresh := range expected[utils.ThresholdSConnsCfg].([]string) { if got[utils.ThresholdSConnsCfg].([]string)[i] != thresh { t.Errorf("Expected ThresholdSConns[%d] to be %v, but got: %v", i, thresh, got[utils.ThresholdSConnsCfg].([]string)[i]) } } } if len(got[utils.ScheduledIDsCfg].(map[string][]string)) != len(expected[utils.ScheduledIDsCfg].(map[string][]string)) { t.Errorf("Expected ScheduledIDs length to be %v, but got: %v", len(expected[utils.ScheduledIDsCfg].(map[string][]string)), len(got[utils.ScheduledIDsCfg].(map[string][]string))) } else { for key, ids := range expected[utils.ScheduledIDsCfg].(map[string][]string) { if got[utils.ScheduledIDsCfg].(map[string][]string)[key][0] != ids[0] { t.Errorf("Expected ScheduledIDs[%s] to be %v, but got: %v", key, ids, got[utils.ScheduledIDsCfg].(map[string][]string)[key]) } } } if len(got[utils.EEsConnsCfg].([]string)) != len(expected[utils.EEsConnsCfg].([]string)) { t.Errorf("Expected EEsConns length to be %v, but got: %v", len(expected[utils.EEsConnsCfg].([]string)), len(got[utils.EEsConnsCfg].([]string))) } else { for i, ees := range expected[utils.EEsConnsCfg].([]string) { if got[utils.EEsConnsCfg].([]string)[i] != ees { t.Errorf("Expected EEsConns[%d] to be %v, but got: %v", i, ees, got[utils.EEsConnsCfg].([]string)[i]) } } } if len(got[utils.EEsExporterIDsCfg].([]string)) != len(expected[utils.EEsExporterIDsCfg].([]string)) { t.Errorf("Expected EEsExporterIDs length to be %v, but got: %v", len(expected[utils.EEsExporterIDsCfg].([]string)), len(got[utils.EEsExporterIDsCfg].([]string))) } else { for i, exporter := range expected[utils.EEsExporterIDsCfg].([]string) { if got[utils.EEsExporterIDsCfg].([]string)[i] != exporter { t.Errorf("Expected EEsExporterIDs[%d] to be %v, but got: %v", i, exporter, got[utils.EEsExporterIDsCfg].([]string)[i]) } } } } func TestTrendSCfgClone(t *testing.T) { original := &TrendSCfg{ Enabled: true, StatSConns: []string{"conn1", "conn2"}, ThresholdSConns: []string{"thresh1", "thresh2"}, ScheduledIDs: map[string][]string{"tenant1": {"id1", "id2"}, "tenant2": {"id3"}}, StoreInterval: 30 * time.Second, EEsConns: []string{"eeconn1", "eeconn2"}, EEsExporterIDs: []string{"exporter1", "exporter2"}, } cloned := original.Clone() if cloned.Enabled != original.Enabled { t.Errorf("Enabled field mismatch: expected %v, got %v", original.Enabled, cloned.Enabled) } if !reflect.DeepEqual(cloned.StatSConns, original.StatSConns) { t.Errorf("StatSConns mismatch: expected %v, got %v", original.StatSConns, cloned.StatSConns) } if !reflect.DeepEqual(cloned.ThresholdSConns, original.ThresholdSConns) { t.Errorf("ThresholdSConns mismatch: expected %v, got %v", original.ThresholdSConns, cloned.ThresholdSConns) } if !reflect.DeepEqual(cloned.ScheduledIDs, original.ScheduledIDs) { t.Errorf("ScheduledIDs mismatch: expected %v, got %v", original.ScheduledIDs, cloned.ScheduledIDs) } if cloned.StoreInterval != original.StoreInterval { t.Errorf("StoreInterval mismatch: expected %v, got %v", original.StoreInterval, cloned.StoreInterval) } if !reflect.DeepEqual(cloned.EEsConns, original.EEsConns) { t.Errorf("EEsConns mismatch: expected %v, got %v", original.EEsConns, cloned.EEsConns) } if !reflect.DeepEqual(cloned.EEsExporterIDs, original.EEsExporterIDs) { t.Errorf("EEsExporterIDs mismatch: expected %v, got %v", original.EEsExporterIDs, cloned.EEsExporterIDs) } cloned.Enabled = false cloned.StatSConns[0] = "modified_conn" cloned.ThresholdSConns[0] = "modified_thresh" cloned.ScheduledIDs["tenant1"][0] = "modified_id" cloned.StoreInterval = 45 * time.Second cloned.EEsConns[0] = "modified_eeconn" cloned.EEsExporterIDs[0] = "modified_exporter" if cloned.Enabled == original.Enabled { t.Error("Modifying cloned.Enabled should not affect original.Enabled") } if reflect.DeepEqual(cloned.StatSConns, original.StatSConns) { t.Error("Modifying cloned.StatSConns should not affect original.StatSConns") } if reflect.DeepEqual(cloned.ThresholdSConns, original.ThresholdSConns) { t.Error("Modifying cloned.ThresholdSConns should not affect original.ThresholdSConns") } if reflect.DeepEqual(cloned.ScheduledIDs, original.ScheduledIDs) { t.Error("Modifying cloned.ScheduledIDs should not affect original.ScheduledIDs") } if cloned.StoreInterval == original.StoreInterval { t.Error("Modifying cloned.StoreInterval should not affect original.StoreInterval") } if reflect.DeepEqual(cloned.EEsConns, original.EEsConns) { t.Error("Modifying cloned.EEsConns should not affect original.EEsConns") } if reflect.DeepEqual(cloned.EEsExporterIDs, original.EEsExporterIDs) { t.Error("Modifying cloned.EEsExporterIDs should not affect original.EEsExporterIDs") } }