mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Add new trends config option: scheduled_ids
This commit is contained in:
committed by
Dan Christian Bogos
parent
769293d4db
commit
d9a5458a43
@@ -857,6 +857,7 @@ const CGRATES_CFG_JSON = `
|
||||
"trends":{ // TrendS config
|
||||
"enabled": false, // starts TrendS service: <true|false>.
|
||||
"stats_conns": [], // connections to StatS ,empty to disable stats functionality: <""|*internal|$rpc_conns_id>
|
||||
"scheduled_ids": {}
|
||||
},
|
||||
|
||||
"thresholds": { // ThresholdS
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -681,6 +681,7 @@ type TrendsJsonCfg struct {
|
||||
Enabled *bool
|
||||
Stats_conns *[]string
|
||||
Thresholds_conns *[]string
|
||||
Scheduled_ids map[string][]string
|
||||
}
|
||||
|
||||
type RankingsJsonCfg struct {
|
||||
|
||||
@@ -20,6 +20,7 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
@@ -293,3 +294,15 @@ func (cda *DAClientOpts) AsMapInterface() map[string]any {
|
||||
}
|
||||
return mp
|
||||
}
|
||||
|
||||
func diffMapStringSlice(d, v1, v2 map[string][]string) map[string][]string {
|
||||
if d == nil {
|
||||
d = make(map[string][]string)
|
||||
}
|
||||
for k, v := range v2 {
|
||||
if val, has := v1[k]; !has || !slices.Equal(val, v) {
|
||||
d[k] = v
|
||||
}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
@@ -379,3 +379,65 @@ func TestDAClientOptsAsMapInterface(t *testing.T) {
|
||||
t.Errorf("opts.AsMapInterface() returned an unexpected value(-want +got): \n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiffMapStringSlice(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
d map[string][]string
|
||||
v1 map[string][]string
|
||||
v2 map[string][]string
|
||||
want map[string][]string
|
||||
}{
|
||||
{
|
||||
name: "Empty maps",
|
||||
d: nil,
|
||||
v1: map[string][]string{},
|
||||
v2: map[string][]string{},
|
||||
want: map[string][]string{},
|
||||
},
|
||||
{
|
||||
name: "v1 has no key from v2",
|
||||
d: nil,
|
||||
v1: map[string][]string{},
|
||||
v2: map[string][]string{"tenant1": {"id1", "id2"}},
|
||||
want: map[string][]string{"tenant1": {"id1", "id2"}},
|
||||
},
|
||||
{
|
||||
name: "Different values for the same key",
|
||||
d: nil,
|
||||
v1: map[string][]string{"tenant1": {"id1", "id2"}},
|
||||
v2: map[string][]string{"tenant1": {"id3", "id4"}},
|
||||
want: map[string][]string{"tenant1": {"id3", "id4"}},
|
||||
},
|
||||
{
|
||||
name: "Same key with equal values",
|
||||
d: nil,
|
||||
v1: map[string][]string{"tenant1": {"id1", "id2"}},
|
||||
v2: map[string][]string{"tenant1": {"id1", "id2"}},
|
||||
want: map[string][]string{},
|
||||
},
|
||||
{
|
||||
name: "d is not nil, adds differences from v2",
|
||||
d: map[string][]string{"existing": {"val3"}},
|
||||
v1: map[string][]string{"tenant1": {"id1", "id2"}},
|
||||
v2: map[string][]string{"tenant1": {"id3", "id4"}, "tenant2": {"id4", "id5"}},
|
||||
want: map[string][]string{"existing": {"val3"}, "tenant1": {"id3", "id4"}, "tenant2": {"id4", "id5"}},
|
||||
},
|
||||
{
|
||||
name: "Adding multiple tenants",
|
||||
d: nil,
|
||||
v1: map[string][]string{"tenant1": {"id1", "id2"}},
|
||||
v2: map[string][]string{"tenant1": {"id1", "id2"}, "tenant2": {"id4", "id5"}},
|
||||
want: map[string][]string{"tenant2": {"id4", "id5"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := diffMapStringSlice(tt.d, tt.v1, tt.v2)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("diffMapStringSlice() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package config
|
||||
|
||||
import "github.com/cgrates/cgrates/utils"
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
type TrendSCfg struct {
|
||||
Enabled bool
|
||||
StatSConns []string
|
||||
ThresholdSConns []string
|
||||
ScheduledIDs map[string][]string
|
||||
}
|
||||
|
||||
func (sa *TrendSCfg) loadFromJSONCfg(jsnCfg *TrendsJsonCfg) (err error) {
|
||||
@@ -51,6 +56,9 @@ func (sa *TrendSCfg) loadFromJSONCfg(jsnCfg *TrendsJsonCfg) (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if jsnCfg.Scheduled_ids != nil {
|
||||
sa.ScheduledIDs = jsnCfg.Scheduled_ids
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -78,6 +86,9 @@ func (sa *TrendSCfg) AsMapInterface() (initialMP map[string]any) {
|
||||
}
|
||||
initialMP[utils.ThresholdSConnsCfg] = thresholdSConns
|
||||
}
|
||||
if sa.ScheduledIDs != nil {
|
||||
initialMP[utils.ScheduledIDsCfg] = sa.ScheduledIDs
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -93,5 +104,12 @@ func (sa *TrendSCfg) Clone() (cln *TrendSCfg) {
|
||||
cln.ThresholdSConns = make([]string, len(sa.ThresholdSConns))
|
||||
copy(cln.ThresholdSConns, sa.ThresholdSConns)
|
||||
}
|
||||
if sa.ScheduledIDs != nil {
|
||||
cln.ScheduledIDs = make(map[string][]string)
|
||||
for key, value := range sa.ScheduledIDs {
|
||||
cln.ScheduledIDs[key] = slices.Clone(value)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
224
config/trendscfg_test.go
Normal file
224
config/trendscfg_test.go
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestLoadFromJSONCfgs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input *TrendsJsonCfg
|
||||
expected *TrendSCfg
|
||||
}{
|
||||
{
|
||||
name: "Test with MetaInternal in Stats_conns",
|
||||
input: &TrendsJsonCfg{
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Stats_conns: &[]string{"conn1", utils.MetaInternal},
|
||||
Thresholds_conns: &[]string{"thresh1"},
|
||||
Scheduled_ids: map[string][]string{"tenant1": {"id1"}},
|
||||
},
|
||||
expected: &TrendSCfg{
|
||||
Enabled: true,
|
||||
StatSConns: []string{"conn1", utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)},
|
||||
ThresholdSConns: []string{"thresh1"},
|
||||
ScheduledIDs: map[string][]string{"tenant1": {"id1"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
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"}},
|
||||
},
|
||||
expected: &TrendSCfg{
|
||||
Enabled: true,
|
||||
StatSConns: []string{"conn1"},
|
||||
ThresholdSConns: []string{"thresh1", utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)},
|
||||
ScheduledIDs: map[string][]string{"tenant1": {"id1"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test without any connections",
|
||||
input: &TrendsJsonCfg{
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Stats_conns: nil,
|
||||
Thresholds_conns: nil,
|
||||
Scheduled_ids: nil,
|
||||
},
|
||||
expected: &TrendSCfg{
|
||||
Enabled: true,
|
||||
StatSConns: nil,
|
||||
ThresholdSConns: nil,
|
||||
ScheduledIDs: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var trendCfg TrendSCfg
|
||||
|
||||
err := trendCfg.loadFromJSONCfg(tt.input)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, but got: %v", 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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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"}},
|
||||
}
|
||||
|
||||
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"}},
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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"}},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
cloned.Enabled = false
|
||||
cloned.StatSConns[0] = "modified_conn"
|
||||
cloned.ThresholdSConns[0] = "modified_thresh"
|
||||
cloned.ScheduledIDs["tenant1"][0] = "modified_id"
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
@@ -2534,6 +2534,7 @@ const (
|
||||
SchedulerConnsCfg = "scheduler_conns"
|
||||
GapiCredentialsCfg = "gapi_credentials"
|
||||
GapiTokenCfg = "gapi_token"
|
||||
ScheduledIDsCfg = "scheduled_ids"
|
||||
)
|
||||
|
||||
// MigratorCgrCfg
|
||||
|
||||
Reference in New Issue
Block a user