From a0f94c68041c7a9acf787e78dee602b6b14767d3 Mon Sep 17 00:00:00 2001 From: arberkatellari Date: Tue, 11 Jun 2024 17:12:57 +0200 Subject: [PATCH] Add/Update unit and integration tests adjusting for sessions backup --- apier/v1/config_it_test.go | 4 +- config/config_it_test.go | 5 +- config/config_json_test.go | 10 +- config/config_test.go | 13 +- config/generalcfg.go | 5 +- config/generalcfg_test.go | 4 +- config/sessionscfg_test.go | 2 + general_tests/accounts_it_test.go | 2 +- general_tests/balance_it_test.go | 3 +- .../session_bkup_interval_it_test.go | 352 ++++++++++ services/datadb_it_test.go | 1 + services/ers_it_test.go | 1 + services/sessions_it_test.go | 16 +- sessions/sessions_bkup_it_test.go | 627 ++++++++++++++++++ sessions/sessions_bkup_rpl_it_test.go | 401 +++++++++++ sessions/sessions_test.go | 29 +- sessions/sessionscover_test.go | 23 +- utils/reflect_test.go | 19 + 18 files changed, 1474 insertions(+), 43 deletions(-) create mode 100644 general_tests/session_bkup_interval_it_test.go create mode 100644 sessions/sessions_bkup_it_test.go create mode 100644 sessions/sessions_bkup_rpl_it_test.go diff --git a/apier/v1/config_it_test.go b/apier/v1/config_it_test.go index 39a51c51a..2c0362d14 100644 --- a/apier/v1/config_it_test.go +++ b/apier/v1/config_it_test.go @@ -165,6 +165,7 @@ func testConfigSSetConfigSessionS(t *testing.T) { "scheduler_conns": []any{}, "thresholds_conns": []any{}, "stats_conns": []any{}, + utils.BackupIntervalCfg: "0", "min_dur_low_balance": "0", "stir": map[string]any{ "allowed_attest": []any{utils.MetaAny}, @@ -232,7 +233,7 @@ func testConfigSSetConfigSessionS(t *testing.T) { }, &rpl); err != nil { t.Error(err) } else if !reflect.DeepEqual(exp, rpl) { - t.Errorf("Expected %+v , received: %+v ", utils.ToJSON(exp), utils.ToJSON(rpl)) + t.Errorf("Expected %+v , \nreceived: %+v ", utils.ToJSON(exp), utils.ToJSON(rpl)) } } @@ -259,6 +260,7 @@ func testConfigSv1GetJSONSectionWithoutTenant(t *testing.T) { "session_ttl": "0", "stale_chan_max_extra_usage": "0", "store_session_costs": false, + utils.BackupIntervalCfg: "0", "min_dur_low_balance": "0", "alterable_fields": []any{}, "stir": map[string]any{ diff --git a/config/config_it_test.go b/config/config_it_test.go index 75eb3c7dc..1ffde468f 100644 --- a/config/config_it_test.go +++ b/config/config_it_test.go @@ -1053,11 +1053,12 @@ func testCGRConfigReloadConfigFromStringSessionS(t *testing.T) { } var rcv string - expected := `{"sessions":{"alterable_fields":[],"attributes_conns":["*localhost"],"cdrs_conns":["*internal"],"channel_sync_interval":"0","chargers_conns":["*localhost"],"client_protocol":2,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":true,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":["*internal"],"replication_conns":[],"resources_conns":["*localhost"],"routes_conns":["*localhost"],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]}}` + expected := `{"sessions":{"alterable_fields":[],"attributes_conns":["*localhost"],"backup_interval":"0","cdrs_conns":["*internal"],"channel_sync_interval":"0","chargers_conns":["*localhost"],"client_protocol":2,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":true,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":["*internal"],"replication_conns":[],"resources_conns":["*localhost"],"routes_conns":["*localhost"],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]}}` + if err := cfg.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: SessionSJson}, &rcv); err != nil { t.Error(err) } else if expected != rcv { - t.Errorf("Expected: %+q, \n received: %s", expected, rcv) + t.Errorf("Expected: %s, \n received: %s", expected, rcv) } } diff --git a/config/config_json_test.go b/config/config_json_test.go index f69fde674..564bc894e 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -532,6 +532,13 @@ func TestDfDataDbJsonCfg(t *testing.T) { Ttl: utils.StringPointer(utils.EmptyString), Static_ttl: utils.BoolPointer(false), }, + utils.MetaSessionsBackup: { + Replicate: utils.BoolPointer(false), + Remote: utils.BoolPointer(false), + Limit: utils.IntPointer(-1), + Ttl: utils.StringPointer(utils.EmptyString), + Static_ttl: utils.BoolPointer(false), + }, }, } dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON)) @@ -843,6 +850,7 @@ func TestSmgJsonCfg(t *testing.T) { Stale_chan_max_extra_usage: utils.StringPointer("0"), Terminate_attempts: utils.IntPointer(5), Alterable_fields: &[]string{}, + Backup_interval: utils.StringPointer("0s"), Default_usage: &map[string]string{ utils.MetaAny: "3h", utils.MetaVoice: "3h", @@ -865,7 +873,7 @@ func TestSmgJsonCfg(t *testing.T) { if cfg, err := dfCgrJSONCfg.SessionSJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, cfg) { - t.Errorf("Expecting: %s, received: %s", utils.ToJSON(eCfg), utils.ToJSON(cfg)) + t.Errorf("Expecting: %s, \nreceived: %s", utils.ToJSON(eCfg), utils.ToJSON(cfg)) } } diff --git a/config/config_test.go b/config/config_test.go index 3b8534f10..ef4e78a04 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -501,6 +501,7 @@ func TestCgrCfgJSONDefaultsSMGenericCfg(t *testing.T) { DebitInterval: 0, StoreSCosts: false, SessionTTL: 0, + BackupInterval: 0, SessionIndexes: utils.StringSet{}, ClientProtocol: 2.0, ChannelSyncInterval: 0, @@ -2112,6 +2113,7 @@ func TestSessionSConfig(t *testing.T) { DebitInterval: 0, StoreSCosts: false, SessionTTL: 0, + BackupInterval: 0, SessionIndexes: utils.StringSet{}, ClientProtocol: 2.0, ChannelSyncInterval: 0, @@ -3590,7 +3592,7 @@ func TestV1GetConfigGeneral(t *testing.T) { utils.DefaultTenantCfg: "cgrates.org", utils.DefaultTimezoneCfg: "Local", utils.DefaultCachingCfg: "*reload", - utils.CachingDlayCfg: 0 * time.Second, + utils.CachingDlayCfg: "0", utils.ConnectAttemptsCfg: 5, utils.ReconnectsCfg: -1, utils.MaxReconnectIntervalCfg: "0", @@ -3891,6 +3893,7 @@ func TestV1GetConfigSessionS(t *testing.T) { utils.SessionIndexesCfg: []string{}, utils.ClientProtocolCfg: 2.0, utils.SessionTTLCfg: "0", + utils.BackupIntervalCfg: "0", utils.ChannelSyncIntervalCfg: "0", utils.StaleChanMaxExtraUsageCfg: "0", utils.TerminateAttemptsCfg: 5, @@ -4822,7 +4825,7 @@ func TestV1GetConfigAsJSONGeneral(t *testing.T) { "node_id": "ENGINE1", } }` - expected := `{"general":{"caching_delay":0,"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"}}` + expected := `{"general":{"caching_delay":"0","connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"}}` if cfgCgr, err := NewCGRConfigFromJSONStringWithDefaults(strJSON); err != nil { t.Error(err) } else if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: GENERAL_JSN}, &reply); err != nil { @@ -4834,7 +4837,7 @@ func TestV1GetConfigAsJSONGeneral(t *testing.T) { func TestV1GetConfigAsJSONDataDB(t *testing.T) { var reply string - expected := `{"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false}}` + expected := `{"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*sessions_backup":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false}}` cfgCgr := NewDefaultCGRConfig() if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: DATADB_JSN}, &reply); err != nil { t.Error(err) @@ -4944,7 +4947,7 @@ func TestV1GetConfigAsJSONCdrs(t *testing.T) { func TestV1GetConfigAsJSONSessionS(t *testing.T) { var reply string - expected := `{"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":2,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]}}` + expected := `{"sessions":{"alterable_fields":[],"attributes_conns":[],"backup_interval":"0","cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":2,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]}}` cfgCgr := NewDefaultCGRConfig() if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: SessionSJson}, &reply); err != nil { t.Error(err) @@ -5357,7 +5360,7 @@ func TestV1GetConfigAsJSONAllConfig(t *testing.T) { }` var reply string cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSON) - expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*processRuns":1,"*profileIDs":[],"*profileIgnoreFilters":false,"*profileRuns":0},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*radius_packets":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*rating_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*shared_groups":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"prevent_loop":false,"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"concurrent_events":1,"ees_conns":[],"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"active_session_delimiter":",","create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5,"reply_timeout":"1m0s"}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"caching_delay":0,"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"MaxReconnectInterval","tag":"MaxReconnectInterval","type":"*variable","value":"~*req.6"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.7"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.8"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.9"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.10"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.11"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"*redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"0s","mysqlDSNParams":null,"mysqlLocation":"","pgSSLMode":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":0,"sqlMaxOpenConns":0},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"*mysql","out_stordb_user":"cgrates","users_filters":null},"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"coa_template":"*coa","dmr_template":"*dmr","enabled":false,"listeners":[{"acct_address":"127.0.0.1:1813","auth_address":"127.0.0.1:1812","network":"udp"}],"request_processors":[],"requests_cache_key":"","sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"fallback_depth":3,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"sessions_conns":[],"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*context":"*routes","*ignoreErrors":false,"*maxCost":""},"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"sags":{"enabled":false},"sars":{"enabled":false,"stats_conns":[]},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sentrypeer":{"Audience":"https://sentrypeer.com/api","ClientID":"","ClientSecret":"","GrantType":"client_credentials","IpUrl":"https://sentrypeer.com/api/ip-addresses","NumberUrl":"https://sentrypeer.com/api/phone-numbers","TokenURL":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":2,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"CGRateS.org","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*session_costs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_account_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_attributes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_chargers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destination_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_routes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_stats":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","pgSchema":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*coa":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Filter-Id","tag":"Filter-Id","type":"*variable","value":"~*req.CustomFilter"}],"*dmr":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Reply-Message","tag":"Reply-Message","type":"*variable","value":"~*req.DisconnectCause"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}` + expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*processRuns":1,"*profileIDs":[],"*profileIgnoreFilters":false,"*profileRuns":0},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*radius_packets":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*rating_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*shared_groups":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*sessions_backup":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"prevent_loop":false,"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"concurrent_events":1,"ees_conns":[],"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"active_session_delimiter":",","create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5,"reply_timeout":"1m0s"}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"caching_delay":"0","connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"MaxReconnectInterval","tag":"MaxReconnectInterval","type":"*variable","value":"~*req.6"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.7"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.8"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.9"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.10"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.11"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"*redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"0s","mysqlDSNParams":null,"mysqlLocation":"","pgSSLMode":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":0,"sqlMaxOpenConns":0},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"*mysql","out_stordb_user":"cgrates","users_filters":null},"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"coa_template":"*coa","dmr_template":"*dmr","enabled":false,"listeners":[{"acct_address":"127.0.0.1:1813","auth_address":"127.0.0.1:1812","network":"udp"}],"request_processors":[],"requests_cache_key":"","sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"fallback_depth":3,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"sessions_conns":[],"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*context":"*routes","*ignoreErrors":false,"*maxCost":""},"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"sags":{"enabled":false},"sars":{"enabled":false,"stats_conns":[]},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sentrypeer":{"Audience":"https://sentrypeer.com/api","ClientID":"","ClientSecret":"","GrantType":"client_credentials","IpUrl":"https://sentrypeer.com/api/ip-addresses","NumberUrl":"https://sentrypeer.com/api/phone-numbers","TokenURL":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"alterable_fields":[],"attributes_conns":[],"backup_interval":"0","cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":2,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"CGRateS.org","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*session_costs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_account_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_attributes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_chargers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destination_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_routes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_stats":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","pgSchema":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*coa":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Filter-Id","tag":"Filter-Id","type":"*variable","value":"~*req.CustomFilter"}],"*dmr":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Reply-Message","tag":"Reply-Message","type":"*variable","value":"~*req.DisconnectCause"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}` if err != nil { t.Fatal(err) } diff --git a/config/generalcfg.go b/config/generalcfg.go index 9aa90919a..e6ae2eb54 100644 --- a/config/generalcfg.go +++ b/config/generalcfg.go @@ -167,7 +167,7 @@ func (gencfg *GeneralCfg) AsMapInterface() (initialMP map[string]any) { utils.DefaultTenantCfg: gencfg.DefaultTenant, utils.DefaultTimezoneCfg: gencfg.DefaultTimezone, utils.DefaultCachingCfg: gencfg.DefaultCaching, - utils.CachingDlayCfg: gencfg.CachingDelay, + utils.CachingDlayCfg: "0", utils.ConnectAttemptsCfg: gencfg.ConnectAttempts, utils.ReconnectsCfg: gencfg.Reconnects, utils.MaxReconnectIntervalCfg: "0", @@ -201,6 +201,9 @@ func (gencfg *GeneralCfg) AsMapInterface() (initialMP map[string]any) { initialMP[utils.ReplyTimeoutCfg] = gencfg.ReplyTimeout.String() } + if gencfg.CachingDelay != 0 { + initialMP[utils.CachingDlayCfg] = gencfg.CachingDelay.String() + } return } diff --git a/config/generalcfg_test.go b/config/generalcfg_test.go index e3d0e96fc..aa2438601 100644 --- a/config/generalcfg_test.go +++ b/config/generalcfg_test.go @@ -165,7 +165,7 @@ func TestGeneralCfgAsMapInterface(t *testing.T) { utils.DefaultTenantCfg: "cgrates.org", utils.DefaultTimezoneCfg: "Local", utils.DefaultCachingCfg: "*reload", - utils.CachingDlayCfg: 0 * time.Second, + utils.CachingDlayCfg: "0", utils.ConnectAttemptsCfg: 5, utils.ReconnectsCfg: -1, utils.MaxReconnectIntervalCfg: "1s", @@ -210,7 +210,7 @@ func TestGeneralCfgAsMapInterface1(t *testing.T) { utils.DefaultTenantCfg: "cgrates.org", utils.DefaultTimezoneCfg: "Local", utils.DefaultCachingCfg: "*reload", - utils.CachingDlayCfg: 0 * time.Second, + utils.CachingDlayCfg: "0", utils.ConnectAttemptsCfg: 5, utils.ReconnectsCfg: -1, utils.MaxReconnectIntervalCfg: "0", diff --git a/config/sessionscfg_test.go b/config/sessionscfg_test.go index b1264ae0d..0229d4796 100644 --- a/config/sessionscfg_test.go +++ b/config/sessionscfg_test.go @@ -369,6 +369,7 @@ func TestSessionSCfgAsMapInterfaceCase1(t *testing.T) { utils.TerminateAttemptsCfg: 5, utils.MinDurLowBalanceCfg: "0", utils.AlterableFieldsCfg: []string{}, + utils.BackupIntervalCfg: "0", utils.STIRCfg: map[string]any{ utils.AllowedAtestCfg: []string{"*any"}, utils.PayloadMaxdurationCfg: "-1", @@ -444,6 +445,7 @@ func TestSessionSCfgAsMapInterfaceCase2(t *testing.T) { utils.StaleChanMaxExtraUsageCfg: "0", utils.TerminateAttemptsCfg: 10, utils.AlterableFieldsCfg: []string{}, + utils.BackupIntervalCfg: "0", utils.STIRCfg: map[string]any{ utils.AllowedAtestCfg: []string{"any1", "any2"}, utils.PayloadMaxdurationCfg: "1s", diff --git a/general_tests/accounts_it_test.go b/general_tests/accounts_it_test.go index bb3ab168c..f5242354a 100644 --- a/general_tests/accounts_it_test.go +++ b/general_tests/accounts_it_test.go @@ -287,7 +287,7 @@ func testV1AccSendToThreshold(t *testing.T) { } // give time to threshold to made the change - time.Sleep(10 * time.Millisecond) + time.Sleep(100 * time.Millisecond) //verify the account var acnt *engine.Account attrAcc := &utils.AttrGetAccount{ diff --git a/general_tests/balance_it_test.go b/general_tests/balance_it_test.go index 662f917f4..4e7c87217 100644 --- a/general_tests/balance_it_test.go +++ b/general_tests/balance_it_test.go @@ -317,7 +317,8 @@ func TestBalanceFactor(t *testing.T) { "enabled": true, "cdrs_conns": ["*internal"], "chargers_conns": ["*internal"], - "rals_conns": ["*internal"] + "rals_conns": ["*internal"], + "backup_interval": "-1" }, "chargers": { diff --git a/general_tests/session_bkup_interval_it_test.go b/general_tests/session_bkup_interval_it_test.go new file mode 100644 index 000000000..83d6041ba --- /dev/null +++ b/general_tests/session_bkup_interval_it_test.go @@ -0,0 +1,352 @@ +//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 ( + "fmt" + "path" + "testing" + "time" + + "github.com/cgrates/birpc" + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/sessions" + "github.com/cgrates/cgrates/utils" +) + +var ( + sBkupCfgPath string + sBkupCfgDIR string + sBkupCfg *config.CGRConfig + sBkupRPC *birpc.Client + dDB engine.DataDB + + SessionsBkupIntrvlTests = []func(t *testing.T){ + testSessionSBkupIntrvlInitCfg, + testSessionSBkupIntrvlResetDB, + testSessionSBkupIntrvlStartEngine, + testSessionSBkupIntrvlApierRpcConn, + testSessionSBkupIntrvlLoadTP, + testSessionSBkupIntrvlInitiate, + testSessionSBkupIntrvlConcurrentAPIWithInterval, + testSessionSBkupIntrvlGetBackedupSessions1, + testSessionSBkupIntrvlStopCgrEngine, + + testSessionSBkupIntrvlStartEngine, + testSessionSBkupIntrvlApierRpcConn, + testSessionSBkupIntrvlGetActiveSessionsTerminate, + testSessionSBkupIntrvlGetBackedupSessions2, + testSessionSBkupIntrvlStopCgrEngine, + + testSessionSBkupIntrvlStartEngine, + testSessionSBkupIntrvlApierRpcConn, + testSessionSBkupIntrvlGetActiveSessions0, + testSessionSBkupIntrvlStopCgrEngine, + } +) + +func TestSessionsBkupIntrvl(t *testing.T) { + switch *utils.DBType { + case utils.MetaInternal: + t.SkipNow() + case utils.MetaMySQL: + sBkupCfgDIR = "sessions_backup_interval_mysql" + case utils.MetaMongo: + sBkupCfgDIR = "sessions_backup_interval_mongo" + case utils.MetaPostgres: + sBkupCfgDIR = "sessions_backup_interval_postgres" + default: + t.Fatal("Unknown Database type") + } + for _, stest := range SessionsBkupIntrvlTests { + t.Run(*utils.DBType, stest) + } +} + +func testSessionSBkupIntrvlInitCfg(t *testing.T) { + sBkupCfgPath = path.Join(*utils.DataDir, "conf", "samples", sBkupCfgDIR) + if sBkupCfg, err = config.NewCGRConfigFromPath(sBkupCfgPath); err != nil { + t.Fatal(err) + } +} + +// Remove data in both rating and accounting db +func testSessionSBkupIntrvlResetDB(t *testing.T) { + if err := engine.InitDataDb(sBkupCfg); err != nil { + t.Fatal(err) + } + if err := engine.InitStorDb(sBkupCfg); err != nil { + t.Fatal(err) + } +} + +// Start CGR Engine +func testSessionSBkupIntrvlStartEngine(t *testing.T) { + if _, err := engine.StartEngine(sBkupCfgPath, *utils.WaitRater); err != nil { + t.Fatal(err) + } +} + +// Connect rpc client to rater +func testSessionSBkupIntrvlApierRpcConn(t *testing.T) { + if sBkupRPC, err = newRPCClient(sBkupCfg.ListenCfg()); err != nil { + t.Fatal(err) + } +} + +// Load the tariff plan, creating accounts and their balances +func testSessionSBkupIntrvlLoadTP(t *testing.T) { + tpFiles := map[string]string{ + utils.AccountActionsCsv: `#Tenant,Account,ActionPlanId,ActionTriggersId,AllowNegative,Disabled +cgrates.org,1001,AP_PACKAGE_10,,, +cgrates.org,1002,AP_PACKAGE_10,,,`, + utils.ActionPlansCsv: `#Id,ActionsId,TimingId,Weight +AP_PACKAGE_10,ACT_TOPUP_RST_10,*asap,10`, + utils.ActionsCsv: `#ActionsId[0],Action[1],ExtraParameters[2],Filter[3],BalanceId[4],BalanceType[5],Categories[6],DestinationIds[7],RatingSubject[8],SharedGroup[9],ExpiryTime[10],TimingIds[11],Units[12],BalanceWeight[13],BalanceBlocker[14],BalanceDisabled[15],Weight[16] +ACT_TOPUP_RST_10,*topup_reset,,,test,*monetary,,*any,,,*unlimited,,100000000000000,10,false,false,10`, + utils.ChargersCsv: `#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight +cgrates.org,DEFAULT,,,*default,*none,0`, + utils.DestinationRatesCsv: `#Id,DestinationId,RatesTag,RoundingMethod,RoundingDecimals,MaxCost,MaxCostStrategy +DR_ANY_20CNT,*any,RT_20CNT,*up,4,0,`, + utils.RatesCsv: `#Id,ConnectFee,Rate,RateUnit,RateIncrement,GroupIntervalStart +RT_20CNT,0,1,1s,1s,0s`, + utils.RatingPlansCsv: `#Id,DestinationRatesId,TimingTag,Weight +RP_ANY,DR_ANY_20CNT,*any,10`, + utils.RatingProfilesCsv: `#Tenant,Category,Subject,ActivationTime,RatingPlanId,RatesFallbackSubject +cgrates.org,call,*any,2014-01-14T00:00:00Z,RP_ANY,`, + } + + loadCSVs(t, sBkupRPC, "", t.TempDir(), tpFiles) + + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) +} + +func testSessionSBkupIntrvlInitiate(t *testing.T) { + var aSessions []*sessions.ExternalSession + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + + for i := 1; i <= 500; i++ { + strI := fmt.Sprint(i) + usage := time.Duration(i) * time.Second + argsInit := &sessions.V1InitSessionArgs{ + InitSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "Test_" + strI, + Event: map[string]any{ + utils.EventName: "EVENT_" + strI, + utils.Tenant: "cgrates.org", + utils.OriginID: strI, + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1002", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 0, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 10, 0, time.UTC), + utils.Usage: usage, + }, + }, + } + + var initRpl sessions.V1InitSessionReply + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1InitiateSession, + argsInit, &initRpl); err != nil { + t.Error(err) + } + if initRpl.MaxUsage == nil || *initRpl.MaxUsage != usage { + t.Errorf("i <%v> Expecting : %+v, received: %+v", i, usage, initRpl.MaxUsage) + } + } + + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 500 { + t.Errorf("Unexpected number of sessions received: <%+v>\n%+v", len(aSessions), utils.ToIJSON(aSessions)) + } + for _, session := range aSessions { + found := false + for i := 1; i <= 500; i++ { + strI := fmt.Sprint(i) + if session.OriginID == strI && session.Usage == time.Duration(i)*time.Second && session.Source == "SessionS_EVENT_"+strI { + found = true + break + } + } + if !found { + t.Errorf("Session not found: %+v", session) + } + } +} + +// try to reach concurrency by calling backup API multiple times while "backup_interval" runs in background +func testSessionSBkupIntrvlConcurrentAPIWithInterval(t *testing.T) { + for i := 0; i <= 1000; i++ { + var sessionsBackedup int + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1BackupActiveSessions, + utils.EmptyString, &sessionsBackedup); err != nil { + t.Fatal(err) + } else if sessionsBackedup != 500 { + t.Errorf("Expected 500 backedup sessions. Backed up: %+v", sessionsBackedup) + } + } +} + +func testSessionSBkupIntrvlGetBackedupSessions1(t *testing.T) { + + if *utils.DBType == utils.MetaMySQL || *utils.DBType == utils.MetaPostgres { + dDB, err = engine.NewRedisStorage( + fmt.Sprintf("%s:%s", sBkupCfg.DataDbCfg().Host, sBkupCfg.DataDbCfg().Port), + 10, sBkupCfg.DataDbCfg().User, sBkupCfg.DataDbCfg().Password, sBkupCfg.GeneralCfg().DBDataEncoding, + 10, 20, "", false, 5*time.Second, 0, 0, 0, 0, false, utils.EmptyString, utils.EmptyString, utils.EmptyString) + if err != nil { + t.Fatal("Could not connect to Redis", err.Error()) + } + } + if *utils.DBType == utils.MetaMongo { + dDB, err = engine.NewMongoStorage("mongodb", sBkupCfg.DataDbCfg().Host, + sBkupCfg.DataDbCfg().Port, sBkupCfg.DataDbCfg().Name, + sBkupCfg.DataDbCfg().User, sBkupCfg.DataDbCfg().Password, + sBkupCfg.GeneralCfg().DBDataEncoding, + utils.StorDB, nil, 10*time.Second) + if err != nil { + t.Fatal(err) + } + } + + // wait for all sessions to be backedup, 2 intervals to make sure all sessions had time to be stored + time.Sleep(1000 * time.Millisecond) + storedSessions, err := dDB.GetSessionsBackupDrv(sBkupCfg.GeneralCfg().NodeID, + sBkupCfg.GeneralCfg().DefaultTenant) + if err != nil { + t.Error(err) + } + + if len(storedSessions) != 500 { + t.Fatalf("Expected 500 sessions stored, received %v", len(storedSessions)) + } + for _, oneSess := range storedSessions { + var found bool + for i := 1; i <= 500; i++ { + strI := fmt.Sprint(i) + if oneSess.ResourceID == strI && oneSess.SRuns[0].TotalUsage == time.Duration(i)*time.Second { + found = true + break + } + } + if !found { + for i := range oneSess.SRuns { + t.Errorf("Session not found: <%+v>, SRun<%+v>", oneSess, oneSess.SRuns[i]) + } + } + } +} + +func testSessionSBkupIntrvlGetActiveSessionsTerminate(t *testing.T) { + var aSessions []*sessions.ExternalSession + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 500 { + t.Errorf("Unexpected number of sessions received: <%+v>\n%+v", len(aSessions), utils.ToIJSON(aSessions)) + } + for _, session := range aSessions { + found := false + for i := 1; i <= 500; i++ { + strI := fmt.Sprint(i) + if session.OriginID == strI && session.Usage == time.Duration(i)*time.Second && session.Source == "SessionS_EVENT_"+strI { + found = true + break + } + } + if !found { + t.Errorf("Session not found: %+v", session) + } + } + + var replyTerminate string + for i := 1; i <= 500; i++ { + strI := fmt.Sprint(i) + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1TerminateSession, + &sessions.V1TerminateSessionArgs{ + TerminateSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "Test_" + strI, + Event: map[string]any{ + utils.EventName: "EVENT_" + strI, + utils.Tenant: "cgrates.org", + utils.OriginID: strI, + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1002", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 3, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 13, 0, time.UTC), + utils.Usage: time.Duration(2 * time.Second), + }, + }, + }, &replyTerminate); err != nil { + t.Fatal(err) + } else if replyTerminate != utils.OK { + t.Errorf("Expected reply , received <%+v>", replyTerminate) + } + } + time.Sleep(1 * time.Second) // Wait for 2 500ms intervals so we are sure it removed all terminated sessions from dataDB +} +func testSessionSBkupIntrvlGetBackedupSessions2(t *testing.T) { + storedSessions, err := dDB.GetSessionsBackupDrv(sBkupCfg.GeneralCfg().NodeID, + sBkupCfg.GeneralCfg().DefaultTenant) + if err != utils.ErrNoBackupFound { + t.Error(err) + } + if len(storedSessions) != 0 { // Sessions terminated should instantly be removed from the backup + t.Errorf("Expected 0 sessions in backup, received %v", len(storedSessions)) + } +} + +func testSessionSBkupIntrvlGetActiveSessions0(t *testing.T) { + var aSessions []*sessions.ExternalSession + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testSessionSBkupIntrvlStopCgrEngine(t *testing.T) { + if err := engine.KillEngine(1000); err != nil { + t.Error(err) + } +} diff --git a/services/datadb_it_test.go b/services/datadb_it_test.go index d7c8174fa..a2416a2fb 100644 --- a/services/datadb_it_test.go +++ b/services/datadb_it_test.go @@ -130,6 +130,7 @@ func TestDataDBReload(t *testing.T) { utils.MetaChargerProfiles: {Limit: -1}, utils.MetaDispatcherProfiles: {Limit: -1}, utils.MetaLoadIDs: {Limit: -1}, + utils.MetaSessionsBackup: {Limit: -1}, utils.CacheVersions: {Limit: -1}, utils.CacheResourceFilterIndexes: {Limit: -1}, diff --git a/services/ers_it_test.go b/services/ers_it_test.go index 23fa03529..76e852eb1 100644 --- a/services/ers_it_test.go +++ b/services/ers_it_test.go @@ -90,6 +90,7 @@ func TestEventReaderSReload(t *testing.T) { } time.Sleep(10 * time.Millisecond) runtime.Gosched() + time.Sleep(100 * time.Millisecond) if !erS.IsRunning() { t.Fatalf("Expected service to be running") } diff --git a/services/sessions_it_test.go b/services/sessions_it_test.go index 664ae6866..1739c3452 100644 --- a/services/sessions_it_test.go +++ b/services/sessions_it_test.go @@ -102,7 +102,11 @@ func TestSessionSReload1(t *testing.T) { utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): clientConect, }) anz := NewAnalyzerService(cfg, server, filterSChan, shdChan, make(chan birpc.ClientConnector, 1), srvDep) - srv := NewSessionService(cfg, new(DataDBService), server, make(chan birpc.ClientConnector, 1), shdChan, conMng, anz, srvDep) + dmService := NewDataDBService(cfg, conMng, srvDep) + if err := dmService.Start(); err != nil { + t.Fatal(err) + } + srv := NewSessionService(cfg, dmService, server, make(chan birpc.ClientConnector, 1), shdChan, conMng, anz, srvDep) err := srv.Start() if err != nil { t.Fatal(err) @@ -133,9 +137,8 @@ func TestSessionSReload1(t *testing.T) { rply := new(sessions.V1InitSessionReply) srv.(*SessionService).sm.BiRPCv1InitiateSession(context.Background(), args, rply) - err = srv.Shutdown() - if err == nil || err != utils.ErrPartiallyExecuted { - t.Fatalf("\nExpecting <%+v>,\n Received <%+v>", utils.ErrPartiallyExecuted, err) + if err = srv.Shutdown(); err != nil { + t.Error(err) } } @@ -252,9 +255,12 @@ func TestSessionSReload3(t *testing.T) { if !srv.IsRunning() { t.Fatalf("\nExpecting service to be running") } + go func() { + time.Sleep(10 * time.Millisecond) + server.StopBiRPC() + }() err2 := srv.(*SessionService).start() if err2 != nil { t.Fatalf("\nExpected <%+v>, \nReceived <%+v>", nil, err2) } - } diff --git a/sessions/sessions_bkup_it_test.go b/sessions/sessions_bkup_it_test.go new file mode 100644 index 000000000..24791e46a --- /dev/null +++ b/sessions/sessions_bkup_it_test.go @@ -0,0 +1,627 @@ +//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 sessions + +import ( + "fmt" + "path" + "testing" + "time" + + "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 ( + sBkupCfgPath string + sBkupCfgDIR string + sBkupCfg *config.CGRConfig + sBkupRPC *birpc.Client + dataDB engine.DataDB + updatedAt time.Time + + SessionsBkupTests = []func(t *testing.T){ + testSessionSBkupInitCfg, + testSessionSBkupResetDB, + testSessionSBkupStartEngine, + testSessionSBkupApierRpcConn, + testSessionSBkupTPFromFolder, + testSessionSBkupInitiate, + testSessionSBkupStopCgrEngine, + + testSessionSBkupStartEngine, + testSessionSBkupApierRpcConn, + testSessionSBkupCheckRestored1, + testSessionSBkupTerminate1, + testSessionSBkupStopCgrEngine, + + testSessionSBkupStartEngine, + testSessionSBkupApierRpcConn, + testSessionSBkupCheckRestored2, + testSessionSBkupTerminate2, + testSessionSBkupStopCgrEngine, + + testSessionSBkupStartEngine, + testSessionSBkupApierRpcConn, + testSessionSBkupCheckRestored3, + testSessionSBkupStopCgrEngine, + + testSessionSBkupStartEngine, + testSessionSBkupApierRpcConn, + testSessionSBkupCallBackup1, + testSessionSBkupInitiate, + testSessionSBkupCallBackup2, + testSessionSBkupGetBackedupSessions, + testSessionSBkupUpdateTerminate, + testSessionSBkupCallBackup3, + testSessionSBkupCheckUpdatedAt, + testSessionSBkupStopCgrEngine, + + testSessionSBkupStartEngine, + testSessionSBkupApierRpcConn, + testSessionSBkupCheckUpdatedNotExpired, + testSessionSBkupStopCgrEngine, + + testSessionSBkupStartEngine, + testSessionSBkupApierRpcConn, + testSessionSBkupCheckUpdatedExpired, + testSessionSBkupStopCgrEngine, + } +) + +func TestSessionsBkup(t *testing.T) { + switch *utils.DBType { + case utils.MetaInternal: + t.SkipNow() + case utils.MetaMySQL: + sBkupCfgDIR = "sessions_backup_mysql" + case utils.MetaMongo: + sBkupCfgDIR = "sessions_backup_mongo" + case utils.MetaPostgres: + sBkupCfgDIR = "sessions_backup_postgres" + default: + t.Fatal("Unknown Database type") + } + for _, stest := range SessionsBkupTests { + t.Run(*utils.DBType, stest) + } +} + +func testSessionSBkupInitCfg(t *testing.T) { + sBkupCfgPath = path.Join(*utils.DataDir, "conf", "samples", sBkupCfgDIR) + if sBkupCfg, err = config.NewCGRConfigFromPath(sBkupCfgPath); err != nil { + t.Fatal(err) + } +} + +// Remove data in both rating and accounting db +func testSessionSBkupResetDB(t *testing.T) { + if err := engine.InitDataDb(sBkupCfg); err != nil { + t.Fatal(err) + } + if err := engine.InitStorDb(sBkupCfg); err != nil { + t.Fatal(err) + } +} + +// Start CGR Engine +func testSessionSBkupStartEngine(t *testing.T) { + if _, err := engine.StartEngine(sBkupCfgPath, *utils.WaitRater); err != nil { + t.Fatal(err) + } +} + +// Connect rpc client to rater +func testSessionSBkupApierRpcConn(t *testing.T) { + if sBkupRPC, err = newRPCClient(sBkupCfg.ListenCfg()); err != nil { + t.Fatal(err) + } +} + +// Load the tariff plan, creating accounts and their balances +func testSessionSBkupTPFromFolder(t *testing.T) { + attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*utils.DataDir, "tariffplans", "oldtutorial")} + var loadInst utils.LoadInstance + if err := sBkupRPC.Call(context.Background(), utils.APIerSv2LoadTariffPlanFromFolder, attrs, &loadInst); err != nil { + t.Error(err) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Give time for scheduler to execute topups +} + +func testSessionSBkupInitiate(t *testing.T) { + var aSessions []*ExternalSession + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + + usage := time.Duration(90 * time.Second) + argsInit := &V1InitSessionArgs{ + InitSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestBkupSessionExpiresAfter3s", + Event: map[string]any{ + utils.EventName: "TEST_EVENT1", + utils.Tenant: "cgrates.org", + utils.OriginID: "123450", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 0, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 10, 0, time.UTC), + utils.Usage: usage, + }, + }, + } + + var initRpl V1InitSessionReply + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1InitiateSession, + argsInit, &initRpl); err != nil { + t.Error(err) + } + //compare the value + if initRpl.MaxUsage == nil || *initRpl.MaxUsage != usage { + t.Errorf("Expecting : %+v, received: %+v", usage, initRpl.MaxUsage) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Wait for the sessions to be populated + // Delay further 4 seconds to make the session unrestorable (session expiries in 4s in configs) + time.Sleep(4 * time.Second) + + //check if the session was createad as active session + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } else if aSessions[0].Usage != usage { + t.Errorf("Expecting : %+v, received: %+v", usage, aSessions[0].Usage) + } + + usage = time.Duration(120 * time.Second) + argsInit = &V1InitSessionArgs{ + InitSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestBkupSession2", + Event: map[string]any{ + utils.EventName: "TEST_EVENT2", + utils.Tenant: "cgrates.org", + utils.OriginID: "123452", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 2, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 12, 0, time.UTC), + utils.Usage: usage, + }, + }, + } + + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1InitiateSession, + argsInit, &initRpl); err != nil { + t.Error(err) + } + //compare the value + if initRpl.MaxUsage == nil || *initRpl.MaxUsage != usage { + t.Errorf("Expecting : %+v, received: %+v", usage, initRpl.MaxUsage) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Wait for the sessions to be populated + + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 2 { + t.Errorf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } + for _, extSess := range aSessions { + if extSess.OriginID == "123452" { + if extSess.Usage != usage { + t.Errorf("OriginID: <123452>, Expecting : %+v, received: %+v", usage, extSess.Usage) + } + } + } + + usage = time.Duration(150 * time.Second) + argsInit = &V1InitSessionArgs{ + InitSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestBkupSession1", + Event: map[string]any{ + utils.EventName: "TEST_EVENT1", + utils.Tenant: "cgrates.org", + utils.OriginID: "123451", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 3, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 13, 0, time.UTC), + utils.Usage: usage, + }, + }, + } + + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1InitiateSession, + argsInit, &initRpl); err != nil { + t.Error(err) + } + //compare the value + if initRpl.MaxUsage == nil || *initRpl.MaxUsage != usage { + t.Errorf("Expecting : %+v, received: %+v", usage, initRpl.MaxUsage) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Wait for the sessions to be populated + + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 3 { + t.Errorf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } + for _, extSess := range aSessions { + if extSess.OriginID == "123451" { + if extSess.Usage != usage { + t.Errorf("OriginID: <123451>, Expecting : %+v, received: %+v", usage, extSess.Usage) + } + } + } +} + +func testSessionSBkupCheckRestored1(t *testing.T) { + var aSessions []*ExternalSession + usage1 := time.Duration(120 * time.Second) + usage2 := time.Duration(150 * time.Second) + //check if the sessions were restored + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 2 { + t.Fatalf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } + for _, extSess := range aSessions { + switch { + case extSess.OriginID == "123451": + if extSess.Usage != usage2 { + t.Errorf("OriginID: <123451>, Expecting : %+v, received: %+v", usage2, extSess.Usage) + } + case extSess.OriginID == "123452": + if extSess.Usage != usage1 { + t.Errorf("OriginID: <123452>, Expecting : %+v, received: %+v", usage1, extSess.Usage) + } + default: + t.Fatalf("Unexpected OriginID <%v> present in the session", extSess.OriginID) + } + } +} + +func testSessionSBkupTerminate1(t *testing.T) { + var replyTerminate string + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1TerminateSession, + &V1TerminateSessionArgs{ + TerminateSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestBkupSession1", + Event: map[string]any{ + utils.EventName: "TEST_EVENT1", + utils.Tenant: "cgrates.org", + utils.OriginID: "123451", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 3, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 13, 0, time.UTC), + }, + }, + }, &replyTerminate); err != nil { + t.Error(err) + } + if replyTerminate != utils.OK { + t.Errorf("Expected reply , received <%+v>", replyTerminate) + } +} + +func testSessionSBkupCheckRestored2(t *testing.T) { + var aSessions []*ExternalSession + usage1 := time.Duration(120 * time.Second) + //check if the sessions were restored + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Fatal(err) + } else if len(aSessions) != 1 { + t.Fatalf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } + if aSessions[0].OriginID == "123452" { + if aSessions[0].Usage != usage1 { + t.Errorf("OriginID: <123452>, Expecting : %+v, received: %+v", usage1, aSessions[0].Usage) + } + } +} + +func testSessionSBkupTerminate2(t *testing.T) { + var replyTerminate string + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1TerminateSession, + &V1TerminateSessionArgs{ + TerminateSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestBkupSession2", + Event: map[string]any{ + utils.EventName: "TEST_EVENT2", + utils.Tenant: "cgrates.org", + utils.OriginID: "123452", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 2, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 12, 0, time.UTC), + }, + }, + }, &replyTerminate); err != nil { + t.Error(err) + } + if replyTerminate != utils.OK { + t.Errorf("Expected reply , received <%+v>", replyTerminate) + } +} + +func testSessionSBkupCheckRestored3(t *testing.T) { + var aSessions []*ExternalSession + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + if len(aSessions) != 0 { + t.Errorf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } +} + +func testSessionSBkupCallBackup1(t *testing.T) { + var sessionsBackedup int + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1BackupActiveSessions, + utils.EmptyString, &sessionsBackedup); err != nil { + t.Error(err) + } else if sessionsBackedup != 0 { + t.Errorf("Expected 0 backedup sessions. Backed up: %+v", sessionsBackedup) + } +} + +func testSessionSBkupCallBackup2(t *testing.T) { + var sessionsBackedup int + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1BackupActiveSessions, + utils.EmptyString, &sessionsBackedup); err != nil { + t.Fatal(err) + } else if sessionsBackedup != 3 { + t.Errorf("Expected 3 backedup sessions. Backed up: %+v", sessionsBackedup) + } +} + +func testSessionSBkupGetBackedupSessions(t *testing.T) { + + if *utils.DBType == utils.MetaMySQL || *utils.DBType == utils.MetaPostgres { + dataDB, err = engine.NewRedisStorage( + fmt.Sprintf("%s:%s", sBkupCfg.DataDbCfg().Host, sBkupCfg.DataDbCfg().Port), + 10, sBkupCfg.DataDbCfg().User, sBkupCfg.DataDbCfg().Password, sBkupCfg.GeneralCfg().DBDataEncoding, + 10, 20, "", false, 5*time.Second, 0, 0, 0, 0, false, utils.EmptyString, utils.EmptyString, utils.EmptyString) + if err != nil { + t.Fatal("Could not connect to Redis", err.Error()) + } + } + if *utils.DBType == utils.MetaMongo { + dataDB, err = engine.NewMongoStorage("mongodb", sBkupCfg.DataDbCfg().Host, + sBkupCfg.DataDbCfg().Port, sBkupCfg.DataDbCfg().Name, + sBkupCfg.DataDbCfg().User, sBkupCfg.DataDbCfg().Password, + sBkupCfg.GeneralCfg().DBDataEncoding, + utils.StorDB, nil, 10*time.Second) + if err != nil { + t.Fatal(err) + } + } + + var getBackSess []*Session + storedSessions, err := dataDB.GetSessionsBackupDrv(sBkupCfg.GeneralCfg().NodeID, + sBkupCfg.GeneralCfg().DefaultTenant) + if err != nil { + t.Error(err) + } + for _, storSess := range storedSessions { + sess := newSessionFromStoredSession(storSess) + getBackSess = append(getBackSess, sess) + } + + if len(getBackSess) != 3 { // even though one of them expired, we are not restoring them currently so in db there should be 3 sessions stored + t.Fatalf("Expected 3 sessions stored, received %v", len(getBackSess)) + } + for _, oneSess := range getBackSess { + switch { + case oneSess.ResourceID == "123450": + if oneSess.totalUsage() != time.Duration(90*time.Second) { + t.Errorf("Expected <%v>, received <%v>", time.Duration(90*time.Second), oneSess.totalUsage()) + } + case oneSess.ResourceID == "123451": + if oneSess.totalUsage() != time.Duration(150*time.Second) { + t.Errorf("Expected <%v>, received <%v>", time.Duration(150*time.Second), oneSess.totalUsage()) + } + case oneSess.ResourceID == "123452": + if oneSess.totalUsage() != time.Duration(120*time.Second) { + t.Errorf("Expected <%v>, received <%v>", time.Duration(120*time.Second), oneSess.totalUsage()) + } + updatedAt = oneSess.UpdatedAt + } + } + +} + +func testSessionSBkupUpdateTerminate(t *testing.T) { + updatedUsage := time.Duration(200 * time.Second) + var upRply V1UpdateSessionReply + upArgs := &V1UpdateSessionArgs{ + UpdateSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestBkupSession2", + Event: map[string]any{ + utils.EventName: "TEST_EVENT2", + utils.Tenant: "cgrates.org", + utils.OriginID: "123452", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 2, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 12, 0, time.UTC), + utils.Usage: updatedUsage, + }, + }, + } + if err = sBkupRPC.Call(context.Background(), utils.SessionSv1UpdateSession, upArgs, &upRply); err != nil { + t.Error(err) + } else if *upRply.MaxUsage != updatedUsage { + t.Errorf("Expected <%+v>, Received <%+v>", updatedUsage, *upRply.MaxUsage) + } + + args := &V1TerminateSessionArgs{ + TerminateSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestBkupSession1", + Event: map[string]any{ + utils.EventName: "TEST_EVENT1", + utils.Tenant: "cgrates.org", + utils.OriginID: "123451", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2024, time.March, 7, 16, 60, 3, 0, time.UTC), + utils.AnswerTime: time.Date(2024, time.March, 7, 16, 60, 13, 0, time.UTC), + utils.Usage: time.Duration(160 * time.Second), + }, + }, + } + var rply string + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1TerminateSession, + args, &rply); err != nil { + t.Error(err) + } + if rply != utils.OK { + t.Errorf("Unexpected reply: %s", rply) + } +} + +func testSessionSBkupCallBackup3(t *testing.T) { + var sessionsBackedup int + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1BackupActiveSessions, + utils.EmptyString, &sessionsBackedup); err != nil { + t.Fatal(err) + } else if sessionsBackedup != 2 { // should've backed up 2 since we terminated one of them + t.Errorf("Expected 2 backedup sessions. Backed up: %+v", sessionsBackedup) + } +} + +func testSessionSBkupCheckUpdatedAt(t *testing.T) { + var getBackSess []*Session + storedSessions, err := dataDB.GetSessionsBackupDrv(sBkupCfg.GeneralCfg().NodeID, + sBkupCfg.GeneralCfg().DefaultTenant) + if err != nil { + t.Error(err) + } + for _, storSess := range storedSessions { + sess := newSessionFromStoredSession(storSess) + getBackSess = append(getBackSess, sess) + } + + if len(getBackSess) != 2 { // even though one of them expired, we are not restoring them currently so in db there should be 2 sessions stored + t.Fatalf("Expected 2 sessions stored, received %v", len(getBackSess)) + } + for _, oneSess := range getBackSess { + switch { + case oneSess.ResourceID == "123450": + if oneSess.totalUsage() != time.Duration(90*time.Second) { + t.Errorf("Expected <%v>, received <%v>", time.Duration(90*time.Second), oneSess.totalUsage()) + } + case oneSess.ResourceID == "123452": + if oneSess.totalUsage() != time.Duration(320*time.Second) { // usage should be updated to 320 seconds + t.Errorf("Expected <%v>, received <%v>", time.Duration(320*time.Second), oneSess.totalUsage()) + } + if oneSess.UpdatedAt == updatedAt { + t.Errorf("Expected UpdatedAt field to be changed on update. Received the same time as before <%+v>", oneSess.UpdatedAt) + } + } + } +} + +func testSessionSBkupCheckUpdatedNotExpired(t *testing.T) { + var aSessions []*ExternalSession + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Fatalf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } + if aSessions[0].OriginID != "123452" { + t.Errorf("Expected backed up session source 123452, received <%+v>", aSessions[0].OriginID) + } + time.Sleep(4 * time.Second) // Wait for updated session to expire +} + +func testSessionSBkupCheckUpdatedExpired(t *testing.T) { + var aSessions []*ExternalSession + if err := sBkupRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } else if len(aSessions) != 0 { + t.Fatalf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } +} + +func testSessionSBkupStopCgrEngine(t *testing.T) { + if err := engine.KillEngine(1000); err != nil { + t.Error(err) + } +} diff --git a/sessions/sessions_bkup_rpl_it_test.go b/sessions/sessions_bkup_rpl_it_test.go new file mode 100644 index 000000000..a02a34b85 --- /dev/null +++ b/sessions/sessions_bkup_rpl_it_test.go @@ -0,0 +1,401 @@ +//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 sessions + +import ( + "fmt" + "os/exec" + "path" + "testing" + "time" + + "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 ( + sBRplcEng1CfgPath, sBRplcEng2CfgPath string + sBRplcEng1CfgDIR, sBRplcEng2CfgDIR string + sBRplcEng1Cfg, sBRplcEng2Cfg *config.CGRConfig + sBRplcEng1RPC, sBRplcEng2RPC *birpc.Client + sBRplcEng1Eng, sBRplcEng2Eng *exec.Cmd + + SessionsBkupRplTests = []func(t *testing.T){ + testSessionSBkupRplcInitCfg, + testSessionSBkupRplcResetDB, + testSessionSBkupRplcStartEngineBoth, + testSessionSBkupRplcApierRpcConnBoth, + testSessionSBkupRplcTPFromFolder, + testSessionSBkupRplcInitiate, + testSessionSBkupRplcGetSessions, + testSessionSBkupRplcUpdate, + testSessionSBkupRplcStartEngine2, + testSessionSBkupRplcApierRpcConn2, + testSessionSBkupRplcGetActvSessionsFromRestored, + testSessionSBkupRplcTerminate, + testSessionSBkupRplcStopCgrEngine, + + testSessionSBkupRplcStartEngine2, + testSessionSBkupRplcApierRpcConn2, + testSessionSBkupRplcGetNoActvSessionsFromRestored, + testSessionSBkupRplcStopCgrEngine, + } +) + +func TestSessionSBkupRplc(t *testing.T) { + switch *utils.DBType { + case utils.MetaInternal: + t.SkipNow() + case utils.MetaMySQL: + sBRplcEng1CfgDIR = "sbkupreplcengine1_mysql" + sBRplcEng2CfgDIR = "sbkupreplcengine2_mongo" + case utils.MetaMongo: + sBRplcEng1CfgDIR = "sbkupreplcengine1_mongo" + sBRplcEng2CfgDIR = "sbkupreplcengine2_mysql" + case utils.MetaPostgres: + sBRplcEng1CfgDIR = "sbkupreplcengine1_postgres" + sBRplcEng2CfgDIR = "sbkupreplcengine2_mongo" + default: + t.Fatal("Unknown Database type") + } + if *utils.Encoding == utils.MetaGOB { + sBRplcEng1CfgDIR += "_gob" + sBRplcEng2CfgDIR += "_gob" + } + for _, stest := range SessionsBkupRplTests { + t.Run(*utils.DBType, stest) + } +} + +func testSessionSBkupRplcInitCfg(t *testing.T) { + sBRplcEng1CfgPath = path.Join(*utils.DataDir, "conf", "samples", sBRplcEng1CfgDIR) + if sBRplcEng1Cfg, err = config.NewCGRConfigFromPath(sBRplcEng1CfgPath); err != nil { + t.Fatal(err) + } + sBRplcEng2CfgPath = path.Join(*utils.DataDir, "conf", "samples", sBRplcEng2CfgDIR) + if sBRplcEng2Cfg, err = config.NewCGRConfigFromPath(sBRplcEng2CfgPath); err != nil { + t.Fatal(err) + } +} + +// Remove data in both rating and accounting db +func testSessionSBkupRplcResetDB(t *testing.T) { + if err := engine.InitDataDb(sBRplcEng1Cfg); err != nil { + t.Fatal(err) + } + if err := engine.InitStorDb(sBRplcEng1Cfg); err != nil { + t.Fatal(err) + } + if err := engine.InitDataDb(sBRplcEng2Cfg); err != nil { + t.Fatal(err) + } + if err := engine.InitStorDb(sBRplcEng2Cfg); err != nil { + t.Fatal(err) + } +} + +// Start CGR Engine +func testSessionSBkupRplcStartEngineBoth(t *testing.T) { + if sBRplcEng2Eng, err = engine.StopStartEngine(sBRplcEng2CfgPath, *utils.WaitRater); err != nil { // Start engine2 before engine1 + t.Fatal(err) + } + if sBRplcEng1Eng, err = engine.StartEngine(sBRplcEng1CfgPath, *utils.WaitRater); err != nil { + t.Fatal(err) + } +} + +// Connect rpc client to rater +func testSessionSBkupRplcApierRpcConnBoth(t *testing.T) { + if sBRplcEng1RPC, err = newRPCClient(sBRplcEng1Cfg.ListenCfg()); err != nil { + t.Fatal(err) + } + if sBRplcEng2RPC, err = newRPCClient(sBRplcEng2Cfg.ListenCfg()); err != nil { + t.Fatal(err) + } +} + +// Load the tariff plan, creating accounts and their balances +func testSessionSBkupRplcTPFromFolder(t *testing.T) { + attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*utils.DataDir, "tariffplans", "oldtutorial")} + var loadInst utils.LoadInstance + if err := sBRplcEng1RPC.Call(context.Background(), utils.APIerSv2LoadTariffPlanFromFolder, attrs, &loadInst); err != nil { + t.Error(err) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Give time for scheduler to execute topups + attrs = &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*utils.DataDir, "tariffplans", "oldtutorial")} + if err := sBRplcEng2RPC.Call(context.Background(), utils.APIerSv2LoadTariffPlanFromFolder, attrs, &loadInst); err != nil { + t.Error(err) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Give time for scheduler to execute topups +} + +func testSessionSBkupRplcInitiate(t *testing.T) { + var aSessions []*ExternalSession + //make sure we don't have active sessions on engine1 and passive on engine2 + if err := sBRplcEng1RPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + + usage := time.Minute + 30*time.Second + argsInit := &V1InitSessionArgs{ + InitSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestSessionSBkupRplcInitiate", + Event: map[string]any{ + utils.EventName: "TEST_EVENT", + utils.Tenant: "cgrates.org", + utils.OriginID: "123451", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2018, time.January, 7, 16, 60, 0, 0, time.UTC), + utils.AnswerTime: time.Date(2018, time.January, 7, 16, 60, 10, 0, time.UTC), + utils.Usage: usage, + }, + }, + } + + var initRpl V1InitSessionReply + if err := sBRplcEng1RPC.Call(context.Background(), utils.SessionSv1InitiateSession, + argsInit, &initRpl); err != nil { + t.Error(err) + } + //compare the value + if initRpl.MaxUsage == nil || *initRpl.MaxUsage != usage { + t.Errorf("Expecting : %+v, received: %+v", usage, initRpl.MaxUsage) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Wait for the sessions to be populated + + //check if the session was createad as active session on engine1 + if err := sBRplcEng1RPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + utils.SessionFilter{ + Filters: []string{ + fmt.Sprintf("*string:~*req.%s:%s", utils.OriginID, "123451"), + }, + }, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } else if aSessions[0].Usage != 90*time.Second { + t.Errorf("Expecting : %+v, received: %+v", 90*time.Second, aSessions[0].Usage) + } + + //check if the session was created as passive session on engine2 + var pSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, + utils.SessionFilter{ + Filters: []string{ + fmt.Sprintf("*string:~*req.%s:%s", utils.OriginID, "123451"), + }, + }, &pSessions); err != nil { + t.Error(err) + } else if len(pSessions) != 1 { + t.Errorf("PassiveSessions: %+v", pSessions) + } else if pSessions[0].Usage != 90*time.Second { + t.Errorf("Expecting : %+v, received: %+v", 90*time.Second, pSessions[0].Usage) + } +} + +func testSessionSBkupRplcGetSessions(t *testing.T) { + time.Sleep(501 * time.Millisecond) // make sure active sessions are backed up from "backup_interval" + if err := sBRplcEng1Eng.Process.Kill(); err != nil { + t.Errorf("Failed to kill process, error: %v", err.Error()) + } + // make sure we have no active sessions on engine2 + var aSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + // make sure we have passive sessions on engine2 + var pSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, + utils.SessionFilter{}, &pSessions); err != nil { + t.Error(err) + } else if len(pSessions) != 1 { + t.Errorf("PassiveSessions: %+v", pSessions) + } else if pSessions[0].Usage != 90*time.Second { + t.Errorf("Expecting : %+v, received: %+v", 90*time.Second, pSessions[0].Usage) + } +} + +func testSessionSBkupRplcUpdate(t *testing.T) { + //update the session on engine2 so the session should became active + usage := time.Minute + argsUpdate := &V1UpdateSessionArgs{ + UpdateSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestSessionSBkupRplcUpdate", + Event: map[string]any{ + utils.EventName: "TEST_EVENT", + utils.Tenant: "cgrates.org", + utils.OriginID: "123451", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2018, time.January, 7, 16, 60, 0, 0, time.UTC), + utils.AnswerTime: time.Date(2018, time.January, 7, 16, 60, 10, 0, time.UTC), + utils.Usage: usage, + }, + }, + } + var updtRpl V1UpdateSessionReply + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1UpdateSession, + argsUpdate, &updtRpl); err != nil { + t.Error(err) + } + if updtRpl.MaxUsage == nil || *updtRpl.MaxUsage != usage { + t.Errorf("Expecting : %+v, received: %+v", usage, updtRpl.MaxUsage) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Wait for the sessions to be populated + + var aSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + utils.SessionFilter{ + Filters: []string{ + fmt.Sprintf("*string:~*req.%s:%s", utils.OriginID, "123451"), + }, + }, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } else if aSessions[0].Usage != 150*time.Second { + t.Errorf("Expecting : %+v, received: %+v", 150*time.Second, aSessions[0].Usage) + } + + var pSessions []*ExternalSession + // Make sure we don't have passive session on active host + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, new(utils.SessionFilter), + &pSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + time.Sleep(501 * time.Millisecond) // make sure active sessions are backed up from "backup_interval" + if err := sBRplcEng2Eng.Process.Kill(); err != nil { + t.Errorf("Failed to kill process, error: %v", err.Error()) + } +} + +func testSessionSBkupRplcStartEngine2(t *testing.T) { + if sBRplcEng2Eng, err = engine.StopStartEngine(sBRplcEng2CfgPath, *utils.WaitRater); err != nil { + t.Fatal(err) + } +} + +func testSessionSBkupRplcApierRpcConn2(t *testing.T) { + if sBRplcEng2RPC, err = newRPCClient(sBRplcEng2Cfg.ListenCfg()); err != nil { + t.Fatal(err) + } +} + +func testSessionSBkupRplcGetActvSessionsFromRestored(t *testing.T) { + var aSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + utils.SessionFilter{}, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", utils.ToIJSON(aSessions)) + } else if aSessions[0].Usage != 150*time.Second { + t.Errorf("Expecting : %+v, received: %+v", 150*time.Second, aSessions[0].Usage) + } + + var pSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, + new(utils.SessionFilter), &pSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testSessionSBkupRplcTerminate(t *testing.T) { + args := &V1TerminateSessionArgs{ + TerminateSession: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "TestSessionSBkupRplcTerminate", + Event: map[string]any{ + utils.EventName: "TEST_EVENT", + utils.Tenant: "cgrates.org", + utils.OriginID: "123451", + utils.ToR: utils.MetaVoice, + utils.RequestType: utils.MetaPrepaid, + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1004", + utils.Category: "call", + utils.SetupTime: time.Date(2018, time.January, 7, 16, 60, 0, 0, time.UTC), + utils.AnswerTime: time.Date(2018, time.January, 7, 16, 60, 10, 0, time.UTC), + utils.Usage: 2*time.Minute + 30*time.Second, + }, + }, + } + var reply string + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1TerminateSession, args, &reply); err != nil { + t.Error(err) + } + time.Sleep(time.Duration(*utils.WaitRater) * time.Millisecond) // Wait for the sessions to be populated + var aSessions []*ExternalSession + //check if the session was terminated on engine2 + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + new(utils.SessionFilter), &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Errorf("Error: %v with len(aSessions)=%v , session : %+v", err, len(aSessions), utils.ToIJSON(aSessions)) + } + // make sure we don't have passive session on engine2 + var pSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, new(utils.SessionFilter), + &pSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Errorf("Error: %v with len(pSessions)=%v , session : %+v", err, len(pSessions), utils.ToIJSON(pSessions)) + } +} + +func testSessionSBkupRplcGetNoActvSessionsFromRestored(t *testing.T) { + var aSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + utils.SessionFilter{}, &aSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } + + var pSessions []*ExternalSession + if err := sBRplcEng2RPC.Call(context.Background(), utils.SessionSv1GetPassiveSessions, + new(utils.SessionFilter), &pSessions); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testSessionSBkupRplcStopCgrEngine(t *testing.T) { + if err := engine.KillEngine(1000); err != nil { + t.Error(err) + } +} diff --git a/sessions/sessions_test.go b/sessions/sessions_test.go index a70b2d431..e7a91cb51 100644 --- a/sessions/sessions_test.go +++ b/sessions/sessions_test.go @@ -1938,21 +1938,23 @@ func (*testRPCClientConnection) Call(string, any, any) error { return nil } func TestNewSessionS(t *testing.T) { cgrCGF := config.NewDefaultCGRConfig() - eOut := &SessionS{ - cgrCfg: cgrCGF, - dm: nil, - biJClnts: make(map[birpc.ClientConnector]string), - biJIDs: make(map[string]*biJClient), - aSessions: make(map[string]*Session), - aSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), - aSessionsRIdx: make(map[string][]*riFieldNameVal), - pSessions: make(map[string]*Session), - pSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), - pSessionsRIdx: make(map[string][]*riFieldNameVal), - } sS := NewSessionS(cgrCGF, nil, nil) + eOut := &SessionS{ + cgrCfg: cgrCGF, + dm: nil, + biJClnts: make(map[birpc.ClientConnector]string), + biJIDs: make(map[string]*biJClient), + aSessions: make(map[string]*Session), + aSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), + aSessionsRIdx: make(map[string][]*riFieldNameVal), + pSessions: make(map[string]*Session), + pSessionsIdx: make(map[string]map[string]map[string]utils.StringSet), + pSessionsRIdx: make(map[string][]*riFieldNameVal), + markedSsCGRIDs: make(utils.StringSet), + removeSsCGRIDs: make(utils.StringSet), + } if !reflect.DeepEqual(sS, eOut) { - t.Errorf("Expected %s , received: %s", utils.ToJSON(sS), utils.ToJSON(eOut)) + t.Errorf("Expected <%+v> , \nreceived: <%+v>", sS, eOut) } } @@ -2663,6 +2665,7 @@ func TestInitSession(t *testing.T) { }, DebitInterval: 0, Chargeable: true, + UpdatedAt: s.UpdatedAt, } s.SRuns = nil if !reflect.DeepEqual(exp, s) { diff --git a/sessions/sessionscover_test.go b/sessions/sessionscover_test.go index ff576d580..d7ca17171 100644 --- a/sessions/sessionscover_test.go +++ b/sessions/sessionscover_test.go @@ -1545,11 +1545,12 @@ func TestTransitSState(t *testing.T) { CGRID: "TEST_CGRID", }, } - expected := &Session{ - CGRID: "TEST_CGRID", - } rcv = sessions.getActivateSession("test") + expected := &Session{ + CGRID: "TEST_CGRID", + UpdatedAt: rcv.UpdatedAt, + } if !reflect.DeepEqual(rcv, expected) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(rcv)) } @@ -1579,6 +1580,7 @@ func TestRelocateSession(t *testing.T) { }, }, } + rcv := sessions.relocateSession("111", "222", "127.0.0.1") expected := &Session{ CGRID: "dfa2adaa5ab49349777c1ab3bcf3455df0259880", EventStart: map[string]any{ @@ -1593,10 +1595,9 @@ func TestRelocateSession(t *testing.T) { }, }, }, + UpdatedAt: rcv.UpdatedAt, } - if rcv := sessions.relocateSession("111", "222", "127.0.0.1"); rcv == nil { - t.Errorf("Expected to not be nil") - } else if !reflect.DeepEqual(rcv, expected) { + if !reflect.DeepEqual(rcv, expected) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(rcv)) } @@ -1604,7 +1605,7 @@ func TestRelocateSession(t *testing.T) { "0d0fe8779b54c88f121e26c5d83abee5935127e5": nil, } - rcv := sessions.relocateSession("111", "222", utils.EmptyString) + rcv = sessions.relocateSession("111", "222", utils.EmptyString) if rcv != nil { t.Errorf("Expected to be nil") } @@ -1629,12 +1630,12 @@ func TestGetRelocateSession(t *testing.T) { }, } + rcv = sessions.getRelocateSession("test", utils.EmptyString, "222", "127.0.0.1") expected := &Session{ - CGRID: "TEST_CGRID", + CGRID: "TEST_CGRID", + UpdatedAt: rcv.UpdatedAt, } - if rcv = sessions.getRelocateSession("test", utils.EmptyString, "222", "127.0.0.1"); rcv == nil { - t.Errorf("Expected to be nil") - } else if !reflect.DeepEqual(rcv, expected) { + if !reflect.DeepEqual(rcv, expected) { t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(rcv)) } } diff --git a/utils/reflect_test.go b/utils/reflect_test.go index 2b0822cb9..eddf185f7 100644 --- a/utils/reflect_test.go +++ b/utils/reflect_test.go @@ -2009,3 +2009,22 @@ func TestReflectDifference(t *testing.T) { t.Error(rcv) } } + +func TestMapIfaceTimeAsString(t *testing.T) { + someTime := time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC) + mapAny := make(map[string]any) + mapAny["someTime"] = someTime + mapAny["timeDuration"] = 5 * time.Second + mapAny["simpleKey"] = "simpleValue" + + MapIfaceTimeAsString(mapAny) + if mapAny["someTime"] != "2009-11-17T20:34:58Z" { + t.Errorf("Expected <%q>, received <%v>", "2009-11-17T20:34:58Z", mapAny["someTime"]) + } + if mapAny["timeDuration"] != 5*time.Second { + t.Errorf("Expected <%q>, received <%v>", 5*time.Second, mapAny["timeDuration"]) + } + if mapAny["simpleKey"] != "simpleValue" { + t.Errorf("Expected <%q>, received <%v>", "simpleValue", mapAny["simpleKey"]) + } +}