mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Updated general tests with sub-tests
This commit is contained in:
committed by
Dan Christian Bogos
parent
7e884a4058
commit
519a11cebb
@@ -39,28 +39,28 @@ var (
|
||||
accConfDIR string //run tests for specific configuration
|
||||
account *engine.Account
|
||||
accDelay int
|
||||
)
|
||||
|
||||
var sTestsAcc = []func(t *testing.T){
|
||||
testV1AccLoadConfig,
|
||||
testV1AccInitDataDb,
|
||||
testAccResetStorDb,
|
||||
testV1AccStartEngine,
|
||||
testV1AccRpcConn,
|
||||
testV1AccGetAccountBeforeSet,
|
||||
testV1AccLoadTarrifPlans,
|
||||
testV1AccGetAccountAfterLoad,
|
||||
testV1AccRemAccount,
|
||||
testV1AccGetAccountAfterDelete,
|
||||
testV1AccSetAccount,
|
||||
testV1AccGetAccountAfterSet,
|
||||
testV1AccRemAccountSet,
|
||||
testV1AccGetAccountSetAfterDelete,
|
||||
//testV1AccRemAccountAfterDelete,
|
||||
testV1AccMonthly,
|
||||
testV1AccSendToThreshold,
|
||||
testV1AccStopEngine,
|
||||
}
|
||||
sTestsAcc = []func(t *testing.T){
|
||||
testV1AccLoadConfig,
|
||||
testV1AccInitDataDb,
|
||||
testAccResetStorDb,
|
||||
testV1AccStartEngine,
|
||||
testV1AccRpcConn,
|
||||
testV1AccGetAccountBeforeSet,
|
||||
testV1AccLoadTarrifPlans,
|
||||
testV1AccGetAccountAfterLoad,
|
||||
testV1AccRemAccount,
|
||||
testV1AccGetAccountAfterDelete,
|
||||
testV1AccSetAccount,
|
||||
testV1AccGetAccountAfterSet,
|
||||
testV1AccRemAccountSet,
|
||||
testV1AccGetAccountSetAfterDelete,
|
||||
//testV1AccRemAccountAfterDelete,
|
||||
testV1AccMonthly,
|
||||
testV1AccSendToThreshold,
|
||||
testV1AccStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
// Test start here
|
||||
func TestAccITMySQL(t *testing.T) {
|
||||
|
||||
@@ -40,20 +40,20 @@ var (
|
||||
cdreDataDir = "/usr/share/cgrates"
|
||||
cdreDelay int
|
||||
cdreConfigDIR string
|
||||
)
|
||||
|
||||
var sTestsCDRE = []func(t *testing.T){
|
||||
testCDREInitCfg,
|
||||
testCDREInitDataDb,
|
||||
testCDREResetStorDb,
|
||||
testCDREStartEngine,
|
||||
testCDRERpcConn,
|
||||
testCDREGetCdrs,
|
||||
testCDREExportNotFound,
|
||||
testCDREProcessCdr,
|
||||
testCDREExport,
|
||||
testCDREStopEngine,
|
||||
}
|
||||
sTestsCDRE = []func(t *testing.T){
|
||||
testCDREInitCfg,
|
||||
testCDREInitDataDb,
|
||||
testCDREResetStorDb,
|
||||
testCDREStartEngine,
|
||||
testCDRERpcConn,
|
||||
testCDREGetCdrs,
|
||||
testCDREExportNotFound,
|
||||
testCDREProcessCdr,
|
||||
testCDREExport,
|
||||
testCDREStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestCDREITMySql(t *testing.T) {
|
||||
cdreConfigDIR = "tutmysql"
|
||||
|
||||
@@ -35,47 +35,49 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var cdrsCfgPath string
|
||||
var cdrsCfg *config.CGRConfig
|
||||
var cdrsRpc *rpc.Client
|
||||
var cdrsConfDIR string // run the tests for specific configuration
|
||||
var (
|
||||
cdrsCfgPath string
|
||||
cdrsCfg *config.CGRConfig
|
||||
cdrsRpc *rpc.Client
|
||||
cdrsConfDIR string // run the tests for specific configuration
|
||||
|
||||
// subtests to be executed for each confDIR
|
||||
var sTestsCDRsIT = []func(t *testing.T){
|
||||
testV2CDRsInitConfig,
|
||||
testV2CDRsInitDataDb,
|
||||
testV2CDRsInitCdrDb,
|
||||
testV2CDRsStartEngine,
|
||||
testV2CDRsRpcConn,
|
||||
testV2CDRsLoadTariffPlanFromFolder,
|
||||
//default process
|
||||
testV2CDRsProcessCDR,
|
||||
testV2CDRsGetCdrs,
|
||||
//custom process
|
||||
testV2CDRsProcessCDR2,
|
||||
testV2CDRsGetCdrs2,
|
||||
testV2CDRsProcessCDR3,
|
||||
testV2CDRsGetCdrs3,
|
||||
// subtests to be executed for each confDIR
|
||||
sTestsCDRsIT = []func(t *testing.T){
|
||||
testV2CDRsInitConfig,
|
||||
testV2CDRsInitDataDb,
|
||||
testV2CDRsInitCdrDb,
|
||||
testV2CDRsStartEngine,
|
||||
testV2CDRsRpcConn,
|
||||
testV2CDRsLoadTariffPlanFromFolder,
|
||||
//default process
|
||||
testV2CDRsProcessCDR,
|
||||
testV2CDRsGetCdrs,
|
||||
//custom process
|
||||
testV2CDRsProcessCDR2,
|
||||
testV2CDRsGetCdrs2,
|
||||
testV2CDRsProcessCDR3,
|
||||
testV2CDRsGetCdrs3,
|
||||
|
||||
testV2CDRsProcessCDR4,
|
||||
testV2CDRsGetCdrs4,
|
||||
testV2CDRsProcessCDR4,
|
||||
testV2CDRsGetCdrs4,
|
||||
|
||||
testV2CDRsSetStats,
|
||||
testV2CDRsSetThresholdProfile,
|
||||
testV2CDRsSetStats,
|
||||
testV2CDRsSetThresholdProfile,
|
||||
|
||||
testV2CDRsProcessCDR5,
|
||||
testV2CDRsGetCdrs5,
|
||||
testV2CDRsGetStats1,
|
||||
testV2CDRsGetThreshold1,
|
||||
testV2CDRsProcessCDR6,
|
||||
testV2CDRsGetCdrs5,
|
||||
testV2CDRsGetStats2,
|
||||
testV2CDRsGetThreshold2,
|
||||
testV2CDRsProcessCDR7,
|
||||
testV2CDRsGetCdrs7,
|
||||
testV2CDRsProcessCDR5,
|
||||
testV2CDRsGetCdrs5,
|
||||
testV2CDRsGetStats1,
|
||||
testV2CDRsGetThreshold1,
|
||||
testV2CDRsProcessCDR6,
|
||||
testV2CDRsGetCdrs5,
|
||||
testV2CDRsGetStats2,
|
||||
testV2CDRsGetThreshold2,
|
||||
testV2CDRsProcessCDR7,
|
||||
testV2CDRsGetCdrs7,
|
||||
|
||||
testV2CDRsKillEngine,
|
||||
}
|
||||
testV2CDRsKillEngine,
|
||||
}
|
||||
)
|
||||
|
||||
// Tests starting here
|
||||
func TestCDRsITMySQL(t *testing.T) {
|
||||
|
||||
@@ -40,11 +40,38 @@ import (
|
||||
"github.com/streadway/amqp"
|
||||
)
|
||||
|
||||
var cdrsMasterCfgPath, cdrsSlaveCfgPath string
|
||||
var cdrsMasterCfg, cdrsSlaveCfg *config.CGRConfig
|
||||
var cdrsMasterRpc *rpcclient.RpcClient
|
||||
var (
|
||||
cdrsMasterCfgPath, cdrsSlaveCfgPath string
|
||||
cdrsMasterCfg, cdrsSlaveCfg *config.CGRConfig
|
||||
cdrsMasterRpc *rpcclient.RpcClient
|
||||
|
||||
func TestCDRsOnExpInitConfig(t *testing.T) {
|
||||
sTestsCDRsOnExp = []func(t *testing.T){
|
||||
testCDRsOnExpInitConfig,
|
||||
testCDRsOnExpInitCdrDb,
|
||||
testCDRsOnExpStartMasterEngine,
|
||||
testCDRsOnExpStartSlaveEngine,
|
||||
testCDRsOnExpAMQPQueuesCreation,
|
||||
testCDRsOnExpInitMasterRPC,
|
||||
testCDRsOnExpDisableOnlineExport,
|
||||
testCDRsOnExpHttpCdrReplication,
|
||||
testCDRsOnExpAMQPReplication,
|
||||
testCDRsOnExpHTTPPosterFileFailover,
|
||||
testCDRsOnExpAMQPPosterFileFailover,
|
||||
testCDRsOnExpAWSAMQPPosterFileFailover,
|
||||
testCDRsOnExpKafkaPosterFileFailover,
|
||||
testCDRsOnExpSQSPosterFileFailover,
|
||||
testCDRsOnExpS3PosterFileFailover,
|
||||
testCDRsOnExpStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestCDRsOnExp(t *testing.T) {
|
||||
for _, stest := range sTestsCDRsOnExp {
|
||||
t.Run("TestCDRsOnExp", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testCDRsOnExpInitConfig(t *testing.T) {
|
||||
var err error
|
||||
cdrsMasterCfgPath = path.Join(*dataDir, "conf", "samples", "cdrsonexpmaster")
|
||||
if cdrsMasterCfg, err = config.NewCGRConfigFromPath(cdrsMasterCfgPath); err != nil {
|
||||
@@ -57,7 +84,7 @@ func TestCDRsOnExpInitConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
// InitDb so we can rely on count
|
||||
func TestCDRsOnExpInitCdrDb(t *testing.T) {
|
||||
func testCDRsOnExpInitCdrDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(cdrsMasterCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -74,13 +101,13 @@ func TestCDRsOnExpInitCdrDb(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestCDRsOnExpStartMasterEngine(t *testing.T) {
|
||||
func testCDRsOnExpStartMasterEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(cdrsMasterCfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRsOnExpStartSlaveEngine(t *testing.T) {
|
||||
func testCDRsOnExpStartSlaveEngine(t *testing.T) {
|
||||
if _, err := engine.StartEngine(cdrsSlaveCfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -88,7 +115,7 @@ func TestCDRsOnExpStartSlaveEngine(t *testing.T) {
|
||||
|
||||
// Create Queues dor amq
|
||||
|
||||
func TestCDRsOnExpAMQPQueuesCreation(t *testing.T) {
|
||||
func testCDRsOnExpAMQPQueuesCreation(t *testing.T) {
|
||||
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -113,7 +140,7 @@ func TestCDRsOnExpAMQPQueuesCreation(t *testing.T) {
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestCDRsOnExpInitMasterRPC(t *testing.T) {
|
||||
func testCDRsOnExpInitMasterRPC(t *testing.T) {
|
||||
var err error
|
||||
cdrsMasterRpc, err = rpcclient.NewRpcClient("tcp", cdrsMasterCfg.ListenCfg().RPCJSONListen, false, "", "", "", 1, 1,
|
||||
time.Duration(1*time.Second), time.Duration(2*time.Second), "json", nil, false)
|
||||
@@ -123,7 +150,7 @@ func TestCDRsOnExpInitMasterRPC(t *testing.T) {
|
||||
}
|
||||
|
||||
// Disable ExportCDR
|
||||
func TestCDRsOnExpDisableOnlineExport(t *testing.T) {
|
||||
func testCDRsOnExpDisableOnlineExport(t *testing.T) {
|
||||
// stop RabbitMQ server so we can test reconnects
|
||||
if err := exec.Command("service", "rabbitmq-server", "stop").Run(); err != nil {
|
||||
t.Error(err)
|
||||
@@ -170,7 +197,7 @@ func TestCDRsOnExpDisableOnlineExport(t *testing.T) {
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
func TestCDRsOnExpHttpCdrReplication(t *testing.T) {
|
||||
func testCDRsOnExpHttpCdrReplication(t *testing.T) {
|
||||
//add a default charger
|
||||
chargerProfile := &engine.ChargerProfile{
|
||||
Tenant: "cgrates.org",
|
||||
@@ -250,7 +277,7 @@ func TestCDRsOnExpHttpCdrReplication(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRsOnExpAMQPReplication(t *testing.T) {
|
||||
func testCDRsOnExpAMQPReplication(t *testing.T) {
|
||||
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -388,7 +415,7 @@ func TestCDRsOnExpAMQPReplication(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestCDRsOnExpHTTPPosterFileFailover(t *testing.T) {
|
||||
func testCDRsOnExpHTTPPosterFileFailover(t *testing.T) {
|
||||
time.Sleep(time.Duration(5 * time.Second))
|
||||
failoverContent := [][]byte{[]byte(`OriginID=httpjsonrpc1`), []byte(`OriginID=amqpreconnect`)}
|
||||
filesInDir, _ := ioutil.ReadDir(cdrsMasterCfg.GeneralCfg().FailedPostsDir)
|
||||
@@ -417,7 +444,7 @@ func TestCDRsOnExpHTTPPosterFileFailover(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRsOnExpAMQPPosterFileFailover(t *testing.T) {
|
||||
func testCDRsOnExpAMQPPosterFileFailover(t *testing.T) {
|
||||
time.Sleep(time.Duration(5 * time.Second))
|
||||
failoverContent := [][]byte{[]byte(`{"CGRID":"57548d485d61ebcba55afbe5d939c82a8e9ff670"}`), []byte(`{"CGRID":"88ed9c38005f07576a1e1af293063833b60edcc6"}`)}
|
||||
filesInDir, _ := ioutil.ReadDir(cdrsMasterCfg.GeneralCfg().FailedPostsDir)
|
||||
@@ -446,7 +473,7 @@ func TestCDRsOnExpAMQPPosterFileFailover(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRsOnExpAWSAMQPPosterFileFailover(t *testing.T) {
|
||||
func testCDRsOnExpAWSAMQPPosterFileFailover(t *testing.T) {
|
||||
time.Sleep(time.Duration(10 * time.Second))
|
||||
failoverContent := [][]byte{[]byte(`{"CGRID":"57548d485d61ebcba55afbe5d939c82a8e9ff670"}`), []byte(`{"CGRID":"88ed9c38005f07576a1e1af293063833b60edcc6"}`)}
|
||||
filesInDir, _ := ioutil.ReadDir(cdrsMasterCfg.GeneralCfg().FailedPostsDir)
|
||||
@@ -475,7 +502,7 @@ func TestCDRsOnExpAWSAMQPPosterFileFailover(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRsOnExpKafkaPosterFileFailover(t *testing.T) {
|
||||
func testCDRsOnExpKafkaPosterFileFailover(t *testing.T) {
|
||||
failoverContent := [][]byte{[]byte(`{"CGRID":"57548d485d61ebcba55afbe5d939c82a8e9ff670"}`), []byte(`{"CGRID":"88ed9c38005f07576a1e1af293063833b60edcc6"}`)}
|
||||
|
||||
reader := kafka.NewReader(kafka.ReaderConfig{
|
||||
@@ -497,7 +524,7 @@ func TestCDRsOnExpKafkaPosterFileFailover(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRsOnExpSQSPosterFileFailover(t *testing.T) {
|
||||
func testCDRsOnExpSQSPosterFileFailover(t *testing.T) {
|
||||
time.Sleep(time.Duration(10 * time.Second))
|
||||
failoverContent := [][]byte{[]byte(`{"CGRID":"57548d485d61ebcba55afbe5d939c82a8e9ff670"}`), []byte(`{"CGRID":"88ed9c38005f07576a1e1af293063833b60edcc6"}`)}
|
||||
filesInDir, _ := ioutil.ReadDir(cdrsMasterCfg.GeneralCfg().FailedPostsDir)
|
||||
@@ -526,7 +553,7 @@ func TestCDRsOnExpSQSPosterFileFailover(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRsOnExpS3PosterFileFailover(t *testing.T) {
|
||||
func testCDRsOnExpS3PosterFileFailover(t *testing.T) {
|
||||
time.Sleep(time.Duration(10 * time.Second))
|
||||
failoverContent := [][]byte{[]byte(`{"CGRID":"57548d485d61ebcba55afbe5d939c82a8e9ff670"}`), []byte(`{"CGRID":"88ed9c38005f07576a1e1af293063833b60edcc6"}`)}
|
||||
filesInDir, _ := ioutil.ReadDir(cdrsMasterCfg.GeneralCfg().FailedPostsDir)
|
||||
@@ -558,7 +585,7 @@ func TestCDRsOnExpS3PosterFileFailover(t *testing.T) {
|
||||
/*
|
||||
// Performance test, check `lsof -a -p 8427 | wc -l`
|
||||
|
||||
func TestCdrsHttpCdrReplication2(t *testing.T) {
|
||||
func testCdrsHttpCdrReplication2(t *testing.T) {
|
||||
cdrs := make([]*engine.CDR, 0)
|
||||
for i := 0; i < 10000; i++ {
|
||||
cdr := &engine.CDR{OriginID: fmt.Sprintf("httpjsonrpc_%d", i),
|
||||
@@ -579,7 +606,7 @@ func TestCdrsHttpCdrReplication2(t *testing.T) {
|
||||
}
|
||||
*/
|
||||
|
||||
func TestCDRsOnExpStopEngine(t *testing.T) {
|
||||
func testCDRsOnExpStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -39,26 +39,26 @@ var (
|
||||
dataRpc *rpc.Client
|
||||
dataConfDIR string //run tests for specific configuration
|
||||
dataDelay int
|
||||
)
|
||||
|
||||
var sTestsData = []func(t *testing.T){
|
||||
testV1DataLoadConfig,
|
||||
testV1DataInitDataDb,
|
||||
testV1DataResetStorDb,
|
||||
testV1DataStartEngine,
|
||||
testV1DataRpcConn,
|
||||
testV1DataLoadTarrifPlans,
|
||||
// testV1DataDataDebitUsageWith10Kilo,
|
||||
// testV1DataGetCostWith10Kilo,
|
||||
// testV1DataDebitBalanceWith10Kilo,
|
||||
// testV1DataDataDebitUsage1G0,
|
||||
// testV1DataGetCost1G0,
|
||||
// testV1DataDebitBalance1G0,
|
||||
testV1DataInitSession,
|
||||
testV1DataUpdateWith1Mo,
|
||||
testV1DataUpdateWith1Go,
|
||||
testV1DataStopEngine,
|
||||
}
|
||||
sTestsData = []func(t *testing.T){
|
||||
testV1DataLoadConfig,
|
||||
testV1DataInitDataDb,
|
||||
testV1DataResetStorDb,
|
||||
testV1DataStartEngine,
|
||||
testV1DataRpcConn,
|
||||
testV1DataLoadTarrifPlans,
|
||||
// testV1DataDataDebitUsageWith10Kilo,
|
||||
// testV1DataGetCostWith10Kilo,
|
||||
// testV1DataDebitBalanceWith10Kilo,
|
||||
// testV1DataDataDebitUsage1G0,
|
||||
// testV1DataGetCost1G0,
|
||||
// testV1DataDebitBalance1G0,
|
||||
testV1DataInitSession,
|
||||
testV1DataUpdateWith1Mo,
|
||||
testV1DataUpdateWith1Go,
|
||||
testV1DataStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
// Test start here
|
||||
func TestDataITMongo(t *testing.T) {
|
||||
|
||||
@@ -34,11 +34,38 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var destCfgPath string
|
||||
var destCfg *config.CGRConfig
|
||||
var destRPC *rpc.Client
|
||||
var (
|
||||
destCfgPath string
|
||||
destCfg *config.CGRConfig
|
||||
destRPC *rpc.Client
|
||||
|
||||
func TestDestManagInitCfg(t *testing.T) {
|
||||
sTestDestManag = []func (t *testing.T){
|
||||
testDestManagInitCfg,
|
||||
testDestManagResetDataDb,
|
||||
testDestManagResetStorDb,
|
||||
testDestManagStartEngine,
|
||||
testDestManagRpcConn,
|
||||
testDestManagLoadTariffPlanFromFolderAll,
|
||||
testDestManagAllDestinationLoaded,
|
||||
testDestManagLoadTariffPlanFromFolderRemoveSome,
|
||||
testDestManagRemoveSomeDestinationLoaded,
|
||||
testDestManagLoadTariffPlanFromFolderRemoveSomeFlush,
|
||||
testDestManagRemoveSomeFlushDestinationLoaded,
|
||||
testDestManagLoadTariffPlanFromFolderAddBack,
|
||||
testDestManagAddBackDestinationLoaded,
|
||||
testDestManagLoadTariffPlanFromFolderAddOne,
|
||||
testDestManagAddOneDestinationLoaded,
|
||||
testDestManagCacheWithGetCache,
|
||||
testDestManagCacheWithGetCost,
|
||||
}
|
||||
)
|
||||
|
||||
func TestDestManag(t *testing.T) {
|
||||
for _, stest := range sTestDestManag {
|
||||
t.Run("TestDestManag", stest)
|
||||
}
|
||||
}
|
||||
func testDestManagInitCfg(t *testing.T) {
|
||||
destCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
// Init config first
|
||||
var err error
|
||||
@@ -51,28 +78,28 @@ func TestDestManagInitCfg(t *testing.T) {
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestDestManagResetDataDb(t *testing.T) {
|
||||
func testDestManagResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(destCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestDestManagResetStorDb(t *testing.T) {
|
||||
func testDestManagResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(destCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestDestManagStartEngine(t *testing.T) {
|
||||
func testDestManagStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(destCfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestDestManagRpcConn(t *testing.T) {
|
||||
func testDestManagRpcConn(t *testing.T) {
|
||||
var err error
|
||||
destRPC, err = jsonrpc.Dial("tcp", destCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
@@ -81,7 +108,7 @@ func TestDestManagRpcConn(t *testing.T) {
|
||||
}
|
||||
|
||||
// Load the tariff plan, creating accounts and their balances
|
||||
func TestDestManagLoadTariffPlanFromFolderAll(t *testing.T) {
|
||||
func testDestManagLoadTariffPlanFromFolderAll(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "alldests")}
|
||||
var destLoadInst utils.LoadInstance
|
||||
if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil {
|
||||
@@ -91,7 +118,7 @@ func TestDestManagLoadTariffPlanFromFolderAll(t *testing.T) {
|
||||
}
|
||||
|
||||
|
||||
func TestDestManagAllDestinationLoaded(t *testing.T) {
|
||||
func testDestManagAllDestinationLoaded(t *testing.T) {
|
||||
dests := make([]*engine.Destination, 0)
|
||||
if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil {
|
||||
t.Error("Got error on ApierV2.GetDestinations: ", err.Error())
|
||||
@@ -108,7 +135,7 @@ func TestDestManagAllDestinationLoaded(t *testing.T) {
|
||||
}
|
||||
|
||||
|
||||
func TestDestManagLoadTariffPlanFromFolderRemoveSome(t *testing.T) {
|
||||
func testDestManagLoadTariffPlanFromFolderRemoveSome(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "removesome")}
|
||||
var destLoadInst utils.LoadInstance
|
||||
if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil {
|
||||
@@ -117,7 +144,7 @@ func TestDestManagLoadTariffPlanFromFolderRemoveSome(t *testing.T) {
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
func TestDestManagRemoveSomeDestinationLoaded(t *testing.T) {
|
||||
func testDestManagRemoveSomeDestinationLoaded(t *testing.T) {
|
||||
dests := make([]*engine.Destination, 0)
|
||||
if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil {
|
||||
t.Error("Got error on ApierV2.GetDestinations: ", err.Error())
|
||||
@@ -133,7 +160,7 @@ func TestDestManagRemoveSomeDestinationLoaded(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestManagLoadTariffPlanFromFolderRemoveSomeFlush(t *testing.T) {
|
||||
func testDestManagLoadTariffPlanFromFolderRemoveSomeFlush(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "removesome"), FlushDb: true}
|
||||
var destLoadInst utils.LoadInstance
|
||||
if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil {
|
||||
@@ -142,7 +169,7 @@ func TestDestManagLoadTariffPlanFromFolderRemoveSomeFlush(t *testing.T) {
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
func TestDestManagRemoveSomeFlushDestinationLoaded(t *testing.T) {
|
||||
func testDestManagRemoveSomeFlushDestinationLoaded(t *testing.T) {
|
||||
dests := make([]*engine.Destination, 0)
|
||||
if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil {
|
||||
t.Error("Got error on ApierV2.GetDestinations: ", err.Error())
|
||||
@@ -158,7 +185,7 @@ func TestDestManagRemoveSomeFlushDestinationLoaded(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestManagLoadTariffPlanFromFolderAddBack(t *testing.T) {
|
||||
func testDestManagLoadTariffPlanFromFolderAddBack(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "addback")}
|
||||
var destLoadInst utils.LoadInstance
|
||||
if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil {
|
||||
@@ -167,7 +194,7 @@ func TestDestManagLoadTariffPlanFromFolderAddBack(t *testing.T) {
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
func TestDestManagAddBackDestinationLoaded(t *testing.T) {
|
||||
func testDestManagAddBackDestinationLoaded(t *testing.T) {
|
||||
dests := make([]*engine.Destination, 0)
|
||||
if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil {
|
||||
t.Error("Got error on ApierV2.GetDestinations: ", err.Error())
|
||||
@@ -183,7 +210,7 @@ func TestDestManagAddBackDestinationLoaded(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestManagLoadTariffPlanFromFolderAddOne(t *testing.T) {
|
||||
func testDestManagLoadTariffPlanFromFolderAddOne(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "test", "destinations", "addone")}
|
||||
var destLoadInst utils.LoadInstance
|
||||
if err := destRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &destLoadInst); err != nil {
|
||||
@@ -192,7 +219,7 @@ func TestDestManagLoadTariffPlanFromFolderAddOne(t *testing.T) {
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
func TestDestManagAddOneDestinationLoaded(t *testing.T) {
|
||||
func testDestManagAddOneDestinationLoaded(t *testing.T) {
|
||||
dests := make([]*engine.Destination, 0)
|
||||
if err := destRPC.Call("ApierV2.GetDestinations", v2.AttrGetDestinations{DestinationIDs: []string{}}, &dests); err != nil {
|
||||
t.Error("Got error on ApierV2.GetDestinations: ", err.Error())
|
||||
@@ -208,7 +235,7 @@ func TestDestManagAddOneDestinationLoaded(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestManagCacheWithGetCache(t *testing.T) {
|
||||
func testDestManagCacheWithGetCache(t *testing.T) {
|
||||
if err := engine.InitDataDb(destCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -259,7 +286,7 @@ func TestDestManagCacheWithGetCache(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestManagCacheWithGetCost(t *testing.T) {
|
||||
func testDestManagCacheWithGetCost(t *testing.T) {
|
||||
if err := engine.InitDataDb(destCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -39,23 +39,23 @@ var (
|
||||
fltrRpc *rpc.Client
|
||||
fltrConfDIR string //run tests for specific configuration
|
||||
fltrDelay int
|
||||
)
|
||||
|
||||
var sTestsFltr = []func(t *testing.T){
|
||||
testV1FltrLoadConfig,
|
||||
testV1FltrInitDataDb,
|
||||
testV1FltrResetStorDb,
|
||||
testV1FltrStartEngine,
|
||||
testV1FltrRpcConn,
|
||||
testV1FltrLoadTarrifPlans,
|
||||
testV1FltrAddStats,
|
||||
testV1FltrPupulateThreshold,
|
||||
testV1FltrGetThresholdForEvent,
|
||||
testV1FltrGetThresholdForEvent2,
|
||||
testV1FltrPopulateResources,
|
||||
testV1FltrAccounts,
|
||||
testV1FltrStopEngine,
|
||||
}
|
||||
sTestsFltr = []func(t *testing.T){
|
||||
testV1FltrLoadConfig,
|
||||
testV1FltrInitDataDb,
|
||||
testV1FltrResetStorDb,
|
||||
testV1FltrStartEngine,
|
||||
testV1FltrRpcConn,
|
||||
testV1FltrLoadTarrifPlans,
|
||||
testV1FltrAddStats,
|
||||
testV1FltrPupulateThreshold,
|
||||
testV1FltrGetThresholdForEvent,
|
||||
testV1FltrGetThresholdForEvent2,
|
||||
testV1FltrPopulateResources,
|
||||
testV1FltrAccounts,
|
||||
testV1FltrStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
// Test start here
|
||||
func TestFltrIT(t *testing.T) {
|
||||
|
||||
@@ -35,16 +35,38 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var cfgPath string
|
||||
var cfg *config.CGRConfig
|
||||
var rater *rpc.Client
|
||||
var (
|
||||
cfgPath string
|
||||
cfg *config.CGRConfig
|
||||
rater *rpc.Client
|
||||
|
||||
var testCalls = flag.Bool("calls", false, "Run test calls simulation, not by default.")
|
||||
var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
|
||||
var storDbType = flag.String("stordb_type", "mysql", "The type of the storDb database <mysql>")
|
||||
var waitRater = flag.Int("wait_rater", 100, "Number of miliseconds to wait for rater to start and cache")
|
||||
testCalls = flag.Bool("calls", false, "Run test calls simulation, not by default.")
|
||||
dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
|
||||
storDbType = flag.String("stordb_type", "mysql", "The type of the storDb database <mysql>")
|
||||
waitRater = flag.Int("wait_rater", 100, "Number of miliseconds to wait for rater to start and cache")
|
||||
|
||||
func TestMCDRCLoadConfig(t *testing.T) {
|
||||
sTestMCDRC = []func(t *testing.T){
|
||||
testMCDRCLoadConfig,
|
||||
testMCDRCResetDataDb,
|
||||
testMCDRCEmptyTables,
|
||||
testMCDRCCreateCdrDirs,
|
||||
testMCDRCStartEngine,
|
||||
testMCDRCRpcConn,
|
||||
testMCDRCApierLoadTariffPlanFromFolder,
|
||||
testMCDRCHandleCdr1File,
|
||||
testMCDRCHandleCdr2File,
|
||||
testMCDRCHandleCdr3File,
|
||||
testMCDRCStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestMCDRC(t *testing.T) {
|
||||
for _, stest := range sTestMCDRC {
|
||||
t.Run("TestsMCDRC", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testMCDRCLoadConfig(t *testing.T) {
|
||||
var err error
|
||||
cfgPath = path.Join(*dataDir, "conf", "samples", "multiplecdrc")
|
||||
if cfg, err = config.NewCGRConfigFromPath(cfgPath); err != nil {
|
||||
@@ -53,19 +75,19 @@ func TestMCDRCLoadConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestMCDRCResetDataDb(t *testing.T) {
|
||||
func testMCDRCResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCDRCEmptyTables(t *testing.T) {
|
||||
func testMCDRCEmptyTables(t *testing.T) {
|
||||
if err := engine.InitStorDb(cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCDRCCreateCdrDirs(t *testing.T) {
|
||||
func testMCDRCCreateCdrDirs(t *testing.T) {
|
||||
for _, cdrcProfiles := range cfg.CdrcProfiles {
|
||||
for _, cdrcInst := range cdrcProfiles {
|
||||
for _, dir := range []string{cdrcInst.CDRInPath, cdrcInst.CDROutPath} {
|
||||
@@ -79,14 +101,14 @@ func TestMCDRCCreateCdrDirs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestMCDRCStartEngine(t *testing.T) {
|
||||
func testMCDRCStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(cfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestMCDRCRpcConn(t *testing.T) {
|
||||
func testMCDRCRpcConn(t *testing.T) {
|
||||
var err error
|
||||
rater, err = jsonrpc.Dial("tcp", cfg.ListenCfg().RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
@@ -95,7 +117,7 @@ func TestMCDRCRpcConn(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test here LoadTariffPlanFromFolder
|
||||
func TestMCDRCApierLoadTariffPlanFromFolder(t *testing.T) {
|
||||
func testMCDRCApierLoadTariffPlanFromFolder(t *testing.T) {
|
||||
reply := ""
|
||||
// Simple test that command is executed without errors
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "testtp")}
|
||||
@@ -108,7 +130,7 @@ func TestMCDRCApierLoadTariffPlanFromFolder(t *testing.T) {
|
||||
}
|
||||
|
||||
// The default scenario, out of cdrc defined in .cfg file
|
||||
func TestMCDRCHandleCdr1File(t *testing.T) {
|
||||
func testMCDRCHandleCdr1File(t *testing.T) {
|
||||
var fileContent1 = `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,default,*voice,dsafdsaf,rated,*out,cgrates.org,call,1001,1001,+4986517174963,2013-11-07 08:42:25 +0000 UTC,2013-11-07 08:42:26 +0000 UTC,10000000000,1.0100,val_extra3,"",val_extra1
|
||||
dbafe9c8614c785a65aabd116dd3959c3c56f7f7,default,*voice,dsafdsag,rated,*out,cgrates.org,call,1001,1001,+4986517174964,2013-11-07 09:42:25 +0000 UTC,2013-11-07 09:42:26 +0000 UTC,20000000000,1.0100,val_extra3,"",val_extra1
|
||||
`
|
||||
@@ -123,7 +145,7 @@ dbafe9c8614c785a65aabd116dd3959c3c56f7f7,default,*voice,dsafdsag,rated,*out,cgra
|
||||
}
|
||||
|
||||
// Scenario out of first .xml config
|
||||
func TestMCDRCHandleCdr2File(t *testing.T) {
|
||||
func testMCDRCHandleCdr2File(t *testing.T) {
|
||||
var fileContent = `616350843,20131022145011,20131022172857,3656,1001,,,data,mo,640113,0.000000,1.222656,1.222660
|
||||
616199016,20131022154924,20131022154955,3656,1001,086517174963,,voice,mo,31,0.000000,0.000000,0.000000
|
||||
800873243,20140516063739,20140516063739,9774,1001,+49621621391,,sms,mo,1,0.00000,0.00000,0.00000`
|
||||
@@ -138,7 +160,7 @@ func TestMCDRCHandleCdr2File(t *testing.T) {
|
||||
}
|
||||
|
||||
// Scenario out of second .xml config
|
||||
func TestMCDRCHandleCdr3File(t *testing.T) {
|
||||
func testMCDRCHandleCdr3File(t *testing.T) {
|
||||
var fileContent = `4986517174960;4986517174963;Sample Mobile;08.04.2014 22:14:29;08.04.2014 22:14:29;1;193;Offeak;0,072728833;31619
|
||||
4986517174960;4986517174964;National;08.04.2014 20:34:55;08.04.2014 20:34:55;1;21;Offeak;0,0079135;311`
|
||||
fileName := "file3.csv"
|
||||
@@ -151,7 +173,7 @@ func TestMCDRCHandleCdr3File(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCDRCStopEngine(t *testing.T) {
|
||||
func testMCDRCStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -53,7 +53,32 @@ var ( // configuration opts
|
||||
RemoteRALsAddr2 = "192.168.244.138:2012"
|
||||
)
|
||||
|
||||
func TestRPCITLclInitCfg(t *testing.T) {
|
||||
//subtests to be executed
|
||||
var sTestRPCITLcl = []func(t *testing.T){
|
||||
testRPCITLclInitCfg,
|
||||
testRPCITLclStartSecondEngine,
|
||||
testRPCITLclRpcConnPoolFirst,
|
||||
testRPCITLclStatusSecondEngine,
|
||||
testRPCITLclStartFirstEngine,
|
||||
testRPCITLclStatusFirstInitial,
|
||||
testRPCITLclStatusFirstFailover,
|
||||
testRPCITLclStatusFirstFailback,
|
||||
testRPCITLclTDirectedRPC,
|
||||
testRPCITLclRpcConnPoolBcast,
|
||||
testRPCITLclBcastStatusInitial,
|
||||
testRPCITLclBcastStatusNoRals1,
|
||||
testRPCITLclBcastStatusBcastNoRals,
|
||||
testRPCITLclBcastStatusRALs2Up,
|
||||
testRPCITLclStatusBcastRALs1Up,
|
||||
}
|
||||
|
||||
func TestRPCITLcl(t *testing.T) {
|
||||
for _, stest := range sTestRPCITLcl {
|
||||
t.Run("sTestRPCITLcl", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testRPCITLclInitCfg(t *testing.T) {
|
||||
rpcITCfgPath1 = path.Join(*dataDir, "conf", "samples", "multiral1")
|
||||
rpcITCfgPath2 = path.Join(*dataDir, "conf", "samples", "multiral2")
|
||||
rpcITCfg1, err = config.NewCGRConfigFromPath(rpcITCfgPath1)
|
||||
@@ -69,14 +94,14 @@ func TestRPCITLclInitCfg(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCITLclStartSecondEngine(t *testing.T) {
|
||||
func testRPCITLclStartSecondEngine(t *testing.T) {
|
||||
if ral2, err = engine.StopStartEngine(rpcITCfgPath2, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestRPCITLclRpcConnPoolFirst(t *testing.T) {
|
||||
func testRPCITLclRpcConnPoolFirst(t *testing.T) {
|
||||
rpcPoolFirst = rpcclient.NewRpcClientPool(rpcclient.POOL_FIRST, 0)
|
||||
rpcRAL1, err = rpcclient.NewRpcClient("tcp", rpcITCfg1.ListenCfg().RPCJSONListen, false, "", "", "", 3, 1,
|
||||
time.Duration(1*time.Second), time.Duration(2*time.Second), rpcclient.JSON_RPC, nil, false)
|
||||
@@ -93,7 +118,7 @@ func TestRPCITLclRpcConnPoolFirst(t *testing.T) {
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestRPCITLclStatusSecondEngine(t *testing.T) {
|
||||
func testRPCITLclStatusSecondEngine(t *testing.T) {
|
||||
var status map[string]interface{}
|
||||
if err := rpcPoolFirst.Call(utils.CoreSv1Status, utils.TenantWithArgDispatcher{}, &status); err != nil {
|
||||
t.Error(err)
|
||||
@@ -108,14 +133,14 @@ func TestRPCITLclStatusSecondEngine(t *testing.T) {
|
||||
}
|
||||
|
||||
// Start first engine
|
||||
func TestRPCITLclStartFirstEngine(t *testing.T) {
|
||||
func testRPCITLclStartFirstEngine(t *testing.T) {
|
||||
if ral1, err = engine.StartEngine(rpcITCfgPath1, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestRPCITLclStatusFirstInitial(t *testing.T) {
|
||||
func testRPCITLclStatusFirstInitial(t *testing.T) {
|
||||
var status map[string]interface{}
|
||||
if err := rpcPoolFirst.Call(utils.CoreSv1Status, utils.TenantWithArgDispatcher{}, &status); err != nil {
|
||||
t.Error(err)
|
||||
@@ -132,7 +157,7 @@ func TestRPCITLclStatusFirstInitial(t *testing.T) {
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestRPCITLclStatusFirstFailover(t *testing.T) {
|
||||
func testRPCITLclStatusFirstFailover(t *testing.T) {
|
||||
if err := ral1.Process.Kill(); err != nil { // Kill the first RAL
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -152,7 +177,7 @@ func TestRPCITLclStatusFirstFailover(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCITLclStatusFirstFailback(t *testing.T) {
|
||||
func testRPCITLclStatusFirstFailback(t *testing.T) {
|
||||
if ral1, err = engine.StartEngine(rpcITCfgPath1, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -170,14 +195,14 @@ func TestRPCITLclStatusFirstFailback(t *testing.T) {
|
||||
}
|
||||
|
||||
// Make sure it executes on the first node supporting the command
|
||||
func TestRPCITLclTDirectedRPC(t *testing.T) {
|
||||
func testRPCITLclTDirectedRPC(t *testing.T) {
|
||||
var sessions []*sessions.ExternalSession
|
||||
if err := rpcPoolFirst.Call(utils.SessionSv1GetActiveSessions, utils.SessionFilter{}, &sessions); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// func TestRPCITLclTimeout(t *testing.T) {
|
||||
// func testRPCITLclTimeout(t *testing.T) {
|
||||
// var status map[string]interface{}
|
||||
// if err := rpcPoolFirst.Call(utils.CoreSv1Status, "10s", &status); err == nil {
|
||||
// t.Error("Expecting timeout")
|
||||
@@ -187,13 +212,13 @@ func TestRPCITLclTDirectedRPC(t *testing.T) {
|
||||
// }
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestRPCITLclRpcConnPoolBcast(t *testing.T) {
|
||||
func testRPCITLclRpcConnPoolBcast(t *testing.T) {
|
||||
rpcPoolBroadcast = rpcclient.NewRpcClientPool(rpcclient.POOL_BROADCAST, time.Duration(2*time.Second))
|
||||
rpcPoolBroadcast.AddClient(rpcRAL1)
|
||||
rpcPoolBroadcast.AddClient(rpcRAL2)
|
||||
}
|
||||
|
||||
func TestRPCITLclBcastStatusInitial(t *testing.T) {
|
||||
func testRPCITLclBcastStatusInitial(t *testing.T) {
|
||||
var status map[string]interface{}
|
||||
if err := rpcPoolBroadcast.Call(utils.CoreSv1Status, utils.TenantWithArgDispatcher{}, &status); err != nil {
|
||||
t.Error(err)
|
||||
@@ -207,7 +232,7 @@ func TestRPCITLclBcastStatusInitial(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCITLclBcastStatusNoRals1(t *testing.T) {
|
||||
func testRPCITLclBcastStatusNoRals1(t *testing.T) {
|
||||
if err := ral1.Process.Kill(); err != nil { // Kill the first RAL
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -225,7 +250,7 @@ func TestRPCITLclBcastStatusNoRals1(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCITLclBcastStatusBcastNoRals(t *testing.T) {
|
||||
func testRPCITLclBcastStatusBcastNoRals(t *testing.T) {
|
||||
if err := ral2.Process.Kill(); err != nil { // Kill the first RAL
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -236,7 +261,7 @@ func TestRPCITLclBcastStatusBcastNoRals(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCITLclBcastStatusRALs2Up(t *testing.T) {
|
||||
func testRPCITLclBcastStatusRALs2Up(t *testing.T) {
|
||||
if ral2, err = engine.StartEngine(rpcITCfgPath2, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -253,7 +278,7 @@ func TestRPCITLclBcastStatusRALs2Up(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCITLclStatusBcastRALs1Up(t *testing.T) {
|
||||
func testRPCITLclStatusBcastRALs1Up(t *testing.T) {
|
||||
if ral1, err = engine.StartEngine(rpcITCfgPath1, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,286 +1,286 @@
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os/exec"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
node1ConfigPath = path.Join(*dataDir, "redis_sentinel", "node1.conf")
|
||||
node2ConfigPath = path.Join(*dataDir, "redis_sentinel", "node2.conf")
|
||||
sentinel1ConfigPath = path.Join(*dataDir, "redis_sentinel", "sentinel1.conf")
|
||||
sentinel2ConfigPath = path.Join(*dataDir, "redis_sentinel", "sentinel2.conf")
|
||||
engineConfigPath = path.Join(*dataDir, "conf", "samples", "tutsentinel")
|
||||
sentinelConfig *config.CGRConfig
|
||||
sentinelRPC *rpc.Client
|
||||
node1Exec, node2Exec,
|
||||
stlExec1, stlExec2 *exec.Cmd
|
||||
redisSentinel = flag.Bool("redis_sentinel", false, "Run tests with redis sentinel")
|
||||
)
|
||||
|
||||
var sTestsRds = []func(t *testing.T){
|
||||
testRedisSentinelStartNodes,
|
||||
testRedisSentinelInitConfig,
|
||||
testRedisSentinelFlushDb,
|
||||
testRedisSentinelStartEngine,
|
||||
testRedisSentinelRPCCon,
|
||||
testRedisSentinelSetGetAttribute,
|
||||
testRedisSentinelInsertion,
|
||||
testRedisSentinelGetAttrAfterFailover,
|
||||
testRedisSentinelKillEngine,
|
||||
}
|
||||
|
||||
// Before running these tests make sure node1.conf, node2.conf, sentinel1.conf are the next
|
||||
// Node1 will be master and start at port 16379
|
||||
// Node2 will be slave of node1 and start at port 16380
|
||||
// Sentinel1 will be started at port 16381 and will watch Node1
|
||||
// Sentinel2 will be started at port 16382 and will watch Node1
|
||||
func TestRedisSentinel(t *testing.T) {
|
||||
if !*redisSentinel {
|
||||
return
|
||||
}
|
||||
for _, stest := range sTestsRds {
|
||||
t.Run("", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelStartNodes(t *testing.T) {
|
||||
node1Exec = exec.Command("redis-server", node1ConfigPath)
|
||||
if err := node1Exec.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
node2Exec = exec.Command("redis-server", node2ConfigPath)
|
||||
if err := node2Exec.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
stlExec1 = exec.Command("redis-sentinel", sentinel1ConfigPath)
|
||||
if err := stlExec1.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
stlExec2 = exec.Command("redis-sentinel", sentinel2ConfigPath)
|
||||
if err := stlExec2.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelInitConfig(t *testing.T) {
|
||||
var err error
|
||||
sentinelConfig, err = config.NewCGRConfigFromPath(engineConfigPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
sentinelConfig.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(sentinelConfig)
|
||||
}
|
||||
|
||||
func testRedisSentinelFlushDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(sentinelConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(engineConfigPath, 2000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelRPCCon(t *testing.T) {
|
||||
var err error
|
||||
sentinelRPC, err = jsonrpc.Dial("tcp", sentinelConfig.ListenCfg().RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelSetGetAttribute(t *testing.T) {
|
||||
alsPrf := &engine.AttributeProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ApierTest",
|
||||
Contexts: []string{utils.MetaSessionS, utils.MetaCDRs},
|
||||
FilterIDs: []string{"*string:Account:1001"},
|
||||
Attributes: []*engine.Attribute{
|
||||
{
|
||||
FieldName: utils.Subject,
|
||||
Value: config.NewRSRParsersMustCompile("1001", true, utils.INFIELD_SEP),
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
}
|
||||
alsPrf.Compile()
|
||||
var result string
|
||||
if err := sentinelRPC.Call("ApierV1.SetAttributeProfile", alsPrf, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
var reply *engine.AttributeProfile
|
||||
if err := sentinelRPC.Call("ApierV1.GetAttributeProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
reply.Compile()
|
||||
if !reflect.DeepEqual(alsPrf, reply) {
|
||||
t.Errorf("Expecting : %+v, received: %+v", alsPrf, reply)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelInsertion(t *testing.T) {
|
||||
nrFails1 := 0
|
||||
nrFails2 := 0
|
||||
alsPrf := &engine.AttributeProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ApierTest",
|
||||
Contexts: []string{utils.MetaSessionS, utils.MetaCDRs},
|
||||
FilterIDs: []string{"*string:Account:1001"},
|
||||
Attributes: []*engine.Attribute{
|
||||
{
|
||||
FieldName: utils.Subject,
|
||||
Value: config.NewRSRParsersMustCompile("1001", true, utils.INFIELD_SEP),
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
}
|
||||
orgiginID := alsPrf.ID + "_"
|
||||
id := alsPrf.ID + "_0"
|
||||
index := 0
|
||||
var result string
|
||||
addFunc := func(t *testing.T, nrFail *int) {
|
||||
alsPrf.ID = id
|
||||
if err := sentinelRPC.Call("ApierV1.SetAttributeProfile", alsPrf, &result); err != nil {
|
||||
if err.Error() == "SERVER_ERROR: No sentinels active" {
|
||||
*nrFail = *nrFail + 1
|
||||
} else {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
index = index + 1
|
||||
id = orgiginID + string(index)
|
||||
}
|
||||
forFunc1 := func(t *testing.T) {
|
||||
for i := 0; i < 25; i++ {
|
||||
t.Run("add", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails1)
|
||||
})
|
||||
if i == 5 {
|
||||
t.Run("stop1", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if err := stlExec1.Process.Kill(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
if i == 10 {
|
||||
t.Run("stop2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if err := stlExec2.Process.Kill(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("add2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails1)
|
||||
})
|
||||
}
|
||||
}
|
||||
forFunc2 := func(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
t.Run("add", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails2)
|
||||
})
|
||||
t.Run("add2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails2)
|
||||
})
|
||||
}
|
||||
}
|
||||
t.Run("for1", forFunc1)
|
||||
if nrFails1 == 0 {
|
||||
t.Error("Fail tests in case of failover")
|
||||
}
|
||||
if err := exec.Command("redis-sentinel", sentinel1ConfigPath).Start(); err != nil { // Kill the master
|
||||
t.Error(err)
|
||||
}
|
||||
t.Run("for2", forFunc2)
|
||||
if nrFails2 > 19 {
|
||||
t.Errorf("Fail tests in case of failback ")
|
||||
}
|
||||
}
|
||||
|
||||
// After we kill node1 check the data if was replicated in node2
|
||||
func testRedisSentinelGetAttrAfterFailover(t *testing.T) {
|
||||
alsPrf := &engine.AttributeProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ApierTest",
|
||||
Contexts: []string{utils.MetaSessionS, utils.MetaCDRs},
|
||||
FilterIDs: []string{"*string:Account:1001"},
|
||||
Attributes: []*engine.Attribute{
|
||||
{
|
||||
FieldName: utils.Subject,
|
||||
Value: config.NewRSRParsersMustCompile("1001", true, utils.INFIELD_SEP),
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
}
|
||||
alsPrf.Compile()
|
||||
var reply *engine.AttributeProfile
|
||||
if err := sentinelRPC.Call("ApierV1.GetAttributeProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
reply.Compile()
|
||||
if !reflect.DeepEqual(alsPrf, reply) {
|
||||
t.Errorf("Expecting : %+v, received: %+v", alsPrf, reply)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelKillEngine(t *testing.T) {
|
||||
if err := exec.Command("pkill", "redis-server").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := exec.Command("pkill", "redis-sentinel").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := exec.Command("pkill", "redis-ser").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := exec.Command("pkill", "redis-sen").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := engine.KillEngine(2000); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os/exec"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
node1ConfigPath = path.Join(*dataDir, "redis_sentinel", "node1.conf")
|
||||
node2ConfigPath = path.Join(*dataDir, "redis_sentinel", "node2.conf")
|
||||
sentinel1ConfigPath = path.Join(*dataDir, "redis_sentinel", "sentinel1.conf")
|
||||
sentinel2ConfigPath = path.Join(*dataDir, "redis_sentinel", "sentinel2.conf")
|
||||
engineConfigPath = path.Join(*dataDir, "conf", "samples", "tutsentinel")
|
||||
sentinelConfig *config.CGRConfig
|
||||
sentinelRPC *rpc.Client
|
||||
node1Exec, node2Exec,
|
||||
stlExec1, stlExec2 *exec.Cmd
|
||||
redisSentinel = flag.Bool("redis_sentinel", false, "Run tests with redis sentinel")
|
||||
|
||||
sTestsRds = []func(t *testing.T){
|
||||
testRedisSentinelStartNodes,
|
||||
testRedisSentinelInitConfig,
|
||||
testRedisSentinelFlushDb,
|
||||
testRedisSentinelStartEngine,
|
||||
testRedisSentinelRPCCon,
|
||||
testRedisSentinelSetGetAttribute,
|
||||
testRedisSentinelInsertion,
|
||||
testRedisSentinelGetAttrAfterFailover,
|
||||
testRedisSentinelKillEngine,
|
||||
}
|
||||
)
|
||||
|
||||
// Before running these tests make sure node1.conf, node2.conf, sentinel1.conf are the next
|
||||
// Node1 will be master and start at port 16379
|
||||
// Node2 will be slave of node1 and start at port 16380
|
||||
// Sentinel1 will be started at port 16381 and will watch Node1
|
||||
// Sentinel2 will be started at port 16382 and will watch Node1
|
||||
func TestRedisSentinel(t *testing.T) {
|
||||
if !*redisSentinel {
|
||||
return
|
||||
}
|
||||
for _, stest := range sTestsRds {
|
||||
t.Run("", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelStartNodes(t *testing.T) {
|
||||
node1Exec = exec.Command("redis-server", node1ConfigPath)
|
||||
if err := node1Exec.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
node2Exec = exec.Command("redis-server", node2ConfigPath)
|
||||
if err := node2Exec.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
stlExec1 = exec.Command("redis-sentinel", sentinel1ConfigPath)
|
||||
if err := stlExec1.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
stlExec2 = exec.Command("redis-sentinel", sentinel2ConfigPath)
|
||||
if err := stlExec2.Start(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelInitConfig(t *testing.T) {
|
||||
var err error
|
||||
sentinelConfig, err = config.NewCGRConfigFromPath(engineConfigPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
sentinelConfig.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(sentinelConfig)
|
||||
}
|
||||
|
||||
func testRedisSentinelFlushDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(sentinelConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(engineConfigPath, 2000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelRPCCon(t *testing.T) {
|
||||
var err error
|
||||
sentinelRPC, err = jsonrpc.Dial("tcp", sentinelConfig.ListenCfg().RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelSetGetAttribute(t *testing.T) {
|
||||
alsPrf := &engine.AttributeProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ApierTest",
|
||||
Contexts: []string{utils.MetaSessionS, utils.MetaCDRs},
|
||||
FilterIDs: []string{"*string:Account:1001"},
|
||||
Attributes: []*engine.Attribute{
|
||||
{
|
||||
FieldName: utils.Subject,
|
||||
Value: config.NewRSRParsersMustCompile("1001", true, utils.INFIELD_SEP),
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
}
|
||||
alsPrf.Compile()
|
||||
var result string
|
||||
if err := sentinelRPC.Call("ApierV1.SetAttributeProfile", alsPrf, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
var reply *engine.AttributeProfile
|
||||
if err := sentinelRPC.Call("ApierV1.GetAttributeProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
reply.Compile()
|
||||
if !reflect.DeepEqual(alsPrf, reply) {
|
||||
t.Errorf("Expecting : %+v, received: %+v", alsPrf, reply)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelInsertion(t *testing.T) {
|
||||
nrFails1 := 0
|
||||
nrFails2 := 0
|
||||
alsPrf := &engine.AttributeProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ApierTest",
|
||||
Contexts: []string{utils.MetaSessionS, utils.MetaCDRs},
|
||||
FilterIDs: []string{"*string:Account:1001"},
|
||||
Attributes: []*engine.Attribute{
|
||||
{
|
||||
FieldName: utils.Subject,
|
||||
Value: config.NewRSRParsersMustCompile("1001", true, utils.INFIELD_SEP),
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
}
|
||||
orgiginID := alsPrf.ID + "_"
|
||||
id := alsPrf.ID + "_0"
|
||||
index := 0
|
||||
var result string
|
||||
addFunc := func(t *testing.T, nrFail *int) {
|
||||
alsPrf.ID = id
|
||||
if err := sentinelRPC.Call("ApierV1.SetAttributeProfile", alsPrf, &result); err != nil {
|
||||
if err.Error() == "SERVER_ERROR: No sentinels active" {
|
||||
*nrFail = *nrFail + 1
|
||||
} else {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
index = index + 1
|
||||
id = orgiginID + string(index)
|
||||
}
|
||||
forFunc1 := func(t *testing.T) {
|
||||
for i := 0; i < 25; i++ {
|
||||
t.Run("add", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails1)
|
||||
})
|
||||
if i == 5 {
|
||||
t.Run("stop1", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if err := stlExec1.Process.Kill(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
if i == 10 {
|
||||
t.Run("stop2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if err := stlExec2.Process.Kill(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("add2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails1)
|
||||
})
|
||||
}
|
||||
}
|
||||
forFunc2 := func(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
t.Run("add", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails2)
|
||||
})
|
||||
t.Run("add2", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
addFunc(t, &nrFails2)
|
||||
})
|
||||
}
|
||||
}
|
||||
t.Run("for1", forFunc1)
|
||||
if nrFails1 == 0 {
|
||||
t.Error("Fail tests in case of failover")
|
||||
}
|
||||
if err := exec.Command("redis-sentinel", sentinel1ConfigPath).Start(); err != nil { // Kill the master
|
||||
t.Error(err)
|
||||
}
|
||||
t.Run("for2", forFunc2)
|
||||
if nrFails2 > 19 {
|
||||
t.Errorf("Fail tests in case of failback ")
|
||||
}
|
||||
}
|
||||
|
||||
// After we kill node1 check the data if was replicated in node2
|
||||
func testRedisSentinelGetAttrAfterFailover(t *testing.T) {
|
||||
alsPrf := &engine.AttributeProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "ApierTest",
|
||||
Contexts: []string{utils.MetaSessionS, utils.MetaCDRs},
|
||||
FilterIDs: []string{"*string:Account:1001"},
|
||||
Attributes: []*engine.Attribute{
|
||||
{
|
||||
FieldName: utils.Subject,
|
||||
Value: config.NewRSRParsersMustCompile("1001", true, utils.INFIELD_SEP),
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
}
|
||||
alsPrf.Compile()
|
||||
var reply *engine.AttributeProfile
|
||||
if err := sentinelRPC.Call("ApierV1.GetAttributeProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "ApierTest"}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
reply.Compile()
|
||||
if !reflect.DeepEqual(alsPrf, reply) {
|
||||
t.Errorf("Expecting : %+v, received: %+v", alsPrf, reply)
|
||||
}
|
||||
}
|
||||
|
||||
func testRedisSentinelKillEngine(t *testing.T) {
|
||||
if err := exec.Command("pkill", "redis-server").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := exec.Command("pkill", "redis-sentinel").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := exec.Command("pkill", "redis-ser").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := exec.Command("pkill", "redis-sen").Run(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := engine.KillEngine(2000); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,15 +40,15 @@ var (
|
||||
ses2RPC *rpc.Client
|
||||
|
||||
ses2Tests = []func(t *testing.T){
|
||||
testSesItLoadConfig,
|
||||
testSesItResetDataDB,
|
||||
testSesItResetStorDb,
|
||||
testSesItStartEngine,
|
||||
testSesItRPCConn,
|
||||
testSesItLoadFromFolder,
|
||||
testSesItInitSession,
|
||||
testSesItAsActiveSessions,
|
||||
testSesItStopCgrEngine,
|
||||
testSes2ItLoadConfig,
|
||||
testSes2ItResetDataDB,
|
||||
testSes2ItResetStorDb,
|
||||
testSes2ItStartEngine,
|
||||
testSes2ItRPCConn,
|
||||
testSes2ItLoadFromFolder,
|
||||
testSes2ItInitSession,
|
||||
testSes2ItAsActiveSessions,
|
||||
testSes2ItStopCgrEngine,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -66,32 +66,32 @@ func TestSes2ItTutMysql(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testSesItLoadConfig(t *testing.T) {
|
||||
func testSes2ItLoadConfig(t *testing.T) {
|
||||
ses2CfgPath = path.Join(*dataDir, "conf", "samples", ses2CfgDir)
|
||||
if ses2Cfg, err = config.NewCGRConfigFromPath(ses2CfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesItResetDataDB(t *testing.T) {
|
||||
func testSes2ItResetDataDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(ses2Cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesItResetStorDb(t *testing.T) {
|
||||
func testSes2ItResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(ses2Cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesItStartEngine(t *testing.T) {
|
||||
func testSes2ItStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(ses2CfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSesItRPCConn(t *testing.T) {
|
||||
func testSes2ItRPCConn(t *testing.T) {
|
||||
var err error
|
||||
ses2RPC, err = jsonrpc.Dial("tcp", ses2Cfg.ListenCfg().RPCJSONListen)
|
||||
if err != nil {
|
||||
@@ -99,7 +99,7 @@ func testSesItRPCConn(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testSesItLoadFromFolder(t *testing.T) {
|
||||
func testSes2ItLoadFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
if err := ses2RPC.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
@@ -108,7 +108,7 @@ func testSesItLoadFromFolder(t *testing.T) {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func testSesItInitSession(t *testing.T) {
|
||||
func testSes2ItInitSession(t *testing.T) {
|
||||
// Set balance
|
||||
attrSetBalance := utils.AttrSetBalance{
|
||||
Tenant: "cgrates.org",
|
||||
@@ -151,7 +151,7 @@ func testSesItInitSession(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func testSesItAsActiveSessions(t *testing.T) {
|
||||
func testSes2ItAsActiveSessions(t *testing.T) {
|
||||
var count int
|
||||
if err := ses2RPC.Call(utils.SessionSv1GetActiveSessionsCount, utils.SessionFilter{
|
||||
Filters: []string{"*string:~Account:1001"},
|
||||
@@ -169,7 +169,7 @@ func testSesItAsActiveSessions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testSesItStopCgrEngine(t *testing.T) {
|
||||
func testSes2ItStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -38,35 +38,54 @@ var (
|
||||
sesRPC *rpc.Client
|
||||
sesAccount = "refundAcc"
|
||||
sesTenant = "cgrates.org"
|
||||
|
||||
sTestSesIt = []func(t *testing.T){
|
||||
testSesItLoadConfig,
|
||||
testSesItResetDataDB,
|
||||
testSesItResetStorDb,
|
||||
testSesItStartEngine,
|
||||
testSesItRPCConn,
|
||||
testSesItLoadFromFolder,
|
||||
testSesItAddVoiceBalance,
|
||||
testSesItInitSession,
|
||||
testSesItTerminateSession,
|
||||
testSesItStopCgrEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestSesIt(t *testing.T) {
|
||||
for _, stest := range sTestSesIt {
|
||||
t.Run("TestSesIT", stest)
|
||||
}
|
||||
}
|
||||
|
||||
// test for 0 balance with session terminate with 1s usage
|
||||
func TestSesItLoadConfig(t *testing.T) {
|
||||
func testSesItLoadConfig(t *testing.T) {
|
||||
sesCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql_internal")
|
||||
if sesCfg, err = config.NewCGRConfigFromPath(sesCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSesItResetDataDB(t *testing.T) {
|
||||
func testSesItResetDataDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(sesCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSesItResetStorDb(t *testing.T) {
|
||||
func testSesItResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(sesCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSesItStartEngine(t *testing.T) {
|
||||
func testSesItStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(sesCfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSesItRPCConn(t *testing.T) {
|
||||
func testSesItRPCConn(t *testing.T) {
|
||||
var err error
|
||||
sesRPC, err = jsonrpc.Dial("tcp", sesCfg.ListenCfg().RPCJSONListen)
|
||||
if err != nil {
|
||||
@@ -74,7 +93,7 @@ func TestSesItRPCConn(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSesItLoadFromFolder(t *testing.T) {
|
||||
func testSesItLoadFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "testit")}
|
||||
if err := sesRPC.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
@@ -97,7 +116,7 @@ func testAccountBalance2(t *testing.T, sracc, srten, balType string, expected fl
|
||||
}
|
||||
}
|
||||
|
||||
func TestSesItAddVoiceBalance(t *testing.T) {
|
||||
func testSesItAddVoiceBalance(t *testing.T) {
|
||||
attrSetBalance := utils.AttrSetBalance{
|
||||
Tenant: sesTenant,
|
||||
Account: sesAccount,
|
||||
@@ -115,7 +134,7 @@ func TestSesItAddVoiceBalance(t *testing.T) {
|
||||
t.Run("TestAddVoiceBalance", func(t *testing.T) { testAccountBalance2(t, sesAccount, sesTenant, utils.MONETARY, 0) })
|
||||
}
|
||||
|
||||
func TestSesItInitSession(t *testing.T) {
|
||||
func testSesItInitSession(t *testing.T) {
|
||||
args1 := &sessions.V1InitSessionArgs{
|
||||
InitSession: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -147,7 +166,7 @@ func TestSesItInitSession(t *testing.T) {
|
||||
t.Run("TestInitSession", func(t *testing.T) { testAccountBalance2(t, sesAccount, sesTenant, utils.MONETARY, 0) })
|
||||
}
|
||||
|
||||
func TestSesItTerminateSession(t *testing.T) {
|
||||
func testSesItTerminateSession(t *testing.T) {
|
||||
args := &sessions.V1TerminateSessionArgs{
|
||||
TerminateSession: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -184,7 +203,7 @@ func TestSesItTerminateSession(t *testing.T) {
|
||||
t.Run("TestTerminateSession", func(t *testing.T) { testAccountBalance2(t, sesAccount, sesTenant, utils.MONETARY, 0) })
|
||||
}
|
||||
|
||||
func TestSesItStopCgrEngine(t *testing.T) {
|
||||
func testSesItStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -38,34 +38,56 @@ var (
|
||||
srrpc *rpc.Client
|
||||
sraccount = "refundAcc"
|
||||
srtenant = "cgrates.org"
|
||||
|
||||
sTestSrIt = []func(t *testing.T){
|
||||
testSrItLoadConfig,
|
||||
testSrItResetDataDB,
|
||||
testSrItResetStorDb,
|
||||
testSrItStartEngine,
|
||||
testSrItRPCConn,
|
||||
testSrItLoadFromFolder,
|
||||
testSrItAddVoiceBalance,
|
||||
testSrItInitSession,
|
||||
testSrItTerminateSession,
|
||||
testSrItAddMonetaryBalance,
|
||||
testSrItInitSession2,
|
||||
testSrItTerminateSession2,
|
||||
testSrItStopCgrEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestSrItLoadConfig(t *testing.T) {
|
||||
func TestSrIt(t *testing.T) {
|
||||
for _, stest := range sTestSrIt {
|
||||
t.Run("sTestSrIt", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testSrItLoadConfig(t *testing.T) {
|
||||
srCfgPath = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
if srCfg, err = config.NewCGRConfigFromPath(srCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSrItResetDataDB(t *testing.T) {
|
||||
func testSrItResetDataDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(srCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSrItResetStorDb(t *testing.T) {
|
||||
func testSrItResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(srCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSrItStartEngine(t *testing.T) {
|
||||
func testSrItStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(srCfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSrItRPCConn(t *testing.T) {
|
||||
func testSrItRPCConn(t *testing.T) {
|
||||
var err error
|
||||
srrpc, err = jsonrpc.Dial("tcp", srCfg.ListenCfg().RPCJSONListen)
|
||||
if err != nil {
|
||||
@@ -73,7 +95,7 @@ func TestSrItRPCConn(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSrItLoadFromFolder(t *testing.T) {
|
||||
func testSrItLoadFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "oldtutorial")}
|
||||
if err := srrpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
@@ -96,7 +118,7 @@ func testAccountBalance(t *testing.T, sracc, srten, balType string, expected flo
|
||||
}
|
||||
}
|
||||
|
||||
func TestSrItAddVoiceBalance(t *testing.T) {
|
||||
func testSrItAddVoiceBalance(t *testing.T) {
|
||||
attrSetBalance := utils.AttrSetBalance{
|
||||
Tenant: srtenant,
|
||||
Account: sraccount,
|
||||
@@ -114,7 +136,7 @@ func TestSrItAddVoiceBalance(t *testing.T) {
|
||||
t.Run("TestAddVoiceBalance", func(t *testing.T) { testAccountBalance(t, sraccount, srtenant, utils.VOICE, 5*float64(time.Second)) })
|
||||
}
|
||||
|
||||
func TestSrItInitSession(t *testing.T) {
|
||||
func testSrItInitSession(t *testing.T) {
|
||||
args1 := &sessions.V1InitSessionArgs{
|
||||
InitSession: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -146,7 +168,7 @@ func TestSrItInitSession(t *testing.T) {
|
||||
t.Run("TestInitSession", func(t *testing.T) { testAccountBalance(t, sraccount, srtenant, utils.VOICE, 3*float64(time.Second)) })
|
||||
}
|
||||
|
||||
func TestSrItTerminateSession(t *testing.T) {
|
||||
func testSrItTerminateSession(t *testing.T) {
|
||||
args := &sessions.V1TerminateSessionArgs{
|
||||
TerminateSession: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -183,7 +205,7 @@ func TestSrItTerminateSession(t *testing.T) {
|
||||
t.Run("TestTerminateSession", func(t *testing.T) { testAccountBalance(t, sraccount, srtenant, utils.VOICE, 5*float64(time.Second)) })
|
||||
}
|
||||
|
||||
func TestSrItAddMonetaryBalance(t *testing.T) {
|
||||
func testSrItAddMonetaryBalance(t *testing.T) {
|
||||
sraccount += "2"
|
||||
attrs := &utils.AttrSetBalance{
|
||||
Tenant: srtenant,
|
||||
@@ -201,7 +223,7 @@ func TestSrItAddMonetaryBalance(t *testing.T) {
|
||||
t.Run("TestAddMonetaryBalance", func(t *testing.T) { testAccountBalance(t, sraccount, srtenant, utils.MONETARY, 10.65) })
|
||||
}
|
||||
|
||||
func TestSrItInitSession2(t *testing.T) {
|
||||
func testSrItInitSession2(t *testing.T) {
|
||||
args1 := &sessions.V1InitSessionArgs{
|
||||
InitSession: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -233,7 +255,7 @@ func TestSrItInitSession2(t *testing.T) {
|
||||
t.Run("TestInitSession", func(t *testing.T) { testAccountBalance(t, sraccount, srtenant, utils.MONETARY, 10.3002) })
|
||||
}
|
||||
|
||||
func TestSrItTerminateSession2(t *testing.T) {
|
||||
func testSrItTerminateSession2(t *testing.T) {
|
||||
args := &sessions.V1TerminateSessionArgs{
|
||||
TerminateSession: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
@@ -270,7 +292,7 @@ func TestSrItTerminateSession2(t *testing.T) {
|
||||
t.Run("TestTerminateSession", func(t *testing.T) { testAccountBalance(t, sraccount, srtenant, utils.MONETARY, 10.65) })
|
||||
}
|
||||
|
||||
func TestSrItStopCgrEngine(t *testing.T) {
|
||||
func testSrItStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -39,26 +39,26 @@ var (
|
||||
splSv1Rpc *rpc.Client
|
||||
splPrf *engine.SupplierProfile
|
||||
splSv1ConfDIR string //run tests for specific configuration
|
||||
)
|
||||
|
||||
var sTestsSupplierSV1 = []func(t *testing.T){
|
||||
testV1SplSLoadConfig,
|
||||
testV1SplSInitDataDb,
|
||||
testV1SplSResetStorDb,
|
||||
testV1SplSStartEngine,
|
||||
testV1SplSRpcConn,
|
||||
testV1SplSFromFolder,
|
||||
testV1SplSSetSupplierProfilesWithoutRatingPlanIDs,
|
||||
//tests for *reas sorting strategy
|
||||
testV1SplSAddNewSplPrf,
|
||||
testV1SplSAddNewResPrf,
|
||||
testV1SplSPopulateResUsage,
|
||||
testV1SplSGetSortedSuppliers,
|
||||
//tests for *reds sorting strategy
|
||||
testV1SplSAddNewSplPrf2,
|
||||
testV1SplSGetSortedSuppliers2,
|
||||
testV1SplSStopEngine,
|
||||
}
|
||||
sTestsSupplierSV1 = []func(t *testing.T){
|
||||
testV1SplSLoadConfig,
|
||||
testV1SplSInitDataDb,
|
||||
testV1SplSResetStorDb,
|
||||
testV1SplSStartEngine,
|
||||
testV1SplSRpcConn,
|
||||
testV1SplSFromFolder,
|
||||
testV1SplSSetSupplierProfilesWithoutRatingPlanIDs,
|
||||
//tests for *reas sorting strategy
|
||||
testV1SplSAddNewSplPrf,
|
||||
testV1SplSAddNewResPrf,
|
||||
testV1SplSPopulateResUsage,
|
||||
testV1SplSGetSortedSuppliers,
|
||||
//tests for *reds sorting strategy
|
||||
testV1SplSAddNewSplPrf2,
|
||||
testV1SplSGetSortedSuppliers2,
|
||||
testV1SplSStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
// Test start here
|
||||
func TestSuplSV1ITMySQL(t *testing.T) {
|
||||
|
||||
@@ -38,14 +38,35 @@ Integration tests with SureTax platform.
|
||||
Configuration file is kept outside of CGRateS repository since it contains sensitive customer information
|
||||
*/
|
||||
|
||||
var configDir = flag.String("config_path", "", "CGR config dir path here")
|
||||
var tpDir = flag.String("tp_dir", "", "CGR config dir path here")
|
||||
var (
|
||||
configDir = flag.String("config_path", "", "CGR config dir path here")
|
||||
tpDir = flag.String("tp_dir", "", "CGR config dir path here")
|
||||
|
||||
var stiCfg *config.CGRConfig
|
||||
var stiRpc *rpc.Client
|
||||
var stiLoadInst utils.LoadInstance
|
||||
stiCfg *config.CGRConfig
|
||||
stiRpc *rpc.Client
|
||||
stiLoadInst utils.LoadInstance
|
||||
|
||||
func TestSTIInitCfg(t *testing.T) {
|
||||
sTestSTI = []func(t *testing.T){
|
||||
testSTIInitCfg,
|
||||
testSTIResetDataDb,
|
||||
testSTIResetStorDb,
|
||||
testSTIStartEngine,
|
||||
testSTIRpcConn,
|
||||
testSTILoadTariffPlanFromFolder,
|
||||
testSTICacheStats,
|
||||
testSTIProcessExternalCdr,
|
||||
testSTIGetCdrs,
|
||||
testSTIStopCgrEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestSTI(t *testing.T) {
|
||||
for _, stest := range sTestSTI {
|
||||
t.Run("TestSTI", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testSTIInitCfg(t *testing.T) {
|
||||
// Init config first
|
||||
var err error
|
||||
stiCfg, err = config.NewCGRConfigFromPath(*configDir)
|
||||
@@ -55,28 +76,28 @@ func TestSTIInitCfg(t *testing.T) {
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestSTIResetDataDb(t *testing.T) {
|
||||
func testSTIResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(stiCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestSTIResetStorDb(t *testing.T) {
|
||||
func testSTIResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(stiCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestSTIStartEngine(t *testing.T) {
|
||||
func testSTIStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(*configDir, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestSTIRpcConn(t *testing.T) {
|
||||
func testSTIRpcConn(t *testing.T) {
|
||||
var err error
|
||||
stiRpc, err = jsonrpc.Dial("tcp", stiCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
@@ -85,7 +106,7 @@ func TestSTIRpcConn(t *testing.T) {
|
||||
}
|
||||
|
||||
// Load the tariff plan, creating accounts and their balances
|
||||
func TestSTILoadTariffPlanFromFolder(t *testing.T) {
|
||||
func testSTILoadTariffPlanFromFolder(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: *tpDir}
|
||||
if err := stiRpc.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &stiLoadInst); err != nil {
|
||||
t.Error(err)
|
||||
@@ -96,7 +117,7 @@ func TestSTILoadTariffPlanFromFolder(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check loaded stats
|
||||
func TestSTICacheStats(t *testing.T) {
|
||||
func testSTICacheStats(t *testing.T) {
|
||||
var rcvStats *utils.CacheStats
|
||||
expectedStats := &utils.CacheStats{Destinations: 1, RatingPlans: 1, RatingProfiles: 1}
|
||||
var args utils.AttrCacheStats
|
||||
@@ -108,7 +129,7 @@ func TestSTICacheStats(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test CDR from external sources
|
||||
func TestSTIProcessExternalCdr(t *testing.T) {
|
||||
func testSTIProcessExternalCdr(t *testing.T) {
|
||||
cdr := &engine.ExternalCDR{ToR: utils.VOICE,
|
||||
OriginID: "teststicdr1", OriginHost: "192.168.1.1", Source: "STI_TEST", RequestType: utils.META_RATED, Direction: utils.META_OUT,
|
||||
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "+14082342500", Destination: "+16268412300", Supplier: "SUPPL1",
|
||||
@@ -124,7 +145,7 @@ func TestSTIProcessExternalCdr(t *testing.T) {
|
||||
time.Sleep(time.Duration(2) * time.Second)
|
||||
}
|
||||
|
||||
func TestSTIGetCdrs(t *testing.T) {
|
||||
func testSTIGetCdrs(t *testing.T) {
|
||||
var cdrs []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}}
|
||||
if err := stiRpc.Call(utils.ApierV2GetCDRs, req, &cdrs); err != nil {
|
||||
@@ -148,7 +169,7 @@ func TestSTIGetCdrs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSTIStopCgrEngine(t *testing.T) {
|
||||
func testSTIStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -1,168 +1,168 @@
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/rpcclient"
|
||||
)
|
||||
|
||||
var (
|
||||
tlsCfgPath string
|
||||
tlsCfg *config.CGRConfig
|
||||
tlsRpcClientJson *rpcclient.RpcClient
|
||||
tlsRpcClientGob *rpcclient.RpcClient
|
||||
tlsHTTPJson *rpcclient.RpcClient
|
||||
tlsConfDIR string //run tests for specific configuration
|
||||
tlsDelay int
|
||||
)
|
||||
|
||||
var sTestsTLS = []func(t *testing.T){
|
||||
testTLSLoadConfig,
|
||||
testTLSInitDataDb,
|
||||
testTLSStartEngine,
|
||||
testTLSRpcConn,
|
||||
testTLSPing,
|
||||
testTLSStopEngine,
|
||||
}
|
||||
|
||||
// Test start here
|
||||
func TestTLS(t *testing.T) {
|
||||
tlsConfDIR = "tls"
|
||||
for _, stest := range sTestsTLS {
|
||||
t.Run(tlsConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSLoadConfig(t *testing.T) {
|
||||
var err error
|
||||
tlsCfgPath = path.Join(*dataDir, "conf", "samples", tlsConfDIR)
|
||||
if tlsCfg, err = config.NewCGRConfigFromPath(tlsCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tlsDelay = 2000
|
||||
}
|
||||
|
||||
func testTLSInitDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tlsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tlsCfgPath, tlsDelay); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tlsRpcClientJson, err = rpcclient.NewRpcClient("tcp", "localhost:2022", true, tlsCfg.TlsCfg().ClientKey,
|
||||
tlsCfg.TlsCfg().ClientCerificate, tlsCfg.TlsCfg().CaCertificate, 3, 3,
|
||||
time.Duration(1*time.Second), time.Duration(5*time.Minute), utils.JSON, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s when dialing", err)
|
||||
}
|
||||
|
||||
tlsRpcClientGob, err = rpcclient.NewRpcClient("tcp", "localhost:2023", true, tlsCfg.TlsCfg().ClientKey,
|
||||
tlsCfg.TlsCfg().ClientCerificate, tlsCfg.TlsCfg().CaCertificate, 3, 3,
|
||||
time.Duration(1*time.Second), time.Duration(5*time.Minute), utils.GOB, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s when dialing", err)
|
||||
}
|
||||
|
||||
tlsHTTPJson, err = rpcclient.NewRpcClient("tcp", "https://localhost:2280/jsonrpc", true, tlsCfg.TlsCfg().ClientKey,
|
||||
tlsCfg.TlsCfg().ClientCerificate, tlsCfg.TlsCfg().CaCertificate, 3, 3,
|
||||
time.Duration(1*time.Second), time.Duration(5*time.Minute), rpcclient.JSON_HTTP, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s when dialing", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSPing(t *testing.T) {
|
||||
var reply string
|
||||
|
||||
if err := tlsRpcClientJson.Call(utils.ThresholdSv1Ping, new(utils.CGREvent), &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.Pong {
|
||||
t.Errorf("Received: %s", reply)
|
||||
}
|
||||
if err := tlsRpcClientGob.Call(utils.ThresholdSv1Ping, new(utils.CGREvent), &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.Pong {
|
||||
t.Errorf("Received: %s", reply)
|
||||
}
|
||||
if err := tlsHTTPJson.Call(utils.ThresholdSv1Ping, new(utils.CGREvent), &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.Pong {
|
||||
t.Errorf("Received: %s", reply)
|
||||
}
|
||||
if err := tlsRpcClientJson.Call(utils.DispatcherSv1Ping, "", &reply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := tlsRpcClientGob.Call(utils.DispatcherSv1Ping, "", &reply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := tlsHTTPJson.Call(utils.DispatcherSv1Ping, "", &reply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
initUsage := time.Duration(5 * time.Minute)
|
||||
args := &sessions.V1InitSessionArgs{
|
||||
InitSession: true,
|
||||
AllocateResources: true,
|
||||
GetAttributes: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TestSSv1ItInitiateSession",
|
||||
Event: map[string]interface{}{
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.Category: "call",
|
||||
utils.ToR: utils.VOICE,
|
||||
utils.OriginID: "TestSSv1It1",
|
||||
utils.RequestType: utils.META_PREPAID,
|
||||
utils.Account: "1001",
|
||||
utils.Subject: "ANY2CNT",
|
||||
utils.Destination: "1002",
|
||||
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: initUsage,
|
||||
},
|
||||
},
|
||||
}
|
||||
var rply sessions.V1InitReplyWithDigest
|
||||
if err := tlsHTTPJson.Call(utils.SessionSv1InitiateSessionWithDigest,
|
||||
args, &rply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/rpcclient"
|
||||
)
|
||||
|
||||
var (
|
||||
tlsCfgPath string
|
||||
tlsCfg *config.CGRConfig
|
||||
tlsRpcClientJson *rpcclient.RpcClient
|
||||
tlsRpcClientGob *rpcclient.RpcClient
|
||||
tlsHTTPJson *rpcclient.RpcClient
|
||||
tlsConfDIR string //run tests for specific configuration
|
||||
tlsDelay int
|
||||
|
||||
sTestsTLS = []func(t *testing.T){
|
||||
testTLSLoadConfig,
|
||||
testTLSInitDataDb,
|
||||
testTLSStartEngine,
|
||||
testTLSRpcConn,
|
||||
testTLSPing,
|
||||
testTLSStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
// Test start here
|
||||
func TestTLS(t *testing.T) {
|
||||
tlsConfDIR = "tls"
|
||||
for _, stest := range sTestsTLS {
|
||||
t.Run(tlsConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSLoadConfig(t *testing.T) {
|
||||
var err error
|
||||
tlsCfgPath = path.Join(*dataDir, "conf", "samples", tlsConfDIR)
|
||||
if tlsCfg, err = config.NewCGRConfigFromPath(tlsCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tlsDelay = 2000
|
||||
}
|
||||
|
||||
func testTLSInitDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tlsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tlsCfgPath, tlsDelay); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tlsRpcClientJson, err = rpcclient.NewRpcClient("tcp", "localhost:2022", true, tlsCfg.TlsCfg().ClientKey,
|
||||
tlsCfg.TlsCfg().ClientCerificate, tlsCfg.TlsCfg().CaCertificate, 3, 3,
|
||||
time.Duration(1*time.Second), time.Duration(5*time.Minute), utils.JSON, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s when dialing", err)
|
||||
}
|
||||
|
||||
tlsRpcClientGob, err = rpcclient.NewRpcClient("tcp", "localhost:2023", true, tlsCfg.TlsCfg().ClientKey,
|
||||
tlsCfg.TlsCfg().ClientCerificate, tlsCfg.TlsCfg().CaCertificate, 3, 3,
|
||||
time.Duration(1*time.Second), time.Duration(5*time.Minute), utils.GOB, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s when dialing", err)
|
||||
}
|
||||
|
||||
tlsHTTPJson, err = rpcclient.NewRpcClient("tcp", "https://localhost:2280/jsonrpc", true, tlsCfg.TlsCfg().ClientKey,
|
||||
tlsCfg.TlsCfg().ClientCerificate, tlsCfg.TlsCfg().CaCertificate, 3, 3,
|
||||
time.Duration(1*time.Second), time.Duration(5*time.Minute), rpcclient.JSON_HTTP, nil, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s when dialing", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSPing(t *testing.T) {
|
||||
var reply string
|
||||
|
||||
if err := tlsRpcClientJson.Call(utils.ThresholdSv1Ping, new(utils.CGREvent), &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.Pong {
|
||||
t.Errorf("Received: %s", reply)
|
||||
}
|
||||
if err := tlsRpcClientGob.Call(utils.ThresholdSv1Ping, new(utils.CGREvent), &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.Pong {
|
||||
t.Errorf("Received: %s", reply)
|
||||
}
|
||||
if err := tlsHTTPJson.Call(utils.ThresholdSv1Ping, new(utils.CGREvent), &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.Pong {
|
||||
t.Errorf("Received: %s", reply)
|
||||
}
|
||||
if err := tlsRpcClientJson.Call(utils.DispatcherSv1Ping, "", &reply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := tlsRpcClientGob.Call(utils.DispatcherSv1Ping, "", &reply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := tlsHTTPJson.Call(utils.DispatcherSv1Ping, "", &reply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
initUsage := time.Duration(5 * time.Minute)
|
||||
args := &sessions.V1InitSessionArgs{
|
||||
InitSession: true,
|
||||
AllocateResources: true,
|
||||
GetAttributes: true,
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "TestSSv1ItInitiateSession",
|
||||
Event: map[string]interface{}{
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.Category: "call",
|
||||
utils.ToR: utils.VOICE,
|
||||
utils.OriginID: "TestSSv1It1",
|
||||
utils.RequestType: utils.META_PREPAID,
|
||||
utils.Account: "1001",
|
||||
utils.Subject: "ANY2CNT",
|
||||
utils.Destination: "1002",
|
||||
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: initUsage,
|
||||
},
|
||||
},
|
||||
}
|
||||
var rply sessions.V1InitReplyWithDigest
|
||||
if err := tlsHTTPJson.Call(utils.SessionSv1InitiateSessionWithDigest,
|
||||
args, &rply); err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTLSStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,12 +34,40 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var tpCfgPath string
|
||||
var tpCfg *config.CGRConfig
|
||||
var tpRPC *rpc.Client
|
||||
var tpLoadInst utils.LoadInstance // Share load information between tests
|
||||
var (
|
||||
tpCfgPath string
|
||||
tpCfg *config.CGRConfig
|
||||
tpRPC *rpc.Client
|
||||
tpLoadInst utils.LoadInstance // Share load information between tests
|
||||
|
||||
func TestTpInitCfg(t *testing.T) {
|
||||
sTestTp = []func(t *testing.T){
|
||||
testTpInitCfg,
|
||||
testTpResetDataDb,
|
||||
testTpResetStorDb,
|
||||
testTpStartEngine,
|
||||
testTpRpcConn,
|
||||
testTpLoadTariffPlanFromFolder,
|
||||
testTpBalanceCounter,
|
||||
testTpActionTriggers,
|
||||
testTpZeroCost,
|
||||
testTpZeroNegativeCost,
|
||||
testTpExecuteActionCgrRpc,
|
||||
testTpExecuteActionCgrRpcAcc,
|
||||
//testTpExecuteActionCgrRpcCdrStats,
|
||||
testTpCreateExecuteActionMatch,
|
||||
testTpSetRemoveActions,
|
||||
testTpRemoveActionsRefenced,
|
||||
testTpApierResetAccountActionTriggers,
|
||||
testTpStopCgrEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestTp(t *testing.T) {
|
||||
for _, stest := range sTestTp {
|
||||
t.Run("TestTp", stest)
|
||||
}
|
||||
}
|
||||
func testTpInitCfg(t *testing.T) {
|
||||
tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
// Init config first
|
||||
var err error
|
||||
@@ -52,28 +80,28 @@ func TestTpInitCfg(t *testing.T) {
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestTpResetDataDb(t *testing.T) {
|
||||
func testTpResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tpCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestTpResetStorDb(t *testing.T) {
|
||||
func testTpResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(tpCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestTpStartEngine(t *testing.T) {
|
||||
func testTpStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tpCfgPath, 1000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestTpRpcConn(t *testing.T) {
|
||||
func testTpRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tpRPC, err = jsonrpc.Dial("tcp", tpCfg.ListenCfg().RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
@@ -82,7 +110,7 @@ func TestTpRpcConn(t *testing.T) {
|
||||
}
|
||||
|
||||
// Load the tariff plan, creating accounts and their balances
|
||||
func TestTpLoadTariffPlanFromFolder(t *testing.T) {
|
||||
func testTpLoadTariffPlanFromFolder(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "testtp")}
|
||||
if err := tpRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &tpLoadInst); err != nil {
|
||||
t.Error(err)
|
||||
@@ -90,7 +118,7 @@ func TestTpLoadTariffPlanFromFolder(t *testing.T) {
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
func TestTpBalanceCounter(t *testing.T) {
|
||||
func testTpBalanceCounter(t *testing.T) {
|
||||
tStart := time.Date(2016, 3, 31, 0, 0, 0, 0, time.UTC)
|
||||
cd := engine.CallDescriptor{
|
||||
Category: "call",
|
||||
@@ -116,7 +144,7 @@ func TestTpBalanceCounter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpActionTriggers(t *testing.T) {
|
||||
func testTpActionTriggers(t *testing.T) {
|
||||
var atrs engine.ActionTriggers
|
||||
if err := tpRPC.Call("ApierV1.GetActionTriggers", v1.AttrGetActionTriggers{GroupIDs: []string{}}, &atrs); err != nil {
|
||||
t.Error("Got error on ApierV1.GetActionTriggers: ", err.Error())
|
||||
@@ -157,7 +185,7 @@ func TestTpActionTriggers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpZeroCost(t *testing.T) {
|
||||
func testTpZeroCost(t *testing.T) {
|
||||
var acnt *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1012"}
|
||||
if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
|
||||
@@ -195,7 +223,7 @@ func TestTpZeroCost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpZeroNegativeCost(t *testing.T) {
|
||||
func testTpZeroNegativeCost(t *testing.T) {
|
||||
tStart := time.Date(2016, 3, 31, 0, 0, 0, 0, time.UTC)
|
||||
cd := engine.CallDescriptor{
|
||||
Category: "call",
|
||||
@@ -222,7 +250,7 @@ func TestTpZeroNegativeCost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpExecuteActionCgrRpc(t *testing.T) {
|
||||
func testTpExecuteActionCgrRpc(t *testing.T) {
|
||||
var reply string
|
||||
if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{ActionsId: "RPC"}, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.ExecuteAction: ", err.Error())
|
||||
@@ -236,7 +264,7 @@ func TestTpExecuteActionCgrRpc(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpExecuteActionCgrRpcAcc(t *testing.T) {
|
||||
func testTpExecuteActionCgrRpcAcc(t *testing.T) {
|
||||
var reply string
|
||||
if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{
|
||||
Tenant: "cgrates.org",
|
||||
@@ -255,7 +283,7 @@ func TestTpExecuteActionCgrRpcAcc(t *testing.T) {
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
// func TestTpExecuteActionCgrRpcCdrStats(t *testing.T) {
|
||||
// func //(t *testing.T) {
|
||||
// var reply string
|
||||
// if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{
|
||||
// ActionsId: "RPC_CDRSTATS",
|
||||
@@ -271,7 +299,7 @@ func TestTpExecuteActionCgrRpcAcc(t *testing.T) {
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestTpCreateExecuteActionMatch(t *testing.T) {
|
||||
func testTpCreateExecuteActionMatch(t *testing.T) {
|
||||
var reply string
|
||||
if err := tpRPC.Call("ApierV2.SetActions", utils.AttrSetActions{
|
||||
ActionsId: "PAYMENT_2056bd2fe137082970f97102b64e42fd",
|
||||
@@ -319,7 +347,7 @@ func TestTpCreateExecuteActionMatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpSetRemoveActions(t *testing.T) {
|
||||
func testTpSetRemoveActions(t *testing.T) {
|
||||
var reply string
|
||||
if err := tpRPC.Call("ApierV2.SetActions", utils.AttrSetActions{
|
||||
ActionsId: "TO_BE_DELETED",
|
||||
@@ -359,7 +387,7 @@ func TestTpSetRemoveActions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpRemoveActionsRefenced(t *testing.T) {
|
||||
func testTpRemoveActionsRefenced(t *testing.T) {
|
||||
actionsMap := make(map[string]engine.Actions)
|
||||
if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{
|
||||
ActionIDs: []string{"TOPUP_VOICE"},
|
||||
@@ -385,7 +413,7 @@ func TestTpRemoveActionsRefenced(t *testing.T) {
|
||||
*/
|
||||
}
|
||||
|
||||
func TestTpApierResetAccountActionTriggers(t *testing.T) {
|
||||
func testTpApierResetAccountActionTriggers(t *testing.T) {
|
||||
var acnt engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1005"}
|
||||
if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
|
||||
@@ -411,7 +439,7 @@ func TestTpApierResetAccountActionTriggers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpStopCgrEngine(t *testing.T) {
|
||||
func testTpStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -34,10 +34,29 @@ import (
|
||||
"github.com/cgrates/ltcache"
|
||||
)
|
||||
|
||||
var tutSMGCfgPath string
|
||||
var tutSMGCfg *config.CGRConfig
|
||||
var tutSMGRpc *rpc.Client
|
||||
var smgLoadInst utils.LoadInstance // Share load information between tests
|
||||
var (
|
||||
tutSMGCfgPath string
|
||||
tutSMGCfg *config.CGRConfig
|
||||
tutSMGRpc *rpc.Client
|
||||
smgLoadInst utils.LoadInstance // Share load information between tests
|
||||
|
||||
sTestTutSMG = []func(t *testing.T){
|
||||
TestTutSMGInitCfg,
|
||||
TestTutSMGResetDataDb,
|
||||
TestTutSMGResetStorDb,
|
||||
TestTutSMGStartEngine,
|
||||
TestTutSMGRpcConn,
|
||||
TestTutSMGLoadTariffPlanFromFolder,
|
||||
TestTutSMGCacheStats,
|
||||
TestTutSMGStopCgrEngine,
|
||||
}
|
||||
)
|
||||
|
||||
func TestTutSMG(t *testing.T) {
|
||||
for _, stest := range sTestTutSMG {
|
||||
t.Run("TestTutSMG", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutSMGInitCfg(t *testing.T) {
|
||||
tutSMGCfgPath = path.Join(*dataDir, "conf", "samples", "smgeneric")
|
||||
|
||||
@@ -1,315 +1,315 @@
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "github.com/cgrates/cgrates/apier/v1"
|
||||
v2 "github.com/cgrates/cgrates/apier/v2"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
tutCfgPath string
|
||||
tutCfg *config.CGRConfig
|
||||
tutRpc *rpc.Client
|
||||
tutCfgDir string //run tests for specific configuration
|
||||
tutDelay int
|
||||
)
|
||||
|
||||
var sTutTests = []func(t *testing.T){
|
||||
testTutLoadConfig,
|
||||
testTutResetDB,
|
||||
testTutStartEngine,
|
||||
testTutRpcConn,
|
||||
testTutFromFolder,
|
||||
testTutGetCost,
|
||||
testTutAccounts,
|
||||
testTutStopEngine,
|
||||
}
|
||||
|
||||
//Test start here
|
||||
func TestTutorial2MySQL(t *testing.T) {
|
||||
tutCfgDir = "tutmysql2"
|
||||
for _, stest := range sTutTests {
|
||||
t.Run(tutCfgDir, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutorial2Mongo(t *testing.T) {
|
||||
tutCfgDir = "tutmongo2"
|
||||
for _, stest := range sTutTests {
|
||||
t.Run(tutCfgDir, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutLoadConfig(t *testing.T) {
|
||||
var err error
|
||||
tutCfgPath = path.Join(*dataDir, "conf", "samples", tutCfgDir)
|
||||
if tutCfg, err = config.NewCGRConfigFromPath(tutCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tutDelay = 2000
|
||||
}
|
||||
|
||||
func testTutResetDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := engine.InitStorDb(tutCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tutCfgPath, tutDelay); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutRpcConn(t *testing.T) {
|
||||
var err error
|
||||
if tutRpc, err = jsonrpc.Dial("tcp", tutCfg.ListenCfg().RPCJSONListen); err != nil {
|
||||
t.Fatal("could not connect to rater: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testTutFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{
|
||||
FolderPath: path.Join(*dataDir, "tariffplans", "tutorial2")}
|
||||
if err := tutRpc.Call(utils.ApierV1LoadTariffPlanFromFolder,
|
||||
attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func testTutGetCost(t *testing.T) {
|
||||
// Standard pricing for 1001->1002
|
||||
attrs := v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "45s",
|
||||
}
|
||||
var rply *engine.EventCost
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.550000 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Fallback pricing from *any, Usage will be rounded to 60s
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "2019-03-11T09:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 1.4 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Fallback pricing from *any, Usage will be rounded to 60s
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "2019-03-11T21:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
// *any to 2001
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1002",
|
||||
Destination: "2001",
|
||||
AnswerTime: "*now",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 1.4 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// *any to 2001 on NEW_YEAR
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1002",
|
||||
Destination: "2001",
|
||||
AnswerTime: "2020-01-01T21:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.55 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Fallback pricing from *any, Usage will be rounded to 60s
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "2019-03-11T21:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.55 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Unauthorized destination
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "4003",
|
||||
AnswerTime: "2019-03-11T09:00:00Z",
|
||||
Usage: "1m",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err == nil ||
|
||||
err.Error() != "SERVER_ERROR: UNAUTHORIZED_DESTINATION" {
|
||||
t.Error("Unexpected nil error received: ", err)
|
||||
}
|
||||
// Data charging
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "data",
|
||||
Subject: "1001",
|
||||
AnswerTime: "*now",
|
||||
Usage: "2048",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 2.0 { // FixMe: missing ConnectFee out of Cost
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// SMS charging 1002
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "sms",
|
||||
Subject: "1003",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "1",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.1 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// SMS charging 10
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "sms",
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "*now",
|
||||
Usage: "1",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.2 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// SMS charging UNAUTHORIZED
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "sms",
|
||||
Subject: "1001",
|
||||
Destination: "2001",
|
||||
AnswerTime: "*now",
|
||||
Usage: "1",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err == nil ||
|
||||
err.Error() != "SERVER_ERROR: UNAUTHORIZED_DESTINATION" {
|
||||
t.Error("Unexpected nil error received: ", err)
|
||||
}
|
||||
// Per call charges
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "call",
|
||||
Subject: "RPF_SPECIAL_BLC",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "5m",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.1 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutAccounts(t *testing.T) {
|
||||
// make sure Account was created
|
||||
var acnt *engine.Account
|
||||
if err := tutRpc.Call(utils.ApierV2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"},
|
||||
&acnt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(acnt.BalanceMap) != 4 ||
|
||||
len(acnt.BalanceMap[utils.MONETARY]) != 1 ||
|
||||
acnt.BalanceMap[utils.MONETARY][0].Value != 10 ||
|
||||
len(acnt.BalanceMap[utils.VOICE]) != 2 ||
|
||||
len(acnt.BalanceMap[utils.SMS]) != 1 ||
|
||||
acnt.BalanceMap[utils.SMS][0].Value != 100 ||
|
||||
len(acnt.BalanceMap[utils.DATA]) != 1 ||
|
||||
acnt.BalanceMap[utils.DATA][0].Value != 1024 ||
|
||||
len(acnt.ActionTriggers) != 2 ||
|
||||
acnt.Disabled {
|
||||
t.Errorf("received account: %s", utils.ToIJSON(acnt))
|
||||
}
|
||||
// test ActionTriggers
|
||||
attrs := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001",
|
||||
BalanceId: utils.StringPointer(utils.MetaDefault),
|
||||
BalanceType: utils.MONETARY, Value: 101}
|
||||
var reply string
|
||||
if err := tutRpc.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.SetBalance: ", err.Error())
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"},
|
||||
&acnt); err != nil {
|
||||
t.Error(err)
|
||||
} else if !acnt.Disabled {
|
||||
t.Errorf("account: %s", utils.ToIJSON(acnt))
|
||||
}
|
||||
// enable the account again
|
||||
if err := tutRpc.Call(utils.ApierV2SetAccount,
|
||||
v2.AttrSetAccount{
|
||||
Tenant: "cgrates.org",
|
||||
Account: "1001",
|
||||
Disabled: utils.BoolPointer(false),
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"},
|
||||
&acnt); err != nil {
|
||||
t.Error(err)
|
||||
} else if acnt.Disabled {
|
||||
t.Errorf("account: %s", utils.ToIJSON(acnt))
|
||||
}
|
||||
}
|
||||
|
||||
func testTutStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(tutDelay); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "github.com/cgrates/cgrates/apier/v1"
|
||||
v2 "github.com/cgrates/cgrates/apier/v2"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
tutCfgPath string
|
||||
tutCfg *config.CGRConfig
|
||||
tutRpc *rpc.Client
|
||||
tutCfgDir string //run tests for specific configuration
|
||||
tutDelay int
|
||||
)
|
||||
|
||||
var sTutTests = []func(t *testing.T){
|
||||
testTutLoadConfig,
|
||||
testTutResetDB,
|
||||
testTutStartEngine,
|
||||
testTutRpcConn,
|
||||
testTutFromFolder,
|
||||
testTutGetCost,
|
||||
testTutAccounts,
|
||||
testTutStopEngine,
|
||||
}
|
||||
|
||||
//Test start here
|
||||
func TestTutorial2MySQL(t *testing.T) {
|
||||
tutCfgDir = "tutmysql2"
|
||||
for _, stest := range sTutTests {
|
||||
t.Run(tutCfgDir, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutorial2Mongo(t *testing.T) {
|
||||
tutCfgDir = "tutmongo2"
|
||||
for _, stest := range sTutTests {
|
||||
t.Run(tutCfgDir, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutLoadConfig(t *testing.T) {
|
||||
var err error
|
||||
tutCfgPath = path.Join(*dataDir, "conf", "samples", tutCfgDir)
|
||||
if tutCfg, err = config.NewCGRConfigFromPath(tutCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tutDelay = 2000
|
||||
}
|
||||
|
||||
func testTutResetDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := engine.InitStorDb(tutCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tutCfgPath, tutDelay); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutRpcConn(t *testing.T) {
|
||||
var err error
|
||||
if tutRpc, err = jsonrpc.Dial("tcp", tutCfg.ListenCfg().RPCJSONListen); err != nil {
|
||||
t.Fatal("could not connect to rater: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testTutFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{
|
||||
FolderPath: path.Join(*dataDir, "tariffplans", "tutorial2")}
|
||||
if err := tutRpc.Call(utils.ApierV1LoadTariffPlanFromFolder,
|
||||
attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func testTutGetCost(t *testing.T) {
|
||||
// Standard pricing for 1001->1002
|
||||
attrs := v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "45s",
|
||||
}
|
||||
var rply *engine.EventCost
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.550000 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Fallback pricing from *any, Usage will be rounded to 60s
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "2019-03-11T09:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 1.4 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Fallback pricing from *any, Usage will be rounded to 60s
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "2019-03-11T21:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
// *any to 2001
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1002",
|
||||
Destination: "2001",
|
||||
AnswerTime: "*now",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 1.4 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// *any to 2001 on NEW_YEAR
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1002",
|
||||
Destination: "2001",
|
||||
AnswerTime: "2020-01-01T21:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.55 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Fallback pricing from *any, Usage will be rounded to 60s
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "2019-03-11T21:00:00Z",
|
||||
Usage: "45s",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.55 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// Unauthorized destination
|
||||
attrs = v1.AttrGetCost{
|
||||
Subject: "1001",
|
||||
Destination: "4003",
|
||||
AnswerTime: "2019-03-11T09:00:00Z",
|
||||
Usage: "1m",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err == nil ||
|
||||
err.Error() != "SERVER_ERROR: UNAUTHORIZED_DESTINATION" {
|
||||
t.Error("Unexpected nil error received: ", err)
|
||||
}
|
||||
// Data charging
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "data",
|
||||
Subject: "1001",
|
||||
AnswerTime: "*now",
|
||||
Usage: "2048",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 2.0 { // FixMe: missing ConnectFee out of Cost
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// SMS charging 1002
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "sms",
|
||||
Subject: "1003",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "1",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.1 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// SMS charging 10
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "sms",
|
||||
Subject: "1001",
|
||||
Destination: "1003",
|
||||
AnswerTime: "*now",
|
||||
Usage: "1",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.2 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
// SMS charging UNAUTHORIZED
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "sms",
|
||||
Subject: "1001",
|
||||
Destination: "2001",
|
||||
AnswerTime: "*now",
|
||||
Usage: "1",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err == nil ||
|
||||
err.Error() != "SERVER_ERROR: UNAUTHORIZED_DESTINATION" {
|
||||
t.Error("Unexpected nil error received: ", err)
|
||||
}
|
||||
// Per call charges
|
||||
attrs = v1.AttrGetCost{
|
||||
Category: "call",
|
||||
Subject: "RPF_SPECIAL_BLC",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "5m",
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV1GetCost, attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.1 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutAccounts(t *testing.T) {
|
||||
// make sure Account was created
|
||||
var acnt *engine.Account
|
||||
if err := tutRpc.Call(utils.ApierV2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"},
|
||||
&acnt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(acnt.BalanceMap) != 4 ||
|
||||
len(acnt.BalanceMap[utils.MONETARY]) != 1 ||
|
||||
acnt.BalanceMap[utils.MONETARY][0].Value != 10 ||
|
||||
len(acnt.BalanceMap[utils.VOICE]) != 2 ||
|
||||
len(acnt.BalanceMap[utils.SMS]) != 1 ||
|
||||
acnt.BalanceMap[utils.SMS][0].Value != 100 ||
|
||||
len(acnt.BalanceMap[utils.DATA]) != 1 ||
|
||||
acnt.BalanceMap[utils.DATA][0].Value != 1024 ||
|
||||
len(acnt.ActionTriggers) != 2 ||
|
||||
acnt.Disabled {
|
||||
t.Errorf("received account: %s", utils.ToIJSON(acnt))
|
||||
}
|
||||
// test ActionTriggers
|
||||
attrs := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001",
|
||||
BalanceId: utils.StringPointer(utils.MetaDefault),
|
||||
BalanceType: utils.MONETARY, Value: 101}
|
||||
var reply string
|
||||
if err := tutRpc.Call(utils.ApierV1SetBalance, attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.SetBalance: ", err.Error())
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"},
|
||||
&acnt); err != nil {
|
||||
t.Error(err)
|
||||
} else if !acnt.Disabled {
|
||||
t.Errorf("account: %s", utils.ToIJSON(acnt))
|
||||
}
|
||||
// enable the account again
|
||||
if err := tutRpc.Call(utils.ApierV2SetAccount,
|
||||
v2.AttrSetAccount{
|
||||
Tenant: "cgrates.org",
|
||||
Account: "1001",
|
||||
Disabled: utils.BoolPointer(false),
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := tutRpc.Call(utils.ApierV2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"},
|
||||
&acnt); err != nil {
|
||||
t.Error(err)
|
||||
} else if acnt.Disabled {
|
||||
t.Errorf("account: %s", utils.ToIJSON(acnt))
|
||||
}
|
||||
}
|
||||
|
||||
func testTutStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(tutDelay); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,148 +1,148 @@
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
itTestMongoAtalas = flag.Bool("mongo_atlas", false, "Run the test with mongo atalas connection")
|
||||
tutorialCfgPath string
|
||||
tutorialCfg *config.CGRConfig
|
||||
tutorialRpc *rpc.Client
|
||||
tutorialConfDIR string //run tests for specific configuration
|
||||
tutorialDelay int
|
||||
)
|
||||
|
||||
var sTestsTutorials = []func(t *testing.T){
|
||||
testTutorialLoadConfig,
|
||||
testTutorialResetDB,
|
||||
testTutorialStartEngine,
|
||||
testTutorialRpcConn,
|
||||
testTutorialFromFolder,
|
||||
testTutorialGetCost,
|
||||
testTutorialStopEngine,
|
||||
}
|
||||
|
||||
//Test start here
|
||||
func TestTutorialMongoAtlas(t *testing.T) {
|
||||
if !*itTestMongoAtalas {
|
||||
return
|
||||
}
|
||||
tutorialConfDIR = "mongoatlas"
|
||||
for _, stest := range sTestsTutorials {
|
||||
t.Run(tutorialConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutorialMongo(t *testing.T) {
|
||||
tutorialConfDIR = "tutmongo"
|
||||
for _, stest := range sTestsTutorials {
|
||||
t.Run(tutorialConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutorialMySQL(t *testing.T) {
|
||||
tutorialConfDIR = "tutmysql"
|
||||
for _, stest := range sTestsTutorials {
|
||||
t.Run(tutorialConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialLoadConfig(t *testing.T) {
|
||||
var err error
|
||||
tutorialCfgPath = path.Join(*dataDir, "conf", "samples", tutorialConfDIR)
|
||||
if tutorialCfg, err = config.NewCGRConfigFromPath(tutorialCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
switch tutorialConfDIR {
|
||||
case "mongoatlas": // Mongo needs more time to reset db
|
||||
tutorialDelay = 4000
|
||||
default:
|
||||
tutorialDelay = 2000
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialResetDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutorialCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := engine.InitStorDb(tutorialCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tutorialCfgPath, tutorialDelay); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tutorialRpc, err = jsonrpc.Dial("tcp", tutorialCfg.ListenCfg().RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal("Could not connect to rater: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
if err := tutorialRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func testTutorialGetCost(t *testing.T) {
|
||||
attrs := v1.AttrGetCost{
|
||||
Tenant: "cgrates.org",
|
||||
Category: "call",
|
||||
Subject: "1001",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "2m10s",
|
||||
}
|
||||
var rply *engine.EventCost
|
||||
if err := tutorialRpc.Call("ApierV1.GetCost", attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.716900 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(tutorialDelay); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// +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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package general_tests
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
itTestMongoAtalas = flag.Bool("mongo_atlas", false, "Run the test with mongo atalas connection")
|
||||
tutorialCfgPath string
|
||||
tutorialCfg *config.CGRConfig
|
||||
tutorialRpc *rpc.Client
|
||||
tutorialConfDIR string //run tests for specific configuration
|
||||
tutorialDelay int
|
||||
|
||||
sTestsTutorials = []func(t *testing.T){
|
||||
testTutorialLoadConfig,
|
||||
testTutorialResetDB,
|
||||
testTutorialStartEngine,
|
||||
testTutorialRpcConn,
|
||||
testTutorialFromFolder,
|
||||
testTutorialGetCost,
|
||||
testTutorialStopEngine,
|
||||
}
|
||||
)
|
||||
|
||||
//Test start here
|
||||
func TestTutorialMongoAtlas(t *testing.T) {
|
||||
if !*itTestMongoAtalas {
|
||||
return
|
||||
}
|
||||
tutorialConfDIR = "mongoatlas"
|
||||
for _, stest := range sTestsTutorials {
|
||||
t.Run(tutorialConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutorialMongo(t *testing.T) {
|
||||
tutorialConfDIR = "tutmongo"
|
||||
for _, stest := range sTestsTutorials {
|
||||
t.Run(tutorialConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutorialMySQL(t *testing.T) {
|
||||
tutorialConfDIR = "tutmysql"
|
||||
for _, stest := range sTestsTutorials {
|
||||
t.Run(tutorialConfDIR, stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialLoadConfig(t *testing.T) {
|
||||
var err error
|
||||
tutorialCfgPath = path.Join(*dataDir, "conf", "samples", tutorialConfDIR)
|
||||
if tutorialCfg, err = config.NewCGRConfigFromPath(tutorialCfgPath); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
switch tutorialConfDIR {
|
||||
case "mongoatlas": // Mongo needs more time to reset db
|
||||
tutorialDelay = 4000
|
||||
default:
|
||||
tutorialDelay = 2000
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialResetDB(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutorialCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := engine.InitStorDb(tutorialCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tutorialCfgPath, tutorialDelay); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tutorialRpc, err = jsonrpc.Dial("tcp", tutorialCfg.ListenCfg().RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal("Could not connect to rater: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
if err := tutorialRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func testTutorialGetCost(t *testing.T) {
|
||||
attrs := v1.AttrGetCost{
|
||||
Tenant: "cgrates.org",
|
||||
Category: "call",
|
||||
Subject: "1001",
|
||||
Destination: "1002",
|
||||
AnswerTime: "*now",
|
||||
Usage: "2m10s",
|
||||
}
|
||||
var rply *engine.EventCost
|
||||
if err := tutorialRpc.Call("ApierV1.GetCost", attrs, &rply); err != nil {
|
||||
t.Error("Unexpected nil error received: ", err.Error())
|
||||
} else if *rply.Cost != 0.716900 {
|
||||
t.Errorf("Unexpected cost received: %f", *rply.Cost)
|
||||
}
|
||||
}
|
||||
|
||||
func testTutorialStopEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(tutorialDelay); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user