Add new options to trends configuration

- store_interval
- ees_conns
- ees_exporter_ids
This commit is contained in:
armirveliaj
2024-10-07 08:47:33 -04:00
committed by Dan Christian Bogos
parent dfc1ed0f0b
commit fbdc789f5c
5 changed files with 186 additions and 23 deletions

View File

@@ -856,8 +856,11 @@ const CGRATES_CFG_JSON = `
"trends":{ // TrendS config
"enabled": false, // starts TrendS service: <true|false>.
"store_interval": "",
"stats_conns": [], // connections to StatS ,empty to disable stats functionality: <""|*internal|$rpc_conns_id>
"scheduled_ids": {}
"scheduled_ids": {},
"ees_conns": [],
"ees_exporter_ids": []
},
"thresholds": { // ThresholdS

File diff suppressed because one or more lines are too long

View File

@@ -682,6 +682,9 @@ type TrendsJsonCfg struct {
Stats_conns *[]string
Thresholds_conns *[]string
Scheduled_ids map[string][]string
Store_interval *string
Ees_conns *[]string
Ees_exporter_ids *[]string
}
type RankingsJsonCfg struct {

View File

@@ -20,6 +20,7 @@ package config
import (
"slices"
"time"
"github.com/cgrates/cgrates/utils"
)
@@ -29,6 +30,9 @@ type TrendSCfg struct {
StatSConns []string
ThresholdSConns []string
ScheduledIDs map[string][]string
StoreInterval time.Duration
EEsConns []string
EEsExporterIDs []string
}
func (sa *TrendSCfg) loadFromJSONCfg(jsnCfg *TrendsJsonCfg) (err error) {
@@ -59,12 +63,30 @@ func (sa *TrendSCfg) loadFromJSONCfg(jsnCfg *TrendsJsonCfg) (err error) {
if jsnCfg.Scheduled_ids != nil {
sa.ScheduledIDs = jsnCfg.Scheduled_ids
}
if jsnCfg.Store_interval != nil {
if sa.StoreInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Store_interval); err != nil {
return err
}
}
if jsnCfg.Ees_conns != nil {
sa.EEsConns = make([]string, len(*jsnCfg.Ees_conns))
for idx, connID := range *jsnCfg.Ees_conns {
sa.EEsConns[idx] = connID
if connID == utils.MetaInternal {
sa.EEsConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs)
}
}
}
if jsnCfg.Ees_exporter_ids != nil {
sa.EEsExporterIDs = append(sa.EEsExporterIDs, *jsnCfg.Ees_exporter_ids...)
}
return
}
func (sa *TrendSCfg) AsMapInterface() (initialMP map[string]any) {
initialMP = map[string]any{
utils.EnabledCfg: sa.Enabled,
utils.EnabledCfg: sa.Enabled,
utils.StoreIntervalCfg: utils.EmptyString,
}
if sa.StatSConns != nil {
statSConns := make([]string, len(sa.StatSConns))
@@ -89,12 +111,26 @@ func (sa *TrendSCfg) AsMapInterface() (initialMP map[string]any) {
if sa.ScheduledIDs != nil {
initialMP[utils.ScheduledIDsCfg] = sa.ScheduledIDs
}
if sa.EEsConns != nil {
eesConns := make([]string, len(sa.EEsConns))
for i, item := range sa.EEsConns {
eesConns[i] = item
if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs) {
eesConns[i] = utils.MetaInternal
}
}
initialMP[utils.EEsConnsCfg] = eesConns
}
eesExporterIDs := make([]string, len(sa.EEsExporterIDs))
copy(eesExporterIDs, sa.EEsExporterIDs)
initialMP[utils.EEsExporterIDsCfg] = eesExporterIDs
return
}
func (sa *TrendSCfg) Clone() (cln *TrendSCfg) {
cln = &TrendSCfg{
Enabled: sa.Enabled,
Enabled: sa.Enabled,
StoreInterval: sa.StoreInterval,
}
if sa.StatSConns != nil {
cln.StatSConns = make([]string, len(sa.StatSConns))
@@ -110,6 +146,14 @@ func (sa *TrendSCfg) Clone() (cln *TrendSCfg) {
cln.ScheduledIDs[key] = slices.Clone(value)
}
}
if sa.EEsConns != nil {
cln.EEsConns = make([]string, len(sa.EEsConns))
copy(cln.EEsConns, sa.EEsConns)
}
if sa.EEsExporterIDs != nil {
cln.EEsExporterIDs = make([]string, len(sa.EEsExporterIDs))
copy(cln.EEsExporterIDs, sa.EEsExporterIDs)
}
return
}

View File

@@ -21,29 +21,37 @@ package config
import (
"reflect"
"testing"
"time"
"github.com/cgrates/cgrates/utils"
)
func TestLoadFromJSONCfgs(t *testing.T) {
tests := []struct {
name string
input *TrendsJsonCfg
expected *TrendSCfg
name string
input *TrendsJsonCfg
expected *TrendSCfg
expectedErr bool
}{
{
name: "Test with MetaInternal in Stats_conns",
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"},
},
},
{
@@ -53,39 +61,48 @@ func TestLoadFromJSONCfgs(t *testing.T) {
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",
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 {
t.Errorf("Expected no error, but got: %v", err)
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)
@@ -123,16 +140,69 @@ func TestLoadFromJSONCfgs(t *testing.T) {
}
}
}
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{
@@ -140,6 +210,8 @@ func TestAsMapInterface(t *testing.T) {
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()
@@ -147,7 +219,6 @@ func TestAsMapInterface(t *testing.T) {
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 {
@@ -157,7 +228,6 @@ func TestAsMapInterface(t *testing.T) {
}
}
}
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 {
@@ -167,7 +237,6 @@ func TestAsMapInterface(t *testing.T) {
}
}
}
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 {
@@ -177,6 +246,25 @@ func TestAsMapInterface(t *testing.T) {
}
}
}
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) {
@@ -185,6 +273,9 @@ func TestTrendSCfgClone(t *testing.T) {
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()
@@ -192,22 +283,32 @@ func TestTrendSCfgClone(t *testing.T) {
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")
@@ -221,4 +322,13 @@ func TestTrendSCfgClone(t *testing.T) {
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")
}
}