diff --git a/apis/resources_it_test.go b/apis/resources_it_test.go
index 906754c96..2eeb056bd 100644
--- a/apis/resources_it_test.go
+++ b/apis/resources_it_test.go
@@ -522,6 +522,7 @@ func testResourceSStartServer(t *testing.T) {
func testResourceSStopServer(t *testing.T) {
rsSrv.Close()
}
+
func testResourceSSetActionProfile(t *testing.T) {
actPrf := &engine.ActionProfileWithAPIOpts{
ActionProfile: &engine.ActionProfile{
diff --git a/apis/stats_it_test.go b/apis/stats_it_test.go
new file mode 100644
index 000000000..be63aeb4f
--- /dev/null
+++ b/apis/stats_it_test.go
@@ -0,0 +1,413 @@
+// +build integration
+
+/*
+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 apis
+
+import (
+ "path"
+ "testing"
+
+ "github.com/cgrates/birpc"
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+)
+
+var (
+ sqCfgPath string
+ sqCfg *config.CGRConfig
+ sqRPC *birpc.Client
+ sqConfigDIR string //run tests for specific configuration
+
+ sTestsSq = []func(t *testing.T){
+ testStatsInitCfg,
+ testStatsInitDataDB,
+ testStatsResetStorDB,
+ testStatsStartEngine,
+ testStatsRPCConn,
+ testStatsGetStatQueueBeforeSet,
+ testStatsSetStatQueueProfiles,
+ // testStatsGetStatQueueAfterSet,
+ // testStatsGetStatQueueIDs,
+ // testStatsGetStatQueueProfileIDs,
+ // testStatsGetStatQueueProfileCount,
+ // testStatsGetStatQueuesForEvent,
+ // testStatsRemoveStatQueueProfiles,
+ // testStatsGetStatQueuesAfterRemove,
+ testStatsPing,
+ testStatsKillEngine,
+ }
+)
+
+func TestStatsIT(t *testing.T) {
+ switch *dbType {
+ case utils.MetaInternal:
+ sqConfigDIR = "stats_internal"
+ case utils.MetaMongo:
+ sqConfigDIR = "stats_mongo"
+ case utils.MetaMySQL:
+ sqConfigDIR = "stats_mysql"
+ case utils.MetaPostgres:
+ t.SkipNow()
+ default:
+ t.Fatal("Unknown Database type")
+ }
+ for _, stest := range sTestsSq {
+ t.Run(sqConfigDIR, stest)
+ }
+}
+
+func testStatsInitCfg(t *testing.T) {
+ var err error
+ sqCfgPath = path.Join(*dataDir, "conf", "samples", sqConfigDIR)
+ sqCfg, err = config.NewCGRConfigFromPath(sqCfgPath)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func testStatsInitDataDB(t *testing.T) {
+ if err := engine.InitDataDB(sqCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testStatsResetStorDB(t *testing.T) {
+ if err := engine.InitStorDB(sqCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Start CGR Engine
+func testStatsStartEngine(t *testing.T) {
+ if _, err := engine.StopStartEngine(sqCfgPath, *waitRater); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testStatsRPCConn(t *testing.T) {
+ var err error
+ sqRPC, err = newRPCClient(sqCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+//Kill the engine when it is about to be finished
+func testStatsKillEngine(t *testing.T) {
+ if err := engine.KillEngine(100); err != nil {
+ t.Error(err)
+ }
+}
+
+func testStatsPing(t *testing.T) {
+ var reply string
+ if err := sqRPC.Call(context.Background(), utils.StatSv1Ping,
+ new(utils.CGREvent), &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.Pong {
+ t.Error("Unexpected reply returned:", reply)
+ }
+}
+
+func testStatsGetStatQueueBeforeSet(t *testing.T) {
+ args := &engine.StatsArgsProcessEvent{
+ StatIDs: []string{"SQ_1", "SQ_2"},
+ CGREvent: &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "StatsEventTest",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ },
+ }
+
+ var rplySqs engine.StatQueues
+ if err := sqRPC.Call(context.Background(), utils.StatSv1GetStatQueuesForEvent,
+ args, &rplySqs); err == nil || err.Error() != utils.ErrNotFound.Error() {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func testStatsSetStatQueueProfiles(t *testing.T) {
+ sqPrf1 := &engine.StatQueueProfileWithAPIOpts{
+ StatQueueProfile: &engine.StatQueueProfile{
+ Tenant: "cgrates.org",
+ ID: "SQ_1",
+ Weight: 10,
+ ThresholdIDs: []string{utils.MetaNone},
+ },
+ }
+
+ var reply string
+ if err := sqRPC.Call(context.Background(), utils.AdminSv1SetStatQueueProfile,
+ sqPrf1, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Error("Unexpected reply returned:", reply)
+ }
+
+ sqPrf2 := &engine.StatQueueProfileWithAPIOpts{
+ StatQueueProfile: &engine.StatQueueProfile{
+ Tenant: "cgrates.org",
+ ID: "SQ_2",
+ Weight: 20,
+ ThresholdIDs: []string{utils.MetaNone},
+ },
+ }
+
+ if err := sqRPC.Call(context.Background(), utils.AdminSv1SetStatQueueProfile,
+ sqPrf2, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Error("Unexpected reply returned:", reply)
+ }
+}
+
+// func testStatsGetStatQueueAfterSet(t *testing.T) {
+// var rplySq engine.StatQueue
+// var rplySqPrf engine.StatQueueProfile
+// expSq := engine.StatQueue{
+// Tenant: "cgrates.org",
+// ID: "SQ_1",
+// SQMetrics: make(map[string]engine.StatMetric),
+// SQItems: []engine.SQItem{},
+// }
+// expSqPrf := engine.StatQueueProfile{
+// Tenant: "cgrates.org",
+// ID: "SQ_1",
+// Weight: 10,
+// ThresholdIDs: []string{utils.MetaNone},
+// }
+
+// if err := sqRPC.Call(context.Background(), utils.StatSv1GetStatQueue,
+// &utils.TenantIDWithAPIOpts{
+// TenantID: &utils.TenantID{
+// Tenant: "cgrates.org",
+// ID: "SQ_1",
+// },
+// }, &rplySq); err != nil {
+// t.Error(err)
+// } else if !reflect.DeepEqual(rplySq, expSq) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+// utils.ToJSON(expSq), utils.ToJSON(rplySq))
+// }
+
+// if err := sqRPC.Call(context.Background(), utils.AdminSv1GetStatQueueProfile,
+// utils.TenantID{
+// Tenant: "cgrates.org",
+// ID: "SQ_1",
+// }, &rplySqPrf); err != nil {
+// t.Error(err)
+// } else if !reflect.DeepEqual(rplySqPrf, expSqPrf) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+// utils.ToJSON(expSqPrf), utils.ToJSON(rplySqPrf))
+// }
+
+// expSq = engine.StatQueue{
+// Tenant: "cgrates.org",
+// ID: "SQ_2",
+// SQMetrics: make(map[string]engine.StatMetric),
+// SQItems: []engine.SQItem{},
+// }
+// expSqPrf = engine.StatQueueProfile{
+// Tenant: "cgrates.org",
+// ID: "SQ_2",
+// Weight: 20,
+// ThresholdIDs: []string{utils.MetaNone},
+// }
+
+// if err := sqRPC.Call(context.Background(), utils.StatSv1GetStatQueue,
+// &utils.TenantIDWithAPIOpts{
+// TenantID: &utils.TenantID{
+// Tenant: "cgrates.org",
+// ID: "SQ_2",
+// },
+// }, &rplySq); err != nil {
+// t.Error(err)
+// } else if !reflect.DeepEqual(rplySq, expSq) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+// utils.ToJSON(expSq), utils.ToJSON(rplySq))
+// }
+
+// if err := sqRPC.Call(context.Background(), utils.AdminSv1GetStatQueueProfile,
+// &utils.TenantID{
+// Tenant: "cgrates.org",
+// ID: "SQ_2",
+// }, &rplySqPrf); err != nil {
+// t.Error(err)
+// } else if !reflect.DeepEqual(rplySqPrf, expSqPrf) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+// utils.ToJSON(expSqPrf), utils.ToJSON(rplySqPrf))
+// }
+// }
+
+// func testStatsGetStatQueueIDs(t *testing.T) {
+// expIDs := []string{"SQ_1", "SQ_2"}
+// var sqIDs []string
+// if err := sqRPC.Call(context.Background(), utils.StatSv1GetQueueIDs,
+// &utils.TenantWithAPIOpts{
+// Tenant: "cgrates.org",
+// }, &sqIDs); err != nil {
+// t.Error(err)
+// } else {
+// sort.Strings(sqIDs)
+// if !reflect.DeepEqual(sqIDs, expIDs) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>", expIDs, sqIDs)
+// }
+// }
+// }
+
+// func testStatsGetStatQueueProfileIDs(t *testing.T) {
+// expIDs := []string{"SQ_1", "SQ_2"}
+// var sqIDs []string
+// if err := sqRPC.Call(context.Background(), utils.AdminSv1GetStatQueueProfileIDs,
+// &utils.PaginatorWithTenant{
+// Tenant: "cgrates.org",
+// Paginator: utils.Paginator{},
+// }, &sqIDs); err != nil {
+// t.Error(err)
+// } else {
+// sort.Strings(sqIDs)
+// if !reflect.DeepEqual(sqIDs, expIDs) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>", expIDs, sqIDs)
+// }
+// }
+// }
+
+// func testStatsGetStatQueueProfileCount(t *testing.T) {
+// var reply int
+// if err := sqRPC.Call(context.Background(), utils.AdminSv1GetStatQueueProfileCount,
+// &utils.TenantWithAPIOpts{
+// Tenant: "cgrates.org",
+// }, &reply); err != nil {
+// t.Error(err)
+// } else if reply != 2 {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>", 2, reply)
+// }
+// }
+
+// func testStatsGetStatQueuesForEvent(t *testing.T) {
+// args := &engine.StatsArgsProcessEvent{
+// StatIDs: []string{"SQ_1", "SQ_2"},
+// CGREvent: &utils.CGREvent{
+// Tenant: "cgrates.org",
+// ID: "StatsEventTest",
+// Event: map[string]interface{}{
+// utils.AccountField: "1001",
+// },
+// },
+// }
+// expSqs := engine.StatQueues{
+// &engine.StatQueue{
+// Tenant: "cgrates.org",
+// ID: "SQ_2",
+// SQMetrics: make(map[string]engine.StatMetric),
+// },
+// &engine.StatQueue{
+// Tenant: "cgrates.org",
+// ID: "SQ_1",
+// SQMetrics: make(map[string]engine.StatMetric),
+// },
+// }
+
+// rplySqs := engine.StatQueues{
+// {
+// SQMetrics: map[string]engine.StatMetric{
+// utils.MetaTCD: &engine.StatTCD{},
+// utils.MetaASR: &engine.StatASR{},
+// utils.MetaACD: &engine.StatACD{},
+// },
+// },
+// {
+// SQMetrics: map[string]engine.StatMetric{
+// utils.MetaTCD: &engine.StatTCD{},
+// utils.MetaASR: &engine.StatASR{},
+// utils.MetaACD: &engine.StatACD{},
+// },
+// },
+// }
+// if err := sqRPC.Call(context.Background(), utils.StatSv1GetStatQueuesForEvent,
+// args, &rplySqs); err != nil {
+// t.Error(err)
+// } else if !reflect.DeepEqual(rplySqs, expSqs) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+// utils.ToJSON(expSqs), utils.ToJSON(rplySqs))
+// }
+// }
+
+// func testStatsRemoveStatQueueProfiles(t *testing.T) {
+// var reply string
+
+// if err := sqRPC.Call(context.Background(), utils.AdminSv1RemoveStatQueueProfile,
+// &utils.TenantIDWithAPIOpts{
+// TenantID: &utils.TenantID{
+// Tenant: "cgrates.org",
+// ID: "SQ_1",
+// }}, &reply); err != nil {
+// t.Error(err)
+// } else if reply != utils.OK {
+// t.Error("Unexpected reply returned:", reply)
+// }
+
+// if err := sqRPC.Call(context.Background(), utils.AdminSv1RemoveStatQueueProfile,
+// &utils.TenantIDWithAPIOpts{
+// TenantID: &utils.TenantID{
+// Tenant: "cgrates.org",
+// ID: "SQ_2",
+// }}, &reply); err != nil {
+// t.Error(err)
+// } else if reply != utils.OK {
+// t.Error("Unexpected reply returned:", reply)
+// }
+// }
+
+// func testStatsGetStatQueuesAfterRemove(t *testing.T) {
+// args := &engine.StatsArgsProcessEvent{
+// StatIDs: []string{"SQ_1", "SQ_2"},
+// CGREvent: &utils.CGREvent{
+// Tenant: "cgrates.org",
+// ID: "StatsEventTest",
+// Event: map[string]interface{}{
+// utils.AccountField: "1001",
+// },
+// },
+// }
+// expSqs := engine.StatQueues{
+// &engine.StatQueue{
+// Tenant: "cgrates.org",
+// ID: "SQ_2",
+// },
+// &engine.StatQueue{
+// Tenant: "cgrates.org",
+// ID: "SQ_1",
+// },
+// }
+
+// var rplySqs engine.StatQueues
+// if err := sqRPC.Call(context.Background(), utils.StatSv1GetStatQueuesForEvent,
+// args, &rplySqs); err != nil {
+// t.Error(err)
+// } else if !reflect.DeepEqual(rplySqs, expSqs) {
+// t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+// utils.ToJSON(expSqs), utils.ToJSON(rplySqs))
+// }
+// }
diff --git a/config/config_it_test.go b/config/config_it_test.go
index 1dfcaf3c0..d04d59bca 100644
--- a/config/config_it_test.go
+++ b/config/config_it_test.go
@@ -265,7 +265,6 @@ func testCGRConfigReloadThresholdS(t *testing.T) {
SuffixIndexedFields: &[]string{},
ActionSConns: []string{},
IndexedSelects: true,
- ActionSConns: []string{},
}
if !reflect.DeepEqual(expAttr, cfg.ThresholdSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.ThresholdSCfg()))
diff --git a/data/conf/samples/stats_internal/cgrates.json b/data/conf/samples/stats_internal/cgrates.json
new file mode 100644
index 000000000..a8e32ac1f
--- /dev/null
+++ b/data/conf/samples/stats_internal/cgrates.json
@@ -0,0 +1,37 @@
+{
+ // CGRateS Configuration file
+ // will be used in apis/stats_it_test.go
+
+ "general": {
+ "log_level": 7,
+ },
+
+ "data_db": {
+ "db_type": "*internal",
+ },
+
+ "stor_db": {
+ "db_type": "*internal",
+ },
+
+ "actions": {
+ "enabled": true,
+ "thresholds_conns": ["*internal"],
+ },
+
+ "stats": {
+ "enabled": true,
+ "store_interval": "-1",
+ "thresholds_conns": ["*internal"],
+ },
+
+ "thresholds": {
+ "enabled": true,
+ "store_interval": "-1",
+ "actions_conns": ["*internal"],
+ },
+
+ "admins": {
+ "enabled": true,
+ },
+ }
\ No newline at end of file
diff --git a/data/conf/samples/stats_mongo/cgrates.json b/data/conf/samples/stats_mongo/cgrates.json
new file mode 100644
index 000000000..79b1d4963
--- /dev/null
+++ b/data/conf/samples/stats_mongo/cgrates.json
@@ -0,0 +1,39 @@
+{
+ // CGRateS Configuration file
+ // will be used in apis/stats_it_test.go
+
+ "general": {
+ "log_level": 7,
+ },
+
+ "data_db": {
+ "db_type": "mongo",
+ "db_name": "10",
+ "db_port": 27017,
+ },
+
+ "stor_db": {
+ "db_type": "mongo",
+ "db_name": "cgrates",
+ "db_port": 27017,
+ },
+
+ "actions": {
+ "enabled": true,
+ "thresholds_conns": ["*internal"],
+ },
+
+ "stats": {
+ "enabled": true,
+ "store_interval": "-1",
+ },
+
+ "thresholds": {
+ "enabled": true,
+ "actions_conns": ["*internal"],
+ },
+
+ "admins": {
+ "enabled": true,
+ }
+ }
\ No newline at end of file
diff --git a/data/conf/samples/stats_mysql/cgrates.json b/data/conf/samples/stats_mysql/cgrates.json
new file mode 100644
index 000000000..c7c81ee4d
--- /dev/null
+++ b/data/conf/samples/stats_mysql/cgrates.json
@@ -0,0 +1,37 @@
+{
+ // CGRateS Configuration file
+ // will be used in apis/stats_it_test.go
+ "general": {
+ "log_level": 7,
+ },
+
+ "data_db": { // database used to store runtime data (eg: accounts, cdr stats)
+ "db_type": "redis", // data_db type:
+ "db_port": 6379, // data_db port to reach the database
+ "db_name": "10", // data_db database name to connect to
+ },
+
+ "stor_db": {
+ "db_password": "CGRateS.org",
+ },
+
+ "actions": {
+ "enabled": true,
+ "thresholds_conns": ["*internal"],
+ },
+
+ "stats": {
+ "enabled": true,
+ "store_interval": "-1",
+ },
+
+ "thresholds": {
+ "enabled": true,
+ "store_interval": "-1",
+ "actions_conns": ["*internal"],
+ },
+
+ "admins": {
+ "enabled": true,
+ }
+ }
\ No newline at end of file
diff --git a/utils/consts.go b/utils/consts.go
index a5dd8b5ff..92808bf2d 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -1344,18 +1344,19 @@ const (
// StatS APIs
const (
- StatSv1ProcessEvent = "StatSv1.ProcessEvent"
- StatSv1GetQueueIDs = "StatSv1.GetQueueIDs"
- StatSv1GetQueueStringMetrics = "StatSv1.GetQueueStringMetrics"
- StatSv1GetQueueFloatMetrics = "StatSv1.GetQueueFloatMetrics"
- StatSv1Ping = "StatSv1.Ping"
- StatSv1GetStatQueuesForEvent = "StatSv1.GetStatQueuesForEvent"
- StatSv1GetStatQueue = "StatSv1.GetStatQueue"
- StatSv1ResetStatQueue = "StatSv1.ResetStatQueue"
- APIerSv1GetStatQueueProfile = "APIerSv1.GetStatQueueProfile"
- APIerSv1RemoveStatQueueProfile = "APIerSv1.RemoveStatQueueProfile"
- APIerSv1SetStatQueueProfile = "APIerSv1.SetStatQueueProfile"
- APIerSv1GetStatQueueProfileIDs = "APIerSv1.GetStatQueueProfileIDs"
+ StatSv1ProcessEvent = "StatSv1.ProcessEvent"
+ StatSv1GetQueueIDs = "StatSv1.GetQueueIDs"
+ StatSv1GetQueueStringMetrics = "StatSv1.GetQueueStringMetrics"
+ StatSv1GetQueueFloatMetrics = "StatSv1.GetQueueFloatMetrics"
+ StatSv1Ping = "StatSv1.Ping"
+ StatSv1GetStatQueuesForEvent = "StatSv1.GetStatQueuesForEvent"
+ StatSv1GetStatQueue = "StatSv1.GetStatQueue"
+ StatSv1ResetStatQueue = "StatSv1.ResetStatQueue"
+ AdminSv1GetStatQueueProfile = "AdminSv1.GetStatQueueProfile"
+ AdminSv1RemoveStatQueueProfile = "AdminSv1.RemoveStatQueueProfile"
+ AdminSv1SetStatQueueProfile = "AdminSv1.SetStatQueueProfile"
+ AdminSv1GetStatQueueProfileIDs = "AdminSv1.GetStatQueueProfileIDs"
+ AdminSv1GetStatQueueProfileCount = "AdminSv1.GetStatQueueProfileCount"
)
// ResourceS APIs