mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Add tests for multiple DB conns
This commit is contained in:
committed by
Dan Christian Bogos
parent
a3f25d1ec5
commit
8af781fb75
@@ -1029,7 +1029,7 @@ func (cfg *CGRConfig) checkConfigSanity() error {
|
||||
for _, dbcfg := range cfg.dbCfg.DBConns {
|
||||
if dbcfg.Type == utils.MetaInternal {
|
||||
if hasOneInternalDB {
|
||||
return fmt.Errorf("<%s> There can only be 1 internal DataDB", utils.DB)
|
||||
return fmt.Errorf("<%s> There can only be 1 internal DB", utils.DB)
|
||||
}
|
||||
if (cfg.dbCfg.Opts.InternalDBDumpInterval != 0 ||
|
||||
cfg.dbCfg.Opts.InternalDBRewriteInterval != 0) &&
|
||||
|
||||
@@ -40,9 +40,13 @@
|
||||
}
|
||||
},
|
||||
"items":{
|
||||
"*charger_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false, "dbConn": "intrnl"},
|
||||
"*charger_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false, "dbConn": "redis2"},
|
||||
"*charger_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false, "dbConn": "redis2"},
|
||||
"*charger_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false, "dbConn": "intrnl"},
|
||||
"*cdrs": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false, "dbConn": "StorDB"}
|
||||
},
|
||||
"opts": {
|
||||
"internalDBDumpPath": "/tmp/internal_db/db",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -54,9 +58,9 @@
|
||||
|
||||
"attributes": {
|
||||
"enabled": true,
|
||||
"stats_conns": ["*localhost"],
|
||||
"resources_conns": ["*localhost"],
|
||||
"accounts_conns": ["*localhost"]
|
||||
"stats_conns": ["*internal"],
|
||||
"resources_conns": ["*internal"],
|
||||
"accounts_conns": ["*internal"]
|
||||
},
|
||||
|
||||
"chargers": {
|
||||
@@ -124,7 +128,7 @@
|
||||
|
||||
"actions": {
|
||||
"enabled": true,
|
||||
"accounts_conns": ["*localhost"]
|
||||
"accounts_conns": ["*internal"]
|
||||
},
|
||||
|
||||
|
||||
@@ -141,6 +145,16 @@
|
||||
|
||||
"tpes": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
|
||||
"loaders": [
|
||||
{
|
||||
"enabled":true,
|
||||
"id": "*default",
|
||||
"tp_in_dir": "/usr/share/cgrates/tariffplans/testit",
|
||||
"tp_out_dir": "",
|
||||
"lockfile_path": ".cgr.lck"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
154
data/conf/samples/multiple_dbs_mongo/cgrates.json
Normal file
154
data/conf/samples/multiple_dbs_mongo/cgrates.json
Normal file
@@ -0,0 +1,154 @@
|
||||
{
|
||||
|
||||
|
||||
"general": {
|
||||
"reply_timeout": "50s"
|
||||
},
|
||||
|
||||
"logger": {
|
||||
"level": 7
|
||||
},
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080"
|
||||
},
|
||||
|
||||
"db": {
|
||||
"db_conns": {
|
||||
"*default": { // using redis a default to see which files are dumped in internal
|
||||
"db_type": "*redis",
|
||||
"db_port": 6379,
|
||||
"db_name": "10"
|
||||
},
|
||||
"internalDBConn": {
|
||||
"db_type": "*internal"
|
||||
},
|
||||
"mongoDBConn": {
|
||||
"db_type": "mongo",
|
||||
"db_host": "127.0.0.1",
|
||||
"db_port": 27017,
|
||||
"db_name": "cgrates",
|
||||
"db_user": "cgrates"
|
||||
}
|
||||
},
|
||||
"items":{
|
||||
"*charger_profiles": {"dbConn": "mongoDBConn"},
|
||||
"*charger_filter_indexes" : {"dbConn": "internalDBConn"},
|
||||
"*cdrs": {"dbConn": "mongoDBConn"}
|
||||
},
|
||||
"opts": {
|
||||
"internalDBDumpPath": "/tmp/internal_db/db",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true,
|
||||
"chargers_conns":["*internal"]
|
||||
},
|
||||
|
||||
|
||||
"attributes": {
|
||||
"enabled": true,
|
||||
"stats_conns": ["*localhost"],
|
||||
"resources_conns": ["*localhost"],
|
||||
"accounts_conns": ["*localhost"]
|
||||
},
|
||||
|
||||
"chargers": {
|
||||
"enabled": true,
|
||||
"attributes_conns": ["*internal"]
|
||||
},
|
||||
|
||||
|
||||
"resources": {
|
||||
"enabled": true,
|
||||
"store_interval": "1s",
|
||||
"thresholds_conns": ["*internal"]
|
||||
},
|
||||
|
||||
|
||||
"stats": {
|
||||
"enabled": true,
|
||||
"store_interval": "1s",
|
||||
"thresholds_conns": ["*internal"]
|
||||
},
|
||||
|
||||
|
||||
"thresholds": {
|
||||
"enabled": true,
|
||||
"store_interval": "1s"
|
||||
},
|
||||
|
||||
|
||||
"routes": {
|
||||
"enabled": true,
|
||||
"prefix_indexed_fields":["*req.Destination"],
|
||||
"stats_conns": ["*internal"],
|
||||
"resources_conns": ["*internal"],
|
||||
"rates_conns": ["*internal"]
|
||||
},
|
||||
|
||||
|
||||
"sessions": {
|
||||
"enabled": true,
|
||||
"routes_conns": ["*internal"],
|
||||
"resources_conns": ["*internal"],
|
||||
"attributes_conns": ["*internal"],
|
||||
"rates_conns": ["*internal"],
|
||||
"cdrs_conns": ["*internal"],
|
||||
"chargers_conns": ["*internal"]
|
||||
},
|
||||
|
||||
|
||||
"migrator":{
|
||||
|
||||
"users_filters":["Account"]
|
||||
},
|
||||
|
||||
|
||||
"admins": {
|
||||
"enabled": true,
|
||||
"scheduler_conns": ["*internal"]
|
||||
},
|
||||
|
||||
|
||||
"rates": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
|
||||
"actions": {
|
||||
"enabled": true,
|
||||
"accounts_conns": ["*localhost"]
|
||||
},
|
||||
|
||||
|
||||
"accounts": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
|
||||
"filters": {
|
||||
"stats_conns": ["*internal"],
|
||||
"resources_conns": ["*internal"],
|
||||
"accounts_conns": ["*internal"]
|
||||
},
|
||||
|
||||
"tpes": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"loaders": [
|
||||
{
|
||||
"enabled":true,
|
||||
"id": "*default",
|
||||
"tp_in_dir": "/usr/share/cgrates/tariffplans/testit",
|
||||
"tp_out_dir": "",
|
||||
"lockfile_path": ".cgr.lck"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
@@ -18,14 +18,16 @@
|
||||
},
|
||||
"opts": {
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "-1"
|
||||
"internalDBDumpInterval": "-1",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"config_db": {
|
||||
"db_type": "*internal",
|
||||
"opts": {
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "-1"
|
||||
"internalDBDumpInterval": "-1",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"cdrs": {
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"opts":{
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "-1",
|
||||
"internalDBFileSizeLimit": "4KB"
|
||||
"internalDBFileSizeLimit": "4KB",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"config_db": {
|
||||
@@ -26,7 +27,8 @@
|
||||
"opts": {
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "-1",
|
||||
"internalDBFileSizeLimit": "4KB"
|
||||
"internalDBFileSizeLimit": "4KB",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"cdrs": {
|
||||
|
||||
@@ -17,14 +17,16 @@
|
||||
},
|
||||
"opts":{
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "500ms"
|
||||
"internalDBDumpInterval": "500ms",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"config_db": {
|
||||
"db_type": "*internal",
|
||||
"opts": {
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "500ms"
|
||||
"internalDBDumpInterval": "500ms",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"cdrs": {
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"opts":{
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "500ms",
|
||||
"internalDBFileSizeLimit": "4KB"
|
||||
"internalDBFileSizeLimit": "4KB",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"config_db": {
|
||||
@@ -26,7 +27,8 @@
|
||||
"opts": {
|
||||
"internalDBStartTimeout": "1m",
|
||||
"internalDBDumpInterval": "500ms",
|
||||
"internalDBFileSizeLimit": "4KB"
|
||||
"internalDBFileSizeLimit": "4KB",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
"cdrs": {
|
||||
|
||||
@@ -125,6 +125,35 @@ func StartEngine(cfgPath string, waitEngine int) (*exec.Cmd, error) {
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// Starts the engine from a string JSON config
|
||||
func StartEngineFromString(cfgJSON string, waitEngine int, t testing.TB) (*exec.Cmd, error) {
|
||||
cfgPath := t.TempDir()
|
||||
// A JSON configuration string has been passed to the object.
|
||||
// It can be standalone or used to overwrite sections from an
|
||||
// existing configuration file. In case it's the latter, ensure
|
||||
// the file is processed towards the end.
|
||||
filePath := filepath.Join(cfgPath, "zzz_dynamic_cgrates.json")
|
||||
if err := os.WriteFile(filePath, []byte(cfgJSON), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error
|
||||
cfg, err := config.NewCGRConfigFromPath(context.TODO(), cfgPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not init config from path %s: %v", cfgPath, err)
|
||||
}
|
||||
binPath, err := exec.LookPath("cgr-engine")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
flags := []string{"-config_path", cfg.ConfigPath}
|
||||
engine := exec.Command(binPath, flags...)
|
||||
if err := engine.Start(); err != nil {
|
||||
return nil, fmt.Errorf("cgr-engine command failed: %v", err)
|
||||
}
|
||||
time.Sleep(time.Duration(waitEngine) * time.Millisecond) // wait for rater to register all subsystems
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// StartEngineWithContext return reference towards the command started so we can stop it if necessary
|
||||
func StartEngineWithContext(ctx context.Context, cfgPath string, waitEngine int) (engine *exec.Cmd, err error) {
|
||||
engine = exec.CommandContext(ctx, "cgr-engine", "-config_path", cfgPath)
|
||||
|
||||
715
general_tests/multiple_dbs_it_test.go
Normal file
715
general_tests/multiple_dbs_it_test.go
Normal file
@@ -0,0 +1,715 @@
|
||||
//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 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 <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/birpc/context"
|
||||
"github.com/cgrates/cgrates/apis"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/loaders"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestMultipleDBs(t *testing.T) {
|
||||
if err := os.MkdirAll("/tmp/internal_db/db", 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := os.RemoveAll("/tmp/internal_db"); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
ng := engine.TestEngine{
|
||||
ConfigPath: filepath.Join(*utils.DataDir, "conf", "samples", "multiple_dbs"),
|
||||
GracefulShutdown: true,
|
||||
Encoding: *utils.Encoding,
|
||||
}
|
||||
client, cfg := ng.Run(t)
|
||||
t.Run("LoadTariffPlans", func(t *testing.T) {
|
||||
var reply string
|
||||
if err := client.Call(context.Background(), utils.LoaderSv1Run,
|
||||
&loaders.ArgsProcessFolder{
|
||||
APIOpts: map[string]any{
|
||||
utils.MetaCache: utils.MetaNone,
|
||||
},
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply returned:", reply)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
})
|
||||
|
||||
t.Run("CheckChargers", func(t *testing.T) { // stored in redis2
|
||||
var chrgrs []*utils.ChargerProfile
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetChargerProfiles,
|
||||
&utils.ArgsItemIDs{
|
||||
Tenant: "cgrates.org",
|
||||
}, &chrgrs); err != nil {
|
||||
t.Errorf("AdminSv1GetChargerProfiles failed unexpectedly: %v", err)
|
||||
}
|
||||
if len(chrgrs) != 3 {
|
||||
t.Fatalf("AdminSv1GetChargerProfiles len(chrgrs)=%v, want 3", len(chrgrs))
|
||||
}
|
||||
sort.Slice(chrgrs, func(i, j int) bool {
|
||||
return chrgrs[i].ID > chrgrs[j].ID
|
||||
})
|
||||
exp := []*utils.ChargerProfile{
|
||||
{
|
||||
ID: "SupplierCharges",
|
||||
Tenant: "cgrates.org",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
RunID: "SupplierCharges",
|
||||
AttributeIDs: []string{"ATTR_SUPPLIER1"},
|
||||
},
|
||||
{
|
||||
ID: "Raw",
|
||||
Tenant: "cgrates.org",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
RunID: "raw",
|
||||
AttributeIDs: []string{"*constant:*req.RequestType:*none"},
|
||||
},
|
||||
{
|
||||
ID: "CustomerCharges",
|
||||
Tenant: "cgrates.org",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
RunID: "CustomerCharges",
|
||||
AttributeIDs: []string{"*none"},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(exp, chrgrs) {
|
||||
t.Errorf("Expected <%+v>,\n received <%+v>", exp, chrgrs)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CheckChargerFilterIndexes", func(t *testing.T) { // stored in internal
|
||||
var replyIdx []string
|
||||
expectedIDx := []string{"*none:*any:*any:CustomerCharges", "*none:*any:*any:Raw",
|
||||
"*none:*any:*any:SupplierCharges"}
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetFilterIndexes,
|
||||
&apis.AttrGetFilterIndexes{
|
||||
Tenant: utils.CGRateSorg,
|
||||
ItemType: utils.MetaChargers,
|
||||
},
|
||||
&replyIdx); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
sort.Strings(replyIdx)
|
||||
sort.Strings(expectedIDx)
|
||||
if !reflect.DeepEqual(expectedIDx, replyIdx) {
|
||||
t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expectedIDx), utils.ToJSON(replyIdx))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CheckAccounts", func(t *testing.T) { // stored in *default (redis in this case)
|
||||
var acnts []*utils.Account
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetAccounts,
|
||||
&utils.ArgsItemIDs{
|
||||
Tenant: "cgrates.org",
|
||||
}, &acnts); err != nil {
|
||||
t.Errorf("AdminSv2GetAccounts failed unexpectedly: %v", err)
|
||||
}
|
||||
if len(acnts) != 2 {
|
||||
t.Fatalf("AdminSv2GetAccounts len(acnts)=%v, want 2", len(acnts))
|
||||
}
|
||||
sort.Slice(acnts, func(i, j int) bool {
|
||||
return acnts[i].ID > acnts[j].ID
|
||||
})
|
||||
exp := []*utils.Account{
|
||||
{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ACC_PRF_1",
|
||||
Opts: map[string]any{},
|
||||
Balances: map[string]*utils.Balance{
|
||||
"MonetaryBalance": {
|
||||
ID: "MonetaryBalance",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
Type: "*monetary",
|
||||
Opts: map[string]any{},
|
||||
Units: utils.NewDecimal(14, 0),
|
||||
UnitFactors: []*utils.UnitFactor{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Factor: utils.NewDecimal(100, 0),
|
||||
},
|
||||
{
|
||||
FilterIDs: []string{"fltr3"},
|
||||
Factor: utils.NewDecimal(200, 0),
|
||||
},
|
||||
},
|
||||
CostIncrements: []*utils.CostIncrement{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Increment: utils.NewDecimal(13, 1),
|
||||
FixedFee: utils.NewDecimal(23, 1),
|
||||
RecurrentFee: utils.NewDecimal(33, 1),
|
||||
},
|
||||
},
|
||||
AttributeIDs: []string{"attr1", "attr2"},
|
||||
},
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
ThresholdIDs: []string{utils.MetaNone},
|
||||
},
|
||||
{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "1001",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
Opts: map[string]any{},
|
||||
Balances: map[string]*utils.Balance{
|
||||
"MonetaryBalance": {
|
||||
ID: "MonetaryBalance",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
Type: "*monetary",
|
||||
Opts: map[string]any{},
|
||||
Units: utils.NewDecimal(14, 0),
|
||||
UnitFactors: []*utils.UnitFactor{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Factor: utils.NewDecimal(100, 0),
|
||||
},
|
||||
{
|
||||
FilterIDs: []string{"fltr3"},
|
||||
Factor: utils.NewDecimal(200, 0),
|
||||
},
|
||||
},
|
||||
CostIncrements: []*utils.CostIncrement{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Increment: utils.NewDecimal(13, 1),
|
||||
FixedFee: utils.NewDecimal(23, 1),
|
||||
RecurrentFee: utils.NewDecimal(33, 1),
|
||||
},
|
||||
},
|
||||
AttributeIDs: []string{"attr1", "attr2"},
|
||||
},
|
||||
"VoiceBalance": {
|
||||
ID: "VoiceBalance",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
Blockers: utils.DynamicBlockers{
|
||||
{
|
||||
FilterIDs: []string{"*string:~*req.Destination:1002"},
|
||||
Blocker: true,
|
||||
},
|
||||
{
|
||||
Blocker: false,
|
||||
},
|
||||
},
|
||||
Type: "*voice",
|
||||
Opts: map[string]any{},
|
||||
Units: utils.NewDecimalFromUsageIgnoreErr("1h"),
|
||||
},
|
||||
},
|
||||
ThresholdIDs: []string{utils.MetaNone},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(exp, acnts) {
|
||||
t.Errorf("Expected <%+v>,\n received <%+v>", exp, acnts)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CheckCdrs", func(t *testing.T) { // stored in mysql
|
||||
var cdrs []*utils.CDR
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetCDRs, &utils.CDRFilters{Tenant: "cgrates.org"}, &cdrs); err == nil || err.Error() != "retrieving CDRs failed: NOT_FOUND" {
|
||||
t.Errorf("Expecting error <%v>, received: <%v>", "retrieving CDRs failed: NOT_FOUND", err)
|
||||
}
|
||||
ev := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TestEv1",
|
||||
Event: map[string]any{
|
||||
utils.ToR: utils.MetaVoice,
|
||||
utils.OriginID: "TestEv1",
|
||||
utils.RequestType: utils.MetaPrepaid,
|
||||
utils.AccountField: "1001",
|
||||
utils.Subject: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.Usage: time.Minute,
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
utils.MetaRates: true,
|
||||
utils.MetaAccounts: false,
|
||||
},
|
||||
}
|
||||
var rply string
|
||||
client.Call(context.Background(), utils.CDRsV1ProcessEvent, ev, &rply)
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetCDRs, &utils.CDRFilters{Tenant: "cgrates.org"}, &cdrs); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(cdrs) != 1 {
|
||||
t.Errorf("unexpected number of cdrs found: %v", len(cdrs))
|
||||
}
|
||||
exp := &utils.CDR{
|
||||
Tenant: utils.CGRateSorg,
|
||||
Opts: map[string]any{
|
||||
utils.MetaCDRID: cdrs[0].Opts[utils.MetaCDRID],
|
||||
utils.MetaRates: true,
|
||||
utils.MetaAccounts: false,
|
||||
},
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.OriginID: "TestEv1",
|
||||
utils.RequestType: utils.MetaPrepaid,
|
||||
utils.Subject: "1001",
|
||||
utils.ToR: utils.MetaVoice,
|
||||
utils.Usage: 6e+10,
|
||||
},
|
||||
CreatedAt: cdrs[0].CreatedAt,
|
||||
UpdatedAt: cdrs[0].UpdatedAt,
|
||||
}
|
||||
if !reflect.DeepEqual(exp, cdrs[0]) {
|
||||
t.Errorf("Expecting <%#v>, \nreceived <%#v>", exp, cdrs[0])
|
||||
}
|
||||
})
|
||||
t.Run("EngineShutdown", func(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CountDBFiles", func(t *testing.T) {
|
||||
var dirs, files int
|
||||
if err := filepath.WalkDir(cfg.DbCfg().Opts.InternalDBDumpPath, func(root string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
dirs++
|
||||
} else {
|
||||
if !strings.HasPrefix(root, "/tmp/internal_db/db/*charger_filter_indexes") &&
|
||||
!strings.HasPrefix(root, "/tmp/internal_db/db/*versions") {
|
||||
t.Fatalf("got unexpected folder <%s>", root)
|
||||
}
|
||||
files++
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
} else if dirs != 37 {
|
||||
t.Errorf("expected <%d> directories, received <%d>", 37, dirs)
|
||||
} else if files != 2 {
|
||||
t.Errorf("expected <%d> files, received <%d>", 2, files)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMultipleDBsMongo(t *testing.T) {
|
||||
if err := os.MkdirAll("/tmp/internal_db/db", 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := os.RemoveAll("/tmp/internal_db"); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
ng := engine.TestEngine{
|
||||
ConfigPath: filepath.Join(*utils.DataDir, "conf", "samples", "multiple_dbs_mongo"),
|
||||
GracefulShutdown: true,
|
||||
Encoding: *utils.Encoding,
|
||||
}
|
||||
client, cfg := ng.Run(t)
|
||||
t.Run("LoadTariffPlans", func(t *testing.T) {
|
||||
var reply string
|
||||
if err := client.Call(context.Background(), utils.LoaderSv1Run,
|
||||
&loaders.ArgsProcessFolder{
|
||||
APIOpts: map[string]any{
|
||||
utils.MetaCache: utils.MetaNone,
|
||||
},
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.OK {
|
||||
t.Error("Unexpected reply returned:", reply)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
})
|
||||
|
||||
t.Run("CheckChargers", func(t *testing.T) { // stored in mongo
|
||||
var chrgrs []*utils.ChargerProfile
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetChargerProfiles,
|
||||
&utils.ArgsItemIDs{
|
||||
Tenant: "cgrates.org",
|
||||
}, &chrgrs); err != nil {
|
||||
t.Errorf("AdminSv1GetChargerProfiles failed unexpectedly: %v", err)
|
||||
}
|
||||
if len(chrgrs) != 3 {
|
||||
t.Fatalf("AdminSv1GetChargerProfiles len(chrgrs)=%v, want 3", len(chrgrs))
|
||||
}
|
||||
sort.Slice(chrgrs, func(i, j int) bool {
|
||||
return chrgrs[i].ID > chrgrs[j].ID
|
||||
})
|
||||
exp := []*utils.ChargerProfile{
|
||||
{
|
||||
ID: "SupplierCharges",
|
||||
Tenant: "cgrates.org",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
RunID: "SupplierCharges",
|
||||
AttributeIDs: []string{"ATTR_SUPPLIER1"},
|
||||
},
|
||||
{
|
||||
ID: "Raw",
|
||||
Tenant: "cgrates.org",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
RunID: "raw",
|
||||
AttributeIDs: []string{"*constant:*req.RequestType:*none"},
|
||||
},
|
||||
{
|
||||
ID: "CustomerCharges",
|
||||
Tenant: "cgrates.org",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
RunID: "CustomerCharges",
|
||||
AttributeIDs: []string{"*none"},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(exp, chrgrs) {
|
||||
t.Errorf("Expected <%+v>,\n received <%+v>", exp, chrgrs)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CheckChargerFilterIndexes", func(t *testing.T) { // stored in internal
|
||||
var replyIdx []string
|
||||
expectedIDx := []string{"*none:*any:*any:CustomerCharges", "*none:*any:*any:Raw",
|
||||
"*none:*any:*any:SupplierCharges"}
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetFilterIndexes,
|
||||
&apis.AttrGetFilterIndexes{
|
||||
Tenant: utils.CGRateSorg,
|
||||
ItemType: utils.MetaChargers,
|
||||
},
|
||||
&replyIdx); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
sort.Strings(replyIdx)
|
||||
sort.Strings(expectedIDx)
|
||||
if !reflect.DeepEqual(expectedIDx, replyIdx) {
|
||||
t.Errorf("Expected %+v, \nreceived %+v", utils.ToJSON(expectedIDx), utils.ToJSON(replyIdx))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CheckAccounts", func(t *testing.T) { // stored in *default (redis in this case)
|
||||
var acnts []*utils.Account
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetAccounts,
|
||||
&utils.ArgsItemIDs{
|
||||
Tenant: "cgrates.org",
|
||||
}, &acnts); err != nil {
|
||||
t.Errorf("AdminSv2GetAccounts failed unexpectedly: %v", err)
|
||||
}
|
||||
if len(acnts) != 2 {
|
||||
t.Fatalf("AdminSv2GetAccounts len(acnts)=%v, want 2", len(acnts))
|
||||
}
|
||||
sort.Slice(acnts, func(i, j int) bool {
|
||||
return acnts[i].ID > acnts[j].ID
|
||||
})
|
||||
exp := []*utils.Account{
|
||||
{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ACC_PRF_1",
|
||||
Opts: map[string]any{},
|
||||
Balances: map[string]*utils.Balance{
|
||||
"MonetaryBalance": {
|
||||
ID: "MonetaryBalance",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
Type: "*monetary",
|
||||
Opts: map[string]any{},
|
||||
Units: utils.NewDecimal(14, 0),
|
||||
UnitFactors: []*utils.UnitFactor{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Factor: utils.NewDecimal(100, 0),
|
||||
},
|
||||
{
|
||||
FilterIDs: []string{"fltr3"},
|
||||
Factor: utils.NewDecimal(200, 0),
|
||||
},
|
||||
},
|
||||
CostIncrements: []*utils.CostIncrement{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Increment: utils.NewDecimal(13, 1),
|
||||
FixedFee: utils.NewDecimal(23, 1),
|
||||
RecurrentFee: utils.NewDecimal(33, 1),
|
||||
},
|
||||
},
|
||||
AttributeIDs: []string{"attr1", "attr2"},
|
||||
},
|
||||
},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
ThresholdIDs: []string{utils.MetaNone},
|
||||
},
|
||||
{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "1001",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 20,
|
||||
},
|
||||
},
|
||||
Opts: map[string]any{},
|
||||
Balances: map[string]*utils.Balance{
|
||||
"MonetaryBalance": {
|
||||
ID: "MonetaryBalance",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
Type: "*monetary",
|
||||
Opts: map[string]any{},
|
||||
Units: utils.NewDecimal(14, 0),
|
||||
UnitFactors: []*utils.UnitFactor{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Factor: utils.NewDecimal(100, 0),
|
||||
},
|
||||
{
|
||||
FilterIDs: []string{"fltr3"},
|
||||
Factor: utils.NewDecimal(200, 0),
|
||||
},
|
||||
},
|
||||
CostIncrements: []*utils.CostIncrement{
|
||||
{
|
||||
FilterIDs: []string{"fltr1", "fltr2"},
|
||||
Increment: utils.NewDecimal(13, 1),
|
||||
FixedFee: utils.NewDecimal(23, 1),
|
||||
RecurrentFee: utils.NewDecimal(33, 1),
|
||||
},
|
||||
},
|
||||
AttributeIDs: []string{"attr1", "attr2"},
|
||||
},
|
||||
"VoiceBalance": {
|
||||
ID: "VoiceBalance",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
{
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
Blockers: utils.DynamicBlockers{
|
||||
{
|
||||
FilterIDs: []string{"*string:~*req.Destination:1002"},
|
||||
Blocker: true,
|
||||
},
|
||||
{
|
||||
Blocker: false,
|
||||
},
|
||||
},
|
||||
Type: "*voice",
|
||||
Opts: map[string]any{},
|
||||
Units: utils.NewDecimalFromUsageIgnoreErr("1h"),
|
||||
},
|
||||
},
|
||||
ThresholdIDs: []string{utils.MetaNone},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(exp, acnts) {
|
||||
t.Errorf("Expected <%+v>,\n received <%+v>", exp, acnts)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CheckCdrs", func(t *testing.T) { // stored in mongo
|
||||
var cdrs []*utils.CDR
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetCDRs, &utils.CDRFilters{Tenant: "cgrates.org"}, &cdrs); err == nil || err.Error() != "retrieving CDRs failed: NOT_FOUND" {
|
||||
t.Errorf("Expecting error <%v>, received: <%v>", "retrieving CDRs failed: NOT_FOUND", err)
|
||||
}
|
||||
ev := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TestEv1",
|
||||
Event: map[string]any{
|
||||
utils.ToR: utils.MetaVoice,
|
||||
utils.OriginID: "TestEv1",
|
||||
utils.RequestType: utils.MetaPrepaid,
|
||||
utils.AccountField: "1001",
|
||||
utils.Subject: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.Usage: time.Minute,
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
utils.MetaRates: true,
|
||||
utils.MetaAccounts: false,
|
||||
},
|
||||
}
|
||||
var rply string
|
||||
client.Call(context.Background(), utils.CDRsV1ProcessEvent, ev, &rply)
|
||||
if err := client.Call(context.Background(), utils.AdminSv1GetCDRs, &utils.CDRFilters{Tenant: "cgrates.org"}, &cdrs); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(cdrs) != 1 {
|
||||
t.Errorf("unexpected number of cdrs found: %v", len(cdrs))
|
||||
}
|
||||
exp := &utils.CDR{
|
||||
Tenant: utils.CGRateSorg,
|
||||
Opts: map[string]any{
|
||||
utils.MetaCDRID: cdrs[0].Opts[utils.MetaCDRID],
|
||||
utils.MetaRates: true,
|
||||
utils.MetaAccounts: false,
|
||||
},
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.OriginID: "TestEv1",
|
||||
utils.RequestType: utils.MetaPrepaid,
|
||||
utils.Subject: "1001",
|
||||
utils.ToR: utils.MetaVoice,
|
||||
utils.Usage: 6e+10,
|
||||
},
|
||||
CreatedAt: cdrs[0].CreatedAt,
|
||||
UpdatedAt: cdrs[0].UpdatedAt,
|
||||
}
|
||||
if !reflect.DeepEqual(exp, cdrs[0]) {
|
||||
t.Errorf("Expecting <%#v>, \nreceived <%#v>", exp, cdrs[0])
|
||||
}
|
||||
})
|
||||
t.Run("EngineShutdown", func(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CountDBFiles", func(t *testing.T) {
|
||||
var dirs, files int
|
||||
if err := filepath.WalkDir(cfg.DbCfg().Opts.InternalDBDumpPath, func(root string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
dirs++
|
||||
} else {
|
||||
if !strings.HasPrefix(root, "/tmp/internal_db/db/*charger_filter_indexes") &&
|
||||
!strings.HasPrefix(root, "/tmp/internal_db/db/*versions") {
|
||||
t.Fatalf("got unexpected folder <%s>", root)
|
||||
}
|
||||
files++
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Error(err)
|
||||
} else if dirs != 37 {
|
||||
t.Errorf("expected <%d> directories, received <%d>", 37, dirs)
|
||||
} else if files != 2 {
|
||||
t.Errorf("expected <%d> files, received <%d>", 2, files)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMultipleDBsInternalFail(t *testing.T) {
|
||||
if err := os.MkdirAll("/tmp/internal_db/db", 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := os.RemoveAll("/tmp/internal_db"); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
cfgJSON := `{
|
||||
"logger": {
|
||||
"level": 7
|
||||
},
|
||||
|
||||
"db": {
|
||||
"db_conns": {
|
||||
"intrnl": {
|
||||
"db_type": "*internal"
|
||||
},
|
||||
},
|
||||
"items":{
|
||||
"*charger_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false, "dbConn": "intrnl"},
|
||||
},
|
||||
"opts": {
|
||||
"internalDBDumpPath": "/tmp/internal_db/db",
|
||||
"internalDBRewriteInterval": "0s"
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
`
|
||||
expErr := `/001: <db> There can only be 1 internal DB`
|
||||
if _, err := engine.StartEngineFromString(cfgJSON, 200, t); err == nil ||
|
||||
!strings.Contains(err.Error(), expErr) {
|
||||
t.Errorf("expected error <%v>, received <%v>", expErr, err)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,9 +62,6 @@ func TestOfflineInternal(t *testing.T) { // run with sudo
|
||||
if err := os.MkdirAll(dfltCfg.DbCfg().Opts.InternalDBDumpPath, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// if err := os.MkdirAll(dfltCfg.StorDbCfg().Opts.InternalDBDumpPath, 0755); err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
if err := os.MkdirAll(dfltCfg.ConfigDBCfg().Opts.InternalDBDumpPath, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user