From 7ba4b1319015ad458f9130aa17a84eb79dec39a9 Mon Sep 17 00:00:00 2001 From: arberkatellari Date: Fri, 15 Aug 2025 18:06:27 +0200 Subject: [PATCH] Add tests for offline internal APIs --- .../offline_internal_apis/cgrates.json | 125 +++++++++++ .../offline_internal_apis_it_test.go | 205 ++++++++++++++++++ utils/consts.go | 6 + 3 files changed, 336 insertions(+) create mode 100644 data/conf/samples/offline_internal_apis/cgrates.json create mode 100644 general_tests/offline_internal_apis_it_test.go diff --git a/data/conf/samples/offline_internal_apis/cgrates.json b/data/conf/samples/offline_internal_apis/cgrates.json new file mode 100644 index 000000000..4d97b0136 --- /dev/null +++ b/data/conf/samples/offline_internal_apis/cgrates.json @@ -0,0 +1,125 @@ +{ + + + + "general": { + "node_id":"offlineApis", + "log_level": 7, + }, + + + "listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080" + }, + + + "data_db": { + "db_type": "*internal", + "opts":{ + "internalDBDumpPath": "/tmp/internal_db/datadb", + "internalDBBackupPath": "/tmp/internal_db/backup_datadb", + "internalDBDumpInterval": "1h", + } + }, + + + "stor_db": { + "db_type": "*internal", + "opts":{ + "internalDBDumpPath": "/tmp/internal_db/stordb", + "internalDBBackupPath": "/tmp/internal_db/backup_stordb", + "internalDBDumpInterval": "1h", + } + }, + + "rals": { + "enabled": true, + "thresholds_conns": ["*internal"], + "max_increments":3000000 + }, + + + "schedulers": { + "enabled": true, + "cdrs_conns": ["*internal"], + "stats_conns": ["*internal"] + }, + + + "cdrs": { + "enabled": true, + "chargers_conns":["*internal"] + }, + + + "attributes": { + "enabled": true, + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "apiers_conns": ["*internal"] + }, + + + "chargers": { + "enabled": true, + "attributes_conns": ["*internal"] + }, + + + "resources": { + "enabled": true, + "store_interval": "-1", + "thresholds_conns": ["*internal"] + }, + + + "stats": { + "enabled": true, + "store_interval": "-1", + "thresholds_conns": ["*internal"] + }, + + "thresholds": { + "enabled": true, + "store_interval": "-1" + }, + + + "routes": { + "enabled": true, + "prefix_indexed_fields":["*req.Destination"], + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "rals_conns": ["*internal"] + }, + + + "sessions": { + "enabled": true, + "routes_conns": ["*internal"], + "resources_conns": ["*internal"], + "attributes_conns": ["*internal"], + "rals_conns": ["*internal"], + "cdrs_conns": ["*internal"], + "chargers_conns": ["*internal"], + "backup_interval": "-1" + }, + + + "apiers": { + "enabled": true, + "scheduler_conns": ["*internal"] + }, + + + "filters": { + "stats_conns": ["*internal"], + "resources_conns": ["*internal"], + "apiers_conns": ["*internal"] + } + + + } + \ No newline at end of file diff --git a/general_tests/offline_internal_apis_it_test.go b/general_tests/offline_internal_apis_it_test.go new file mode 100644 index 000000000..83b33b379 --- /dev/null +++ b/general_tests/offline_internal_apis_it_test.go @@ -0,0 +1,205 @@ +//go:build integration +// +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 general_tests + +import ( + "bytes" + "os" + "path" + "path/filepath" + "testing" + "time" + + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func TestOfflineInternalAPIsDumpDataDB(t *testing.T) { + + if err := os.MkdirAll("/tmp/internal_db/datadb", 0755); err != nil { + t.Fatal(err) + } + ng := engine.TestEngine{ + ConfigPath: path.Join(*utils.DataDir, "conf", "samples", "offline_internal_apis"), + GracefulShutdown: true, + PreserveDataDB: true, + DBCfg: engine.DBCfg{ + StorDB: engine.MongoDBCfg.StorDB, + }, + TpPath: path.Join(*utils.DataDir, "tariffplans", "testit"), + LogBuffer: &bytes.Buffer{}, + } + t.Cleanup(func() { + if err := os.RemoveAll("/tmp/internal_db"); err != nil { + t.Error(err) + } + }) + client, cfg := ng.Run(t) + time.Sleep(100 * time.Millisecond) + + t.Run("CountDataDBFiles", func(t *testing.T) { + var totalSize int64 + var dirs, files int + if err := filepath.Walk(cfg.DataDbCfg().Opts.InternalDBDumpPath, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + dirs++ + } else { + totalSize += info.Size() // Add the size of the file + files++ + } + return nil + }); err != nil { + t.Error(err) + } else if dirs != 43 { + t.Errorf("expected <%d> directories, received <%d>", 43, dirs) + } else if files != 42 { + t.Errorf("expected 42 files, received <%d>", files) + } + if totalSize != 0 { + t.Errorf("expected folder size <%v>, received <%v>", 0, totalSize) + } + }) + + t.Run("DumpDataDB", func(t *testing.T) { + var reply string + if err := client.Call(context.Background(), utils.APIerSv1DumpDataDB, "", &reply); err != nil { + t.Error(err) + } + time.Sleep(50 * time.Millisecond) // wait for dump to finish + }) + + t.Run("CountDataDBFiles2", func(t *testing.T) { + var totalSize int64 + var dirs, files int + if err := filepath.Walk(cfg.DataDbCfg().Opts.InternalDBDumpPath, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + dirs++ + } else { + totalSize += info.Size() // Add the size of the file + files++ + } + return nil + }); err != nil { + t.Error(err) + } else if dirs != 43 { + t.Errorf("expected <%d> directories, received <%d>", 43, dirs) + } else if files != 42 { + t.Errorf("expected 42 files, received <%d>", files) + } + if totalSize < 35500 || totalSize > 35700 { + t.Errorf("expected folder size to be within range 35500KB to 35700KB, received <%v>KB", totalSize) + } + }) + +} + +func TestOfflineInternalAPIsDumpStorDB(t *testing.T) { + + if err := os.MkdirAll("/tmp/internal_db/stordb", 0755); err != nil { + t.Fatal(err) + } + ng := engine.TestEngine{ + ConfigPath: path.Join(*utils.DataDir, "conf", "samples", "offline_internal_apis"), + GracefulShutdown: true, + PreserveStorDB: true, + DBCfg: engine.DBCfg{ + DataDB: engine.MongoDBCfg.DataDB, + }, + TpPath: path.Join(*utils.DataDir, "tariffplans", "testit"), + LogBuffer: &bytes.Buffer{}, + } + t.Cleanup(func() { + if err := os.RemoveAll("/tmp/internal_db"); err != nil { + t.Error(err) + } + }) + client, cfg := ng.Run(t) + time.Sleep(100 * time.Millisecond) + + t.Run("CountStorDBFiles", func(t *testing.T) { + var totalSize int64 + var dirs, files int + if err := filepath.Walk(cfg.StorDbCfg().Opts.InternalDBDumpPath, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + dirs++ + } else { + totalSize += info.Size() // Add the size of the file + files++ + } + return nil + }); err != nil { + t.Error(err) + } else if dirs != 28 { + t.Errorf("expected <%d> directories, received <%d>", 28, dirs) + } else if files != 27 { + t.Errorf("expected 27 files, received <%d>", files) + } + if totalSize != 0 { + t.Errorf("expected folder size <%v>, received <%v>", 0, totalSize) + } + }) + + t.Run("DumpStorDB", func(t *testing.T) { + var reply string + if err := client.Call(context.Background(), utils.APIerSv1DumpStorDB, "", &reply); err != nil { + t.Error(err) + } + time.Sleep(50 * time.Millisecond) // wait for dump to finish + }) + + t.Run("CountStorDBFiles2", func(t *testing.T) { + var totalSize int64 + var dirs, files int + if err := filepath.Walk(cfg.StorDbCfg().Opts.InternalDBDumpPath, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + dirs++ + } else { + totalSize += info.Size() // Add the size of the file + files++ + } + return nil + }); err != nil { + t.Error(err) + } else if dirs != 28 { + t.Errorf("expected <%d> directories, received <%d>", 28, dirs) + } else if files != 27 { + t.Errorf("expected 27 files, received <%d>", files) + } + if totalSize < 500 || totalSize > 1000 { + t.Errorf("expected folder size to be within range 35500KB to 35700KB, received <%v>KB", totalSize) + } + }) + +} diff --git a/utils/consts.go b/utils/consts.go index 079387659..31f25dac5 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -1725,6 +1725,12 @@ const ( APIerSv1RemoveTiming = "APIerSv1.RemoveTiming" APIerSV1GetAccountCost = "APIerSv1.GetAccountCost" APIerSV1TimingIsActiveAt = "APIerSv1.TimingIsActiveAt" + APIerSv1DumpDataDB = "APIerSv1.DumpDataDB" + APIerSv1RewriteDataDB = "APIerSv1.RewriteDataDB" + APIerSv1DumpStorDB = "APIerSv1.DumpStorDB" + APIerSv1RewriteStorDB = "APIerSv1.RewriteStorDB" + APIerSv1BackupDataDB = "APIerSv1.BackupDataDB" + APIerSv1BackupStorDB = "APIerSv1.BackupStorDB" ) // APIerSv1 TP APIs