//go:build integration // +build integration /* Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments Copyright (C) ITsysCOM GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see */ package dispatchers import ( "testing" "time" "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" ) var ( sTestsDspCDRs = []func(t *testing.T){ testDspCDRsPing, testDspCDRsProcessEvent, testDspCDRsCountCDR, testDspCDRsGetCDR, testDspCDRsGetCDRWithoutTenant, testDspCDRsProcessCDR, testDspCDRsGetCDR2, testDspCDRsProcessExternalCDR, testDspCDRsGetCDR3, testDspCDRsV2ProcessEvent, testDspCDRsV2StoreSessionCost, } sTestsDspCDRsWithoutAuth = []func(t *testing.T){ testDspCDRsPingNoAuth, testDspCDRsProcessEventNoAuth, testDspCDRsCountCDRNoAuth, testDspCDRsGetCDRNoAuth, testDspCDRsGetCDRNoAuthWithoutTenant, testDspCDRsProcessCDRNoAuth, testDspCDRsGetCDR2NoAuth, testDspCDRsProcessExternalCDRNoAuth, testDspCDRsGetCDR3NoAuth, testDspCDRsV2ProcessEventNoAuth, testDspCDRsV2StoreSessionCostNoAuth, } ) // Test start here func TestDspCDRsIT(t *testing.T) { var config1, config2, config3 string switch *utils.DBType { case utils.MetaInternal: t.SkipNow() case utils.MetaMySQL: config1 = "all_mysql" config2 = "all2_mysql" config3 = "dispatchers_mysql" case utils.MetaMongo: config1 = "all_mongo" config2 = "all2_mongo" config3 = "dispatchers_mongo" case utils.MetaPostgres: t.SkipNow() default: t.Fatal("Unknown Database type") } dispDIR := "dispatchers" if *utils.Encoding == utils.MetaGOB { dispDIR += "_gob" } testDsp(t, sTestsDspCDRs, "TestDspCDRs", config1, config2, config3, "tutorial", "oldtutorial", dispDIR) } func TestDspCDRsITMySQLWithoutAuth(t *testing.T) { if *utils.DBType != utils.MetaMySQL { t.SkipNow() } if *utils.Encoding == utils.MetaGOB { testDsp(t, sTestsDspCDRsWithoutAuth, "TestDspCDRsWithoutAuth", "all_mysql", "all2_mysql", "dispatchers_no_attributes", "tutorial", "oldtutorial", "dispatchers_gob") } else { testDsp(t, sTestsDspCDRsWithoutAuth, "TestDspCDRsWithoutAuth", "all_mysql", "all2_mysql", "dispatchers_no_attributes", "tutorial", "oldtutorial", "dispatchers") } } func testDspCDRsPing(t *testing.T) { var reply string if err := allEngine.RPC.Call(context.Background(), utils.CDRsV1Ping, new(utils.CGREvent), &reply); err != nil { t.Error(err) } else if reply != utils.Pong { t.Errorf("Received: %s", reply) } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1Ping, &utils.CGREvent{ Tenant: "cgrates.org", APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, }, &reply); err != nil { t.Error(err) } else if reply != utils.Pong { t.Errorf("Received: %s", reply) } } func testDspCDRsProcessEvent(t *testing.T) { var reply string args := &engine.ArgV1ProcessEvent{ CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]any{ utils.OriginID: "testDspCDRsProcessEvent", utils.OriginHost: "192.168.1.1", utils.Source: "testDspCDRsProcessEvent", utils.RequestType: utils.MetaRated, utils.AccountField: "1001", utils.Subject: "1001", utils.Destination: "1002", utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), utils.Usage: time.Minute, "field_extr1": "val_extr1", "fieldextr2": "valextr2", }, APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1ProcessEvent, args, &reply); err != nil { t.Error(err) } else if reply != utils.OK { t.Errorf("Received: %s", reply) } } func testDspCDRsCountCDR(t *testing.T) { var reply int64 args := &utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, }, Tenant: "cgrates.org", APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRsCount, args, &reply); err != nil { t.Error(err) } else if reply != 1 { t.Errorf("Received: %+v", reply) } } func testDspCDRsGetCDR(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, }, Tenant: "cgrates.org", APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "9ee4c71fcd67eef5fb25a4bb3f190487de3073f5" { t.Errorf("Expected: 9ee4c71fcd67eef5fb25a4bb3f190487de3073f5 , received:%v", reply[0].CGRID) } } func testDspCDRsGetCDRWithoutTenant(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, }, APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "9ee4c71fcd67eef5fb25a4bb3f190487de3073f5" { t.Errorf("Expected: 9ee4c71fcd67eef5fb25a4bb3f190487de3073f5 , received:%v", reply[0].CGRID) } } func testDspCDRsProcessCDR(t *testing.T) { var reply string args := &engine.CDRWithAPIOpts{ CDR: &engine.CDR{ Tenant: "cgrates.org", OriginID: "testDspCDRsProcessCDR", OriginHost: "192.168.1.1", Source: "testDspCDRsProcessCDR", RequestType: utils.MetaRated, Account: "1001", Subject: "1001", Destination: "1002", AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), Usage: 2 * time.Minute, }, APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1ProcessCDR, args, &reply); err != nil { t.Error(err) } else if reply != utils.OK { t.Errorf("Received: %s", reply) } } func testDspCDRsGetCDR2(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, OriginIDs: []string{"testDspCDRsProcessCDR"}, }, Tenant: "cgrates.org", APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "f08dfd32930b6bea326bb8ec4e38ab03d781c0bf" { t.Errorf("Expected: f08dfd32930b6bea326bb8ec4e38ab03d781c0bf , received:%v", reply[0].CGRID) } } func testDspCDRsProcessExternalCDR(t *testing.T) { var reply string args := &engine.ExternalCDRWithAPIOpts{ ExternalCDR: &engine.ExternalCDR{ ToR: utils.MetaVoice, OriginID: "testDspCDRsProcessExternalCDR", OriginHost: "127.0.0.1", Source: utils.UnitTest, RequestType: utils.MetaRated, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", Usage: "1s", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, }, APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1ProcessExternalCDR, args, &reply); err != nil { t.Error(err) } else if reply != utils.OK { t.Errorf("Received: %s", reply) } } func testDspCDRsGetCDR3(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1003"}, RunIDs: []string{utils.MetaDefault}, OriginIDs: []string{"testDspCDRsProcessExternalCDR"}, }, Tenant: "cgrates.org", APIOpts: map[string]any{ utils.OptsAPIKey: "cdrs12345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "8ae63781b39f3265d014d2ba6a70437172fba46d" { t.Errorf("Expected: 8ae63781b39f3265d014d2ba6a70437172fba46d , received:%v", reply[0].CGRID) } } func testDspCDRsV2ProcessEvent(t *testing.T) { var reply []*utils.EventWithFlags args := &engine.ArgV1ProcessEvent{ Flags: []string{utils.MetaRALs}, CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]any{ utils.OriginID: "testDspCDRsV2ProcessEvent", utils.OriginHost: "192.168.1.1", utils.Source: "testDspCDRsV2ProcessEvent", utils.RequestType: utils.MetaRated, utils.AccountField: "1001", utils.Subject: "1001", utils.Destination: "1002", utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), utils.Usage: time.Minute, }, APIOpts: map[string]any{ utils.OptsAPIKey: "cdrsv212345", }, }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV2ProcessEvent, args, &reply); err != nil { t.Error(err) } else if len(reply) != 2 { for _, procEv := range reply { if procEv.Event[utils.RequestType] == utils.MetaRated && procEv.Event[utils.Cost] != 0.6 { t.Errorf("Expected: %+v , received: %v", 0.6, procEv.Event[utils.Cost]) } } } } func testDspCDRsV2StoreSessionCost(t *testing.T) { var reply string cc := &engine.CallCost{ Category: "generic", Tenant: "cgrates.org", Subject: "1001", Account: "1001", Destination: "data", ToR: "*data", Cost: 0, } args := &engine.ArgsV2CDRSStoreSMCost{ CheckDuplicate: true, Cost: &engine.V2SMCost{ CGRID: "testDspCDRsV2StoreSessionCost", RunID: utils.MetaDefault, OriginHost: "", OriginID: "testdatagrp_grp1", CostSource: "SMR", Usage: 1536, CostDetails: engine.NewEventCostFromCallCost(cc, "testDspCDRsV2StoreSessionCost", utils.MetaDefault), }, APIOpts: map[string]any{ utils.OptsAPIKey: "cdrsv212345", }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV2StoreSessionCost, args, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } time.Sleep(150 * time.Millisecond) if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV2StoreSessionCost, args, &reply); err == nil || err.Error() != "SERVER_ERROR: EXISTS" { t.Error("Unexpected error: ", err) } } func testDspCDRsPingNoAuth(t *testing.T) { var reply string if err := allEngine.RPC.Call(context.Background(), utils.CDRsV1Ping, new(utils.CGREvent), &reply); err != nil { t.Error(err) } else if reply != utils.Pong { t.Errorf("Received: %s", reply) } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1Ping, &utils.CGREvent{ Tenant: "cgrates.org", }, &reply); err != nil { t.Error(err) } else if reply != utils.Pong { t.Errorf("Received: %s", reply) } } func testDspCDRsProcessEventNoAuth(t *testing.T) { var reply string args := &engine.ArgV1ProcessEvent{ CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]any{ utils.OriginID: "testDspCDRsProcessEvent", utils.OriginHost: "192.168.1.1", utils.Source: "testDspCDRsProcessEvent", utils.RequestType: utils.MetaRated, utils.AccountField: "1001", utils.Subject: "1001", utils.Destination: "1002", utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), utils.Usage: time.Minute, "field_extr1": "val_extr1", "fieldextr2": "valextr2", }, }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1ProcessEvent, args, &reply); err != nil { t.Error(err) } else if reply != utils.OK { t.Errorf("Received: %s", reply) } } func testDspCDRsCountCDRNoAuth(t *testing.T) { var reply int64 args := &utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, }, Tenant: "cgrates.org", } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRsCount, args, &reply); err != nil { t.Error(err) } else if reply != 1 { t.Errorf("Received: %+v", reply) } } func testDspCDRsGetCDRNoAuth(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, }, Tenant: "cgrates.org", } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "9ee4c71fcd67eef5fb25a4bb3f190487de3073f5" { t.Errorf("Expected: 9ee4c71fcd67eef5fb25a4bb3f190487de3073f5 , received:%v", reply[0].CGRID) } } func testDspCDRsGetCDRNoAuthWithoutTenant(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "9ee4c71fcd67eef5fb25a4bb3f190487de3073f5" { t.Errorf("Expected: 9ee4c71fcd67eef5fb25a4bb3f190487de3073f5 , received:%v", reply[0].CGRID) } } func testDspCDRsProcessCDRNoAuth(t *testing.T) { var reply string args := &engine.CDRWithAPIOpts{ CDR: &engine.CDR{ Tenant: "cgrates.org", OriginID: "testDspCDRsProcessCDR", OriginHost: "192.168.1.1", Source: "testDspCDRsProcessCDR", RequestType: utils.MetaRated, Account: "1001", Subject: "1001", Destination: "1002", AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), Usage: 2 * time.Minute, }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1ProcessCDR, args, &reply); err != nil { t.Error(err) } else if reply != utils.OK { t.Errorf("Received: %s", reply) } } func testDspCDRsGetCDR2NoAuth(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1001"}, RunIDs: []string{utils.MetaDefault}, OriginIDs: []string{"testDspCDRsProcessCDR"}, }, Tenant: "cgrates.org", } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "f08dfd32930b6bea326bb8ec4e38ab03d781c0bf" { t.Errorf("Expected: f08dfd32930b6bea326bb8ec4e38ab03d781c0bf , received:%v", reply[0].CGRID) } } func testDspCDRsProcessExternalCDRNoAuth(t *testing.T) { var reply string args := &engine.ExternalCDRWithAPIOpts{ ExternalCDR: &engine.ExternalCDR{ ToR: utils.MetaVoice, OriginID: "testDspCDRsProcessExternalCDR", OriginHost: "127.0.0.1", Source: utils.UnitTest, RequestType: utils.MetaRated, Tenant: "cgrates.org", Category: "call", Account: "1003", Subject: "1003", Destination: "1001", SetupTime: "2014-08-04T13:00:00Z", AnswerTime: "2014-08-04T13:00:07Z", Usage: "1s", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1ProcessExternalCDR, args, &reply); err != nil { t.Error(err) } else if reply != utils.OK { t.Errorf("Received: %s", reply) } } func testDspCDRsGetCDR3NoAuth(t *testing.T) { var reply []*engine.CDR args := utils.RPCCDRsFilterWithAPIOpts{ RPCCDRsFilter: &utils.RPCCDRsFilter{ Accounts: []string{"1003"}, RunIDs: []string{utils.MetaDefault}, OriginIDs: []string{"testDspCDRsProcessExternalCDR"}, }, Tenant: "cgrates.org", } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV1GetCDRs, &args, &reply); err != nil { t.Error(err) } else if len(reply) != 1 { t.Errorf("Received: %+v", reply) } else if reply[0].CGRID != "8ae63781b39f3265d014d2ba6a70437172fba46d" { t.Errorf("Expected: 8ae63781b39f3265d014d2ba6a70437172fba46d , received:%v", reply[0].CGRID) } } func testDspCDRsV2ProcessEventNoAuth(t *testing.T) { var reply []*utils.EventWithFlags args := &engine.ArgV1ProcessEvent{ Flags: []string{utils.MetaRALs}, CGREvent: utils.CGREvent{ Tenant: "cgrates.org", Event: map[string]any{ utils.OriginID: "testDspCDRsV2ProcessEventNoAuth", utils.OriginHost: "192.168.1.1", utils.Source: "testDspCDRsV2ProcessEventNoAuth", utils.RequestType: utils.MetaRated, utils.AccountField: "1001", utils.Subject: "1001", utils.Destination: "1002", utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), utils.Usage: time.Minute, }, }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV2ProcessEvent, args, &reply); err != nil { t.Error(err) } else if len(reply) != 2 { for _, procEv := range reply { if procEv.Event[utils.RequestType] == utils.MetaRated && procEv.Event[utils.Cost] != 0.6 { t.Errorf("Expected: %+v , received: %v", 0.6, procEv.Event[utils.Cost]) } } } } func testDspCDRsV2StoreSessionCostNoAuth(t *testing.T) { var reply string cc := &engine.CallCost{ Category: "generic", Tenant: "cgrates.org", Subject: "1001", Account: "1001", Destination: "data", ToR: "*data", Cost: 0, } args := &engine.ArgsV2CDRSStoreSMCost{ CheckDuplicate: true, Cost: &engine.V2SMCost{ CGRID: "testDspCDRsV2StoreSessionCostNoAuth", RunID: utils.MetaDefault, OriginHost: "", OriginID: "testdatagrp_grp1", CostSource: "SMR", Usage: 1536, CostDetails: engine.NewEventCostFromCallCost(cc, "testDspCDRsV2StoreSessionCostNoAuth", utils.MetaDefault), }, } if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV2StoreSessionCost, args, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } time.Sleep(150 * time.Millisecond) if err := dispEngine.RPC.Call(context.Background(), utils.CDRsV2StoreSessionCost, args, &reply); err == nil || err.Error() != "SERVER_ERROR: EXISTS" { t.Error("Unexpected error: ", err) } }