diff --git a/console/cdrs.go b/console/cdrs.go
deleted file mode 100644
index 09dc56709..000000000
--- a/console/cdrs.go
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package console
-
-import (
- "github.com/cgrates/cgrates/engine"
- "github.com/cgrates/cgrates/utils"
-)
-
-func init() {
- c := &CmdGetCDRs{
- name: "cdrs",
- rpcMethod: utils.CDRsV1GetCDRs,
- }
- commands[c.Name()] = c
- c.CommandExecuter = &CommandExecuter{c}
-}
-
-// Commander implementation
-type CmdGetCDRs struct {
- name string
- rpcMethod string
- rpcParams *utils.RPCCDRsFilterWithAPIOpts
- *CommandExecuter
-}
-
-func (self *CmdGetCDRs) Name() string {
- return self.name
-}
-
-func (self *CmdGetCDRs) RpcMethod() string {
- return self.rpcMethod
-}
-
-func (self *CmdGetCDRs) RpcParams(reset bool) interface{} {
- if reset || self.rpcParams == nil {
- self.rpcParams = &utils.RPCCDRsFilterWithAPIOpts{
- RPCCDRsFilter: new(utils.RPCCDRsFilter),
- }
- }
- return self.rpcParams
-}
-
-func (self *CmdGetCDRs) PostprocessRpcParams() error {
- return nil
-}
-
-func (self *CmdGetCDRs) RpcResult() interface{} {
- a := make([]*engine.CDR, 0)
- return &a
-}
diff --git a/dispatchers/cdrs_it_test.go b/dispatchers/cdrs_it_test.go
deleted file mode 100644
index 71e93d47b..000000000
--- a/dispatchers/cdrs_it_test.go
+++ /dev/null
@@ -1,542 +0,0 @@
-//go:build integration
-// +build integration
-
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package dispatchers
-
-import (
- "testing"
- "time"
-
- "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 *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 *encoding == utils.MetaGOB {
- dispDIR += "_gob"
- }
- testDsp(t, sTestsDspCDRs, "TestDspCDRs", config1, config2, config3, "tutorial", "oldtutorial", dispDIR)
-}
-
-func TestDspCDRsITMySQLWithoutAuth(t *testing.T) {
- if *dbType != utils.MetaMySQL {
- t.SkipNow()
- }
- if *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(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(utils.CDRsV1Ping, &utils.CGREvent{
- Tenant: "cgrates.org",
- APIOpts: map[string]interface{}{
- 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 := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]interface{}{
- 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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- utils.OptsCDRsStore: true,
- },
- }
-
- if err := dispEngine.RPC.Call(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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- },
- }
-
- if err := dispEngine.RPC.Call(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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- },
- }
-
- if err := dispEngine.RPC.Call(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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- },
- }
-
- if err := dispEngine.RPC.Call(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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- },
- }
- if err := dispEngine.RPC.Call(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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- },
- }
-
- if err := dispEngine.RPC.Call(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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- },
- }
- if err := dispEngine.RPC.Call(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]interface{}{
- utils.OptsAPIKey: "cdrs12345",
- },
- }
-
- if err := dispEngine.RPC.Call(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 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]interface{}{
-// utils.OptsAPIKey: "cdrsv212345",
-// },
-// }
-
-// if err := dispEngine.RPC.Call(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(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(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(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 := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]interface{}{
- 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(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(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(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(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(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(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(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(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)
- }
-}
diff --git a/engine/cdr.go b/engine/cdr.go
deleted file mode 100644
index 879d5b6d3..000000000
--- a/engine/cdr.go
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package engine
-
-import (
- "encoding/json"
- "math"
- "strconv"
- "time"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/utils"
-)
-
-func NewCDRFromExternalCDR(extCdr *ExternalCDR, timezone string) (*CDR, error) {
- var err error
- cdr := &CDR{RunID: extCdr.RunID, OrderID: extCdr.OrderID, ToR: extCdr.ToR,
- OriginID: extCdr.OriginID, OriginHost: extCdr.OriginHost,
- Source: extCdr.Source, RequestType: extCdr.RequestType, Tenant: extCdr.Tenant, Category: extCdr.Category,
- Account: extCdr.Account, Subject: extCdr.Subject, Destination: extCdr.Destination,
- CostSource: extCdr.CostSource, Cost: extCdr.Cost, PreRated: extCdr.PreRated}
- if extCdr.SetupTime != "" {
- if cdr.SetupTime, err = utils.ParseTimeDetectLayout(extCdr.SetupTime, timezone); err != nil {
- return nil, err
- }
- }
- if extCdr.AnswerTime != "" {
- if cdr.AnswerTime, err = utils.ParseTimeDetectLayout(extCdr.AnswerTime, timezone); err != nil {
- return nil, err
- }
- }
- if extCdr.Usage != "" {
- if cdr.Usage, err = utils.ParseDurationWithNanosecs(extCdr.Usage); err != nil {
- return nil, err
- }
- }
- if extCdr.ExtraFields != nil {
- cdr.ExtraFields = make(map[string]string)
- }
- for k, v := range extCdr.ExtraFields {
- cdr.ExtraFields[k] = v
- }
- return cdr, nil
-}
-
-type CDR struct {
- RunID string
- OrderID int64 // Stor order id used as export order id
- OriginHost string // represents the IP address of the host generating the CDR (automatically populated by the server)
- Source string // formally identifies the source of the CDR (free form field)
- OriginID string // represents the unique accounting id given by the telecom switch generating the CDR
- ToR string // type of record, meta-field, should map to one of the TORs hardcoded inside the server <*voice|*data|*sms|*generic>
- RequestType string // matching the supported request types by the **CGRateS**, accepted values are hardcoded in the server .
- Tenant string // tenant whom this record belongs
- Category string // free-form filter for this record, matching the category defined in rating profiles.
- Account string // account id (accounting subsystem) the record should be attached to
- Subject string // rating subject (rating subsystem) this record should be attached to
- Destination string // destination to be charged
- SetupTime time.Time // set-up time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp.
- AnswerTime time.Time // answer time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp.
- Usage time.Duration // event usage information (eg: in case of tor=*voice this will represent the total duration of a call)
- ExtraFields map[string]string // Extra fields to be stored in CDR
- ExtraInfo string // Container for extra information related to this CDR, eg: populated with error reason in case of error on calculation
- Partial bool // Used for partial record processing by ERs
- PreRated bool // Mark the CDR as rated so we do not process it during rating
- CostSource string // The source of this cost
- Cost float64 //
-}
-
-// AddDefaults will add missing information based on other fields
-func (cdr *CDR) AddDefaults(cfg *config.CGRConfig) {
-
- if cdr.RunID == utils.EmptyString {
- cdr.RunID = utils.MetaDefault
- }
- if cdr.ToR == utils.EmptyString {
- cdr.ToR = utils.MetaVoice
- }
- if cdr.RequestType == utils.EmptyString {
- cdr.RequestType = cfg.GeneralCfg().DefaultReqType
- }
- if cdr.Tenant == utils.EmptyString {
- cdr.Tenant = cfg.GeneralCfg().DefaultTenant
- }
- if cdr.Category == utils.EmptyString {
- cdr.Category = cfg.GeneralCfg().DefaultCategory
- }
- if cdr.Subject == utils.EmptyString {
- cdr.Subject = cdr.Account
- }
-}
-
-// FormatCost formats the cost as string on export
-func (cdr *CDR) FormatCost(shiftDecimals, roundDecimals int) string {
- cost := cdr.Cost
- if shiftDecimals != 0 {
- cost = cost * math.Pow10(shiftDecimals)
- }
- return strconv.FormatFloat(cost, 'f', roundDecimals, 64)
-}
-
-// FieldAsString is used to retrieve fields as string, primary fields are const labeled
-func (cdr *CDR) FieldAsString(rsrPrs *config.RSRParser) (parsed string, err error) {
- parsed, err = rsrPrs.ParseDataProviderWithInterfaces(
- cdr.AsMapStorage())
- if err != nil {
- return
- }
- return
-}
-
-// FieldsAsString concatenates values of multiple fields defined in template, used eg in CDR templates
-func (cdr *CDR) FieldsAsString(rsrFlds config.RSRParsers) string {
- outVal, err := rsrFlds.ParseDataProvider(
- cdr.AsMapStorage())
- if err != nil {
- return ""
- }
- return outVal
-}
-
-func (cdr *CDR) Clone() *CDR {
- if cdr == nil {
- return nil
- }
- cln := &CDR{
- RunID: cdr.RunID,
- OrderID: cdr.OrderID,
- OriginHost: cdr.OriginHost,
- Source: cdr.Source,
- OriginID: cdr.OriginID,
- ToR: cdr.ToR,
- RequestType: cdr.RequestType,
- Tenant: cdr.Tenant,
- Category: cdr.Category,
- Account: cdr.Account,
- Subject: cdr.Subject,
- Destination: cdr.Destination,
- SetupTime: cdr.SetupTime,
- AnswerTime: cdr.AnswerTime,
- Usage: cdr.Usage,
- ExtraFields: cdr.ExtraFields,
- ExtraInfo: cdr.ExtraInfo,
- Partial: cdr.Partial,
- PreRated: cdr.PreRated,
- CostSource: cdr.CostSource,
- Cost: cdr.Cost,
- }
- if cdr.ExtraFields != nil {
- cln.ExtraFields = make(map[string]string, len(cdr.ExtraFields))
- for key, val := range cdr.ExtraFields {
- cln.ExtraFields[key] = val
- }
- }
-
- return cln
-}
-
-func (cdr *CDR) AsMapStorage() (mp utils.MapStorage) {
- mp = utils.MapStorage{
- utils.MetaReq: cdr.AsMapStringIface(),
- }
- return
-}
-
-func (cdr *CDR) AsMapStringIface() (mp map[string]interface{}) {
- mp = make(map[string]interface{})
- for fld, val := range cdr.ExtraFields {
- mp[fld] = val
- }
- mp[utils.RunID] = cdr.RunID
- mp[utils.OrderID] = cdr.OrderID
- mp[utils.OriginHost] = cdr.OriginHost
- mp[utils.Source] = cdr.Source
- mp[utils.OriginID] = cdr.OriginID
- mp[utils.ToR] = cdr.ToR
- mp[utils.RequestType] = cdr.RequestType
- mp[utils.Tenant] = cdr.Tenant
- mp[utils.Category] = cdr.Category
- mp[utils.AccountField] = cdr.Account
- mp[utils.Subject] = cdr.Subject
- mp[utils.Destination] = cdr.Destination
- mp[utils.SetupTime] = cdr.SetupTime
- mp[utils.AnswerTime] = cdr.AnswerTime
- mp[utils.Usage] = cdr.Usage
- mp[utils.ExtraInfo] = cdr.ExtraInfo
- mp[utils.Partial] = cdr.Partial
- mp[utils.PreRated] = cdr.PreRated
- mp[utils.CostSource] = cdr.CostSource
- mp[utils.Cost] = cdr.Cost
- return
-}
-
-func (cdr *CDR) AsExternalCDR() *ExternalCDR {
- var usageStr string
- switch cdr.ToR {
- case utils.MetaVoice: // usage as time
- usageStr = cdr.Usage.String()
- default: // usage as units
- usageStr = strconv.FormatInt(cdr.Usage.Nanoseconds(), 10)
- }
- return &ExternalCDR{
- RunID: cdr.RunID,
- OrderID: cdr.OrderID,
- OriginHost: cdr.OriginHost,
- Source: cdr.Source,
- OriginID: cdr.OriginID,
- ToR: cdr.ToR,
- RequestType: cdr.RequestType,
- Tenant: cdr.Tenant,
- Category: cdr.Category,
- Account: cdr.Account,
- Subject: cdr.Subject,
- Destination: cdr.Destination,
- SetupTime: cdr.SetupTime.Format(time.RFC3339),
- AnswerTime: cdr.AnswerTime.Format(time.RFC3339),
- Usage: usageStr,
- ExtraFields: cdr.ExtraFields,
- CostSource: cdr.CostSource,
- Cost: cdr.Cost,
- ExtraInfo: cdr.ExtraInfo,
- PreRated: cdr.PreRated,
- }
-}
-
-func (cdr *CDR) String() string {
- mrsh, _ := json.Marshal(cdr)
- return string(mrsh)
-}
-
-// AsCDRsql converts the CDR into the format used for SQL storage
-func (cdr *CDR) AsCDRsql() (cdrSQL *CDRsql) {
- cdrSQL = new(CDRsql)
- cdrSQL.RunID = cdr.RunID
- cdrSQL.OriginHost = cdr.OriginHost
- cdrSQL.Source = cdr.Source
- cdrSQL.OriginID = cdr.OriginID
- cdrSQL.TOR = cdr.ToR
- cdrSQL.RequestType = cdr.RequestType
- cdrSQL.Tenant = cdr.Tenant
- cdrSQL.Category = cdr.Category
- cdrSQL.Account = cdr.Account
- cdrSQL.Subject = cdr.Subject
- cdrSQL.Destination = cdr.Destination
- cdrSQL.SetupTime = cdr.SetupTime
- if !cdr.AnswerTime.IsZero() {
- cdrSQL.AnswerTime = utils.TimePointer(cdr.AnswerTime)
- }
- cdrSQL.Usage = cdr.Usage.Nanoseconds()
- cdrSQL.ExtraFields = utils.ToJSON(cdr.ExtraFields)
- cdrSQL.CostSource = cdr.CostSource
- cdrSQL.Cost = cdr.Cost
- cdrSQL.ExtraInfo = cdr.ExtraInfo
- cdrSQL.CreatedAt = time.Now()
- return
-}
-
-func (cdr *CDR) AsCGREvent() *utils.CGREvent {
- return &utils.CGREvent{
- Tenant: cdr.Tenant,
- ID: utils.UUIDSha1Prefix(),
- Event: cdr.AsMapStringIface(),
- APIOpts: map[string]interface{}{},
- }
-}
-
-// NewCDRFromSQL converts the CDRsql into CDR
-func NewCDRFromSQL(cdrSQL *CDRsql) (cdr *CDR, err error) {
- cdr = new(CDR)
- cdr.RunID = cdrSQL.RunID
- cdr.OriginHost = cdrSQL.OriginHost
- cdr.Source = cdrSQL.Source
- cdr.OriginID = cdrSQL.OriginID
- cdr.OrderID = cdrSQL.ID
- cdr.ToR = cdrSQL.TOR
- cdr.RequestType = cdrSQL.RequestType
- cdr.Tenant = cdrSQL.Tenant
- cdr.Category = cdrSQL.Category
- cdr.Account = cdrSQL.Account
- cdr.Subject = cdrSQL.Subject
- cdr.Destination = cdrSQL.Destination
- cdr.SetupTime = cdrSQL.SetupTime
- if cdrSQL.AnswerTime != nil {
- cdr.AnswerTime = *cdrSQL.AnswerTime
- }
- cdr.Usage = time.Duration(cdrSQL.Usage)
- cdr.CostSource = cdrSQL.CostSource
- cdr.Cost = cdrSQL.Cost
- cdr.ExtraInfo = cdrSQL.ExtraInfo
- if cdrSQL.ExtraFields != "" {
- if err = json.Unmarshal([]byte(cdrSQL.ExtraFields), &cdr.ExtraFields); err != nil {
- return nil, err
- }
- }
- return
-}
-
-type ExternalCDR struct {
- RunID string
- OrderID int64
- OriginHost string
- Source string
- OriginID string
- ToR string
- RequestType string
- Tenant string
- Category string
- Account string
- Subject string
- Destination string
- SetupTime string
- AnswerTime string
- Usage string
- ExtraFields map[string]string
- CostSource string
- Cost float64
- CostDetails string
- ExtraInfo string
- PreRated bool // Mark the CDR as rated so we do not process it during mediation
-}
-
-// UsageRecord is used when authorizing requests from outside, eg APIerSv1.GetMaxUsage
-type UsageRecord struct {
- ToR string
- RequestType string
- Tenant string
- Category string
- Account string
- Subject string
- Destination string
- SetupTime string
- AnswerTime string
- Usage string
- ExtraFields map[string]string
-}
-
-func (uR *UsageRecord) GetID() string {
- return utils.Sha1(uR.ToR, uR.RequestType, uR.Tenant, uR.Category, uR.Account, uR.Subject, uR.Destination, uR.SetupTime, uR.AnswerTime, uR.Usage)
-}
-
-type ExternalCDRWithAPIOpts struct {
- *ExternalCDR
- APIOpts map[string]interface{}
-}
-
-type UsageRecordWithAPIOpts struct {
- *UsageRecord
- APIOpts map[string]interface{}
-}
-
-type CDRWithAPIOpts struct {
- *CDR
- APIOpts map[string]interface{}
-}
diff --git a/engine/cdr_test.go b/engine/cdr_test.go
deleted file mode 100644
index 3612c8c46..000000000
--- a/engine/cdr_test.go
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-package engine
-
-import (
- "encoding/json"
- "reflect"
- "testing"
- "time"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/utils"
-)
-
-func TestNewCDRFromExternalCDR(t *testing.T) {
- extCdr := &ExternalCDR{
- // CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()),
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", RunID: utils.MetaDefault,
- Usage: "10", Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- eStorCdr := &CDR{
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated, RunID: utils.MetaDefault,
- Tenant: "cgrates.org", Category: "call", Account: "1001",
- Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- Usage: 10, Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- if CDR, err := NewCDRFromExternalCDR(extCdr, ""); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eStorCdr, CDR) {
- t.Errorf("Expected: %+v, received: %+v", eStorCdr, CDR)
- }
-}
-
-func TestCDRClone(t *testing.T) {
- storCdr := &CDR{
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated, Tenant: "cgrates.org",
- Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault, Usage: 10,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- Cost: 1.01, PreRated: true,
- }
- if clnStorCdr := storCdr.Clone(); !reflect.DeepEqual(storCdr, clnStorCdr) {
- t.Errorf("Expecting: %+v, received: %+v", storCdr, clnStorCdr)
- }
-}
-
-func TestFieldsAsString(t *testing.T) {
- cdr := CDR{
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", Source: "test",
- RequestType: utils.MetaRated, Tenant: "cgrates.org",
- Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault, Usage: 10 * time.Second,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
- }
- eVal := "call_from_1001"
- if val := cdr.FieldsAsString(
- config.NewRSRParsersMustCompile("~*req.Category;_from_;~*req.Account", utils.InfieldSep)); val != eVal {
- t.Errorf("Expecting : %s, received: %q", eVal, val)
- }
-}
-
-func TestFormatCost(t *testing.T) {
- cdr := CDR{Cost: 1.01}
- if cdr.FormatCost(0, 4) != "1.0100" {
- t.Error("Unexpected format of the cost: ", cdr.FormatCost(0, 4))
- }
- cdr = CDR{Cost: 1.01001}
- if cdr.FormatCost(0, 4) != "1.0100" {
- t.Error("Unexpected format of the cost: ", cdr.FormatCost(0, 4))
- }
- if cdr.FormatCost(2, 0) != "101" {
- t.Error("Unexpected format of the cost: ", cdr.FormatCost(2, 0))
- }
- if cdr.FormatCost(1, 0) != "10" {
- t.Error("Unexpected format of the cost: ", cdr.FormatCost(1, 0))
- }
- if cdr.FormatCost(2, 3) != "101.001" {
- t.Error("Unexpected format of the cost: ", cdr.FormatCost(2, 3))
- }
-}
-
-func TestCDRAsMapStringIface(t *testing.T) {
- cdr := &CDR{
- OrderID: 123,
- ToR: utils.MetaVoice,
- OriginID: "dsafdsaf",
- OriginHost: "192.168.1.1",
- Source: utils.UnitTest,
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Category: "call",
- Account: "1002",
- Subject: "1001",
- Destination: "+4986517174963",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault,
- Usage: 10 * time.Second,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- Cost: 1.01,
- }
-
- mp := map[string]interface{}{
- "field_extr1": "val_extr1",
- "fieldextr2": "valextr2",
- utils.RunID: utils.MetaDefault,
- utils.OrderID: cdr.OrderID,
- utils.OriginHost: "192.168.1.1",
- utils.Source: utils.UnitTest,
- utils.OriginID: "dsafdsaf",
- utils.ToR: utils.MetaVoice,
- utils.RequestType: utils.MetaRated,
- utils.Tenant: "cgrates.org",
- utils.Category: "call",
- utils.AccountField: "1002",
- utils.Subject: "1001",
- utils.Destination: "+4986517174963",
- utils.SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- utils.AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- utils.Usage: 10 * time.Second,
- utils.CostSource: cdr.CostSource,
- utils.Cost: 1.01,
- utils.PreRated: false,
- utils.Partial: false,
- utils.ExtraInfo: cdr.ExtraInfo,
- }
- if cdrMp := cdr.AsMapStringIface(); !reflect.DeepEqual(mp, cdrMp) {
- t.Errorf("Expecting: %+v, received: %+v", mp, cdrMp)
- }
-}
-
-func TestCDRNewCDRFromSQL(t *testing.T) {
- extraFields := map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
- cdrSQL := &CDRsql{
- ID: 123,
- // Cgrid: "abecd993d06672714c4218a6dcf8278e0589a171",
- RunID: utils.MetaDefault,
- OriginID: "dsafdsaf",
- TOR: utils.MetaVoice,
- Source: utils.UnitTest,
- Tenant: "cgrates.org",
- Category: "call",
- Account: "1001",
- Subject: "1001",
- Destination: "+4986517174963",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: utils.TimePointer(time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC)),
- Usage: 10000000000,
- Cost: 1.01,
- RequestType: utils.MetaRated,
- OriginHost: "192.168.1.1",
- ExtraFields: utils.ToJSON(extraFields),
- }
-
- cdr := &CDR{
- OrderID: 123,
- ToR: utils.MetaVoice,
- OriginID: "dsafdsaf",
- OriginHost: "192.168.1.1",
- Source: utils.UnitTest,
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Category: "call",
- Account: "1001",
- Subject: "1001",
- Destination: "+4986517174963",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault,
- Usage: 10 * time.Second,
- Cost: 1.01,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
-
- if eCDR, err := NewCDRFromSQL(cdrSQL); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(cdr, eCDR) {
- t.Errorf("Expecting: %+v, received: %+v", cdr, eCDR)
- }
-
-}
-
-func TestCDRAsCGREvent(t *testing.T) {
- cdr := &CDR{
- OrderID: 123,
- ToR: utils.MetaVoice,
- OriginID: "dsafdsaf",
- OriginHost: "192.168.1.1",
- Source: utils.UnitTest,
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Category: "call",
- Account: "1001",
- Subject: "1001",
- Destination: "+4986517174963",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault,
- Usage: 10 * time.Second,
- Cost: 1.01,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- eCGREvent := utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "GenePreRated",
- Event: map[string]interface{}{
- "Account": "1001",
- "AnswerTime": time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- "Category": "call",
- "Cost": 1.01,
- "CostSource": "",
- "Destination": "+4986517174963",
- "ExtraInfo": "",
- "OrderID": int64(123),
- "OriginHost": "192.168.1.1",
- "OriginID": "dsafdsaf",
- "Partial": false,
- "RequestType": utils.MetaRated,
- "RunID": utils.MetaDefault,
- "SetupTime": time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- "Source": "UNIT_TEST",
- "Subject": "1001",
- "Tenant": "cgrates.org",
- "ToR": "*voice",
- "Usage": 10 * time.Second,
- "field_extr1": "val_extr1",
- "fieldextr2": "valextr2",
- "PreRated": false,
- },
- }
- cgrEvent := cdr.AsCGREvent()
- if !reflect.DeepEqual(eCGREvent.Tenant, cgrEvent.Tenant) {
- t.Errorf("Expecting: %+v, received: %+v", eCGREvent.Tenant, cgrEvent.Tenant)
- }
- for fldName, fldVal := range eCGREvent.Event {
- if _, has := cgrEvent.Event[fldName]; !has {
- t.Errorf("Expecting: %+v, received: %+v", fldName, nil)
- } else if fldVal != cgrEvent.Event[fldName] {
- t.Errorf("Expecting: %s:%+v, received: %s:%+v",
- fldName, eCGREvent.Event[fldName], fldName, cgrEvent.Event[fldName])
- }
- }
-}
-
-func TestCDRAddDefaults(t *testing.T) {
- cdr := &CDR{
- OriginID: "dsafdsaf",
- OriginHost: "192.168.1.2",
- Account: "1001",
- }
- cfg := config.NewDefaultCGRConfig()
-
- eCDR := &CDR{
- ToR: utils.MetaVoice,
- RunID: utils.MetaDefault,
- Subject: "1001",
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Category: utils.Call,
- OriginID: "dsafdsaf",
- OriginHost: "192.168.1.2",
- Account: "1001",
- }
- cdr.AddDefaults(cfg)
- if !reflect.DeepEqual(cdr, eCDR) {
- t.Errorf("Expecting: %+v, received: %+v", eCDR, cdr)
- }
-}
-
-func TestNewCDRFromExternalCDRSetupTimeError(t *testing.T) {
- extCdr := &ExternalCDR{
- // CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()),
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: "*testTime", AnswerTime: "2013-11-07T08:42:26Z", RunID: utils.MetaDefault,
- Usage: "10", Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- _, err := NewCDRFromExternalCDR(extCdr, "")
- if err == nil || err.Error() != "Unsupported time format" {
- t.Error(err)
- }
-}
-
-func TestNewCDRFromExternalCDRAnswerTimeError(t *testing.T) {
- extCdr := &ExternalCDR{
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", AnswerTime: "*testTime", RunID: utils.MetaDefault,
- Usage: "10", Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- _, err := NewCDRFromExternalCDR(extCdr, "")
- if err == nil || err.Error() != "Unsupported time format" {
- t.Error(err)
- }
-}
-
-func TestNewCDRFromExternalCDRUsageError(t *testing.T) {
- extCdr := &ExternalCDR{
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", RunID: utils.MetaDefault,
- Usage: "testUsage", Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- _, err := NewCDRFromExternalCDR(extCdr, "")
- if err == nil || err.Error() != `time: invalid duration "testUsage"` {
- t.Error(err)
- }
-}
-
-func TestCDRCloneNilCDR(t *testing.T) {
- var storCdr *CDR
- if clnStorCdr := storCdr.Clone(); !reflect.DeepEqual(storCdr, clnStorCdr) {
- t.Errorf("\nExpecting: %+v, \nreceived: %+v", storCdr, clnStorCdr)
- }
-}
-
-func TestAsExternalCDR(t *testing.T) {
- extCdr := &ExternalCDR{
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", RunID: utils.MetaDefault,
- Usage: "10ns", Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- eStorCdr := &CDR{
- OrderID: 123, ToR: utils.MetaVoice, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated, RunID: utils.MetaDefault,
- Tenant: "cgrates.org", Category: "call", Account: "1001",
- Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- Usage: 10, Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- if eCDR := eStorCdr.AsExternalCDR(); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(extCdr, eCDR) {
- t.Errorf("\nExpected: %+v, \nreceived: %+v", utils.ToJSON(extCdr), utils.ToJSON(eCDR))
- }
-}
-
-func TestAsExternalCDRDefaultTOR(t *testing.T) {
- extCdr := &ExternalCDR{
- OrderID: 123, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
- SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", RunID: utils.MetaDefault,
- Usage: "10", Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- eStorCdr := &CDR{
- OrderID: 123, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated, RunID: utils.MetaDefault,
- Tenant: "cgrates.org", Category: "call", Account: "1001",
- Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- Usage: 10, Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- if eCDR := eStorCdr.AsExternalCDR(); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(extCdr, eCDR) {
- t.Errorf("\nExpected: %+v, \nreceived: %+v", utils.ToJSON(extCdr), utils.ToJSON(eCDR))
- }
-}
-
-func TestCDRString(t *testing.T) {
- testCdr := &CDR{
- OrderID: 123, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated, RunID: utils.MetaDefault,
- Tenant: "cgrates.org", Category: "call", Account: "1001",
- Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- Usage: 10, Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
- mrsh, _ := json.Marshal(testCdr)
- expected := string(mrsh)
- result := testCdr.String()
- if !reflect.DeepEqual(result, expected) {
- t.Errorf("\nExpected <%+v>, \nreceived <%+v>", expected, result)
- }
-}
-func TestCDRAsCDRsql(t *testing.T) {
- cdr := &CDR{
- OrderID: 123, OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated, RunID: utils.MetaDefault,
- Tenant: "cgrates.org", Category: "call", Account: "1001",
- Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- Usage: 10, Cost: 1.01, PreRated: true,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- }
-
- cdrSQL := new(CDRsql)
- cdrSQL.RunID = cdr.RunID
- cdrSQL.OriginHost = cdr.OriginHost
- cdrSQL.Source = cdr.Source
- cdrSQL.OriginID = cdr.OriginID
- cdrSQL.TOR = cdr.ToR
- cdrSQL.RequestType = cdr.RequestType
- cdrSQL.Tenant = cdr.Tenant
- cdrSQL.Category = cdr.Category
- cdrSQL.Account = cdr.Account
- cdrSQL.Subject = cdr.Subject
- cdrSQL.Destination = cdr.Destination
- cdrSQL.SetupTime = cdr.SetupTime
- if !cdr.AnswerTime.IsZero() {
- cdrSQL.AnswerTime = utils.TimePointer(cdr.AnswerTime)
- }
- cdrSQL.Usage = cdr.Usage.Nanoseconds()
- cdrSQL.ExtraFields = utils.ToJSON(cdr.ExtraFields)
- cdrSQL.CostSource = cdr.CostSource
- cdrSQL.Cost = cdr.Cost
- cdrSQL.ExtraInfo = cdr.ExtraInfo
-
- result := cdr.AsCDRsql()
- cdrSQL.CreatedAt = result.CreatedAt
- if !reflect.DeepEqual(result, cdrSQL) {
- t.Errorf("\nExpected <%+v>, \nreceived <%+v>", utils.ToJSON(cdrSQL), utils.ToJSON(result))
- }
-}
-
-func TestCDRGetID(t *testing.T) {
- uR := &UsageRecord{
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Category: "call",
- Account: "1001",
- Subject: "1001",
- Destination: "1002",
- Usage: "10",
- }
- result := uR.GetID()
- expected := utils.Sha1(uR.ToR, uR.RequestType, uR.Tenant, uR.Category, uR.Account, uR.Subject, uR.Destination, uR.SetupTime, uR.AnswerTime, uR.Usage)
- if !reflect.DeepEqual(result, expected) {
- t.Errorf("\nExpected <%+v>, \nreceived <%+v>", utils.ToJSON(expected), utils.ToJSON(result))
- }
-}
diff --git a/engine/fscdr.go b/engine/fscdr.go
deleted file mode 100644
index 43a03d5ac..000000000
--- a/engine/fscdr.go
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package engine
-
-import (
- "encoding/json"
- "io"
- "strconv"
- "strings"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/utils"
-)
-
-const (
- // Freswitch event property names
- fsCDRMap = "variables"
- fsUUID = "uuid" // -Unique ID for this call leg
- fsCallDestNR = "dialed_extension"
- fsParkTime = "start_epoch"
- fsSetupTime = "start_epoch"
- fsAnswerTime = "answer_epoch"
- fsHangupTime = "end_epoch"
- fsDuration = "billsec"
- fsUsernameVar = "user_name"
- fsCDRSource = "freeswitch_json"
- fsSIPReqUser = "sip_req_user" // Apps like FusionPBX do not set dialed_extension, alternative being destination_number but that comes in customer profile, not in vars
- fsProgressMediamsec = "progress_mediamsec"
- fsProgressMS = "progressmsec"
- fsUsername = "username"
- fsIPv4 = "FreeSWITCH-IPv4"
-)
-
-func NewFSCdr(body io.Reader, cgrCfg *config.CGRConfig) (*FSCdr, error) {
- fsCdr := &FSCdr{cgrCfg: cgrCfg, vars: make(map[string]string)}
- var err error
- if err = json.NewDecoder(body).Decode(&fsCdr.body); err != nil {
- return nil, err
- }
- if variables, ok := fsCdr.body[fsCDRMap]; ok {
- if variables, ok := variables.(map[string]interface{}); ok {
- for k, v := range variables {
- fsCdr.vars[k] = v.(string)
- }
- }
- }
- return fsCdr, nil
-}
-
-type FSCdr struct {
- cgrCfg *config.CGRConfig
- vars map[string]string
- body map[string]interface{} // keeps the loaded body for extra field search
-}
-
-func (fsCdr FSCdr) getOriginID() string {
- return utils.Sha1(fsCdr.vars[fsUUID],
- utils.FirstNonEmpty(fsCdr.vars[utils.CGROriginHost], fsCdr.vars[fsIPv4]))
-}
-
-func (fsCdr FSCdr) getExtraFields() map[string]string {
- extraFields := make(map[string]string, len(fsCdr.cgrCfg.CdrsCfg().ExtraFields))
- const dynprefix string = utils.MetaDynReq + utils.NestingSep
- for _, field := range fsCdr.cgrCfg.CdrsCfg().ExtraFields {
- if !strings.HasPrefix(field.Rules, dynprefix) {
- continue
- }
- attrName := field.AttrName()[5:]
- origFieldVal, foundInVars := fsCdr.vars[attrName]
- if !foundInVars {
- origFieldVal = fsCdr.searchExtraField(attrName, fsCdr.body)
- }
- if parsed, err := field.ParseValue(origFieldVal); err == nil {
- extraFields[attrName] = parsed
- }
- }
- return extraFields
-}
-
-func (fsCdr FSCdr) searchExtraField(field string, body map[string]interface{}) (result string) {
- for key, value := range body {
- if key == field {
- return utils.IfaceAsString(value)
- }
- switch v := value.(type) {
- case map[string]interface{}:
- if result = fsCdr.searchExtraField(field, v); len(result) != 0 {
- return
- }
- case []interface{}:
- for _, item := range v {
- if otherMap, ok := item.(map[string]interface{}); ok {
- if result = fsCdr.searchExtraField(field, otherMap); len(result) != 0 {
- return
- }
- }
- }
- }
- }
- return
-}
-
-// firstDefined will return first defined or search for dfltFld
-func (fsCdr FSCdr) firstDefined(fldNames []string, dfltFld string) (val string) {
- var has bool
- for _, fldName := range fldNames {
- if val, has = fsCdr.vars[fldName]; has {
- return
- }
- }
- return fsCdr.searchExtraField(dfltFld, fsCdr.body)
-}
-
-func (fsCdr FSCdr) AsCDR(timezone string) (storCdr *CDR, err error) {
- storCdr = &CDR{
- RunID: fsCdr.vars["cgr_runid"],
- OriginHost: utils.FirstNonEmpty(fsCdr.vars[utils.CGROriginHost], fsCdr.vars[fsIPv4]),
- Source: fsCDRSource,
- OriginID: fsCdr.vars[fsUUID],
- ToR: utils.MetaVoice,
- RequestType: utils.FirstNonEmpty(fsCdr.vars[utils.CGRReqType], fsCdr.cgrCfg.GeneralCfg().DefaultReqType),
- Tenant: utils.FirstNonEmpty(fsCdr.vars[utils.CGRTenant], fsCdr.cgrCfg.GeneralCfg().DefaultTenant),
- Category: utils.FirstNonEmpty(fsCdr.vars[utils.CGRCategory], fsCdr.cgrCfg.GeneralCfg().DefaultCategory),
- Account: fsCdr.firstDefined([]string{utils.CGRAccount, fsUsernameVar}, fsUsername),
- Subject: fsCdr.firstDefined([]string{utils.CGRSubject, utils.CGRAccount, fsUsernameVar}, fsUsername),
- Destination: utils.FirstNonEmpty(fsCdr.vars[utils.CGRDestination], fsCdr.vars[fsCallDestNR], fsCdr.vars[fsSIPReqUser]),
- ExtraFields: fsCdr.getExtraFields(),
- ExtraInfo: fsCdr.vars["cgr_extrainfo"],
- CostSource: fsCdr.vars["cgr_costsource"],
- Cost: -1,
- }
- if orderID, hasIt := fsCdr.vars["cgr_orderid"]; hasIt {
- if storCdr.OrderID, err = strconv.ParseInt(orderID, 10, 64); err != nil {
- return nil, err
- }
- }
- if setupTime, hasIt := fsCdr.vars[fsSetupTime]; hasIt {
- if storCdr.SetupTime, err = utils.ParseTimeDetectLayout(setupTime, timezone); err != nil {
- return nil, err
- } // Not interested to process errors, should do them if necessary in a previous step
- }
- if answerTime, hasIt := fsCdr.vars[fsAnswerTime]; hasIt {
- if storCdr.AnswerTime, err = utils.ParseTimeDetectLayout(answerTime, timezone); err != nil {
- return nil, err
- }
- }
- if usage, hasIt := fsCdr.vars[fsDuration]; hasIt {
- if storCdr.Usage, err = utils.ParseDurationWithSecs(usage); err != nil {
- return nil, err
- }
- }
- if partial, hasIt := fsCdr.vars["cgr_partial"]; hasIt {
- if storCdr.Partial, err = strconv.ParseBool(partial); err != nil {
- return nil, err
- }
- }
- if preRated, hasIt := fsCdr.vars["cgr_prerated"]; hasIt {
- if storCdr.PreRated, err = strconv.ParseBool(preRated); err != nil {
- return nil, err
- }
- }
- return
-}
diff --git a/engine/fscdr_test.go b/engine/fscdr_test.go
deleted file mode 100644
index d13aa0629..000000000
--- a/engine/fscdr_test.go
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-package engine
-
-import (
- "bytes"
- "reflect"
- "testing"
- "time"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/utils"
-)
-
-var body = []byte(`{
- "core-uuid": "eb8bcdd2-d9eb-4f8f-80c3-1a4042aabe31",
- "switchname": "FSDev1",
- "channel_data": {
- "state": "CS_REPORTING",
- "state_number": "11",
- "flags": "0=1;1=1;3=1;20=1;37=1;38=1;40=1;43=1;48=1;53=1;75=1;98=1;112=1;113=1;122=1;134=1",
- "caps": "1=1;2=1;3=1;4=1;5=1;6=1"
- },
- "callStats": {
- "audio": {
- "inbound": {
- "raw_bytes": 572588,
- "media_bytes": 572588,
- "packet_count": 3329,
- "media_packet_count": 3329,
- "skip_packet_count": 10,
- "jitter_packet_count": 0,
- "dtmf_packet_count": 0,
- "cng_packet_count": 0,
- "flush_packet_count": 0,
- "largest_jb_size": 0,
- "jitter_min_variance": 0,
- "jitter_max_variance": 0,
- "jitter_loss_rate": 0,
- "jitter_burst_rate": 0,
- "mean_interval": 0,
- "flaw_total": 0,
- "quality_percentage": 100,
- "mos": 4.500000
- },
- "outbound": {
- "raw_bytes": 0,
- "media_bytes": 0,
- "packet_count": 0,
- "media_packet_count": 0,
- "skip_packet_count": 0,
- "dtmf_packet_count": 0,
- "cng_packet_count": 0,
- "rtcp_packet_count": 0,
- "rtcp_octet_count": 0
- }
- }
- },
- "variables": {
- "uuid": "3da8bf84-c133-4959-9e24-e72875cb33a1",
- "session_id": "7",
- "sip_from_user": "1001",
- "sip_from_uri": "1001@10.10.10.204",
- "sip_from_host": "10.10.10.204",
- "channel_name": "sofia/internal/1001@10.10.10.204",
- "ep_codec_string": "CORE_PCM_MODULE.PCMU@8000h@20i@64000b,CORE_PCM_MODULE.PCMA@8000h@20i@64000b",
- "sip_local_network_addr": "10.10.10.204",
- "sip_network_ip": "10.10.10.100",
- "sip_network_port": "5060",
- "sip_invite_stamp": "1515666344534355",
- "sip_received_ip": "10.10.10.100",
- "sip_received_port": "5060",
- "sip_via_protocol": "udp",
- "sip_from_user_stripped": "1001",
- "sofia_profile_name": "internal",
- "recovery_profile_name": "internal",
- "sip_req_user": "1002",
- "sip_req_uri": "1002@10.10.10.204",
- "sip_req_host": "10.10.10.204",
- "sip_to_user": "1002",
- "sip_to_uri": "1002@10.10.10.204",
- "sip_to_host": "10.10.10.204",
- "sip_contact_params": "transport=udp;registering_acc=10_10_10_204",
- "sip_contact_user": "1001",
- "sip_contact_port": "5060",
- "sip_contact_uri": "1001@10.10.10.100:5060",
- "sip_contact_host": "10.10.10.100",
- "sip_user_agent": "Jitsi2.10.5550Linux",
- "sip_via_host": "10.10.10.100",
- "sip_via_port": "5060",
- "presence_id": "1001@10.10.10.204",
- "cgr_notify": "AUTH_OK",
- "max_forwards": "69",
- "transfer_history": "1515666344:b4300942-e809-4393-99cb-d39a1bc3c219:bl_xfer:1002/default/XML",
- "transfer_source": "1515666344:b4300942-e809-4393-99cb-d39a1bc3c219:bl_xfer:1002/default/XML",
- "DP_MATCH": "ARRAY::1002|:1002",
- "call_uuid": "3da8bf84-c133-4959-9e24-e72875cb33a1",
- "call_timeout": "30",
- "current_application_data": "user/1002@10.10.10.204",
- "current_application": "bridge",
- "dialed_user": "1002",
- "dialed_domain": "10.10.10.204",
- "originated_legs": "ARRAY::f52c26f1-b018-4963-bf6d-a3111d1a0320;Outbound Call;1002|:f52c26f1-b018-4963-bf6d-a3111d1a0320;Outbound Call;1002",
- "switch_m_sdp": "v=0\r\no=1002-jitsi.org 0 0 IN IP4 10.10.10.100\r\ns=-\r\nc=IN IP4 10.10.10.100\r\nt=0 0\r\nm=audio 5022 RTP/AVP 0 8 101\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:101 telephone-event/8000\r\n",
- "rtp_use_codec_name": "PCMU",
- "rtp_use_codec_rate": "8000",
- "rtp_use_codec_ptime": "20",
- "rtp_use_codec_channels": "1",
- "rtp_last_audio_codec_string": "PCMU@8000h@20i@1c",
- "read_codec": "PCMU",
- "original_read_codec": "PCMU",
- "read_rate": "8000",
- "original_read_rate": "8000",
- "write_codec": "PCMU",
- "write_rate": "8000",
- "video_possible": "true",
- "video_media_flow": "sendonly",
- "local_media_ip": "10.10.10.204",
- "local_media_port": "21566",
- "advertised_media_ip": "10.10.10.204",
- "rtp_use_timer_name": "soft",
- "rtp_use_pt": "0",
- "rtp_use_ssrc": "1448966920",
- "endpoint_disposition": "ANSWER",
- "originate_causes": "ARRAY::f52c26f1-b018-4963-bf6d-a3111d1a0320;NONE|:f52c26f1-b018-4963-bf6d-a3111d1a0320;NONE",
- "originate_disposition": "SUCCESS",
- "DIALSTATUS": "SUCCESS",
- "last_bridge_to": "f52c26f1-b018-4963-bf6d-a3111d1a0320",
- "bridge_channel": "sofia/internal/1002@10.10.10.100:5060",
- "bridge_uuid": "f52c26f1-b018-4963-bf6d-a3111d1a0320",
- "signal_bond": "f52c26f1-b018-4963-bf6d-a3111d1a0320",
- "last_sent_callee_id_name": "Outbound Call",
- "last_sent_callee_id_number": "1002",
- "switch_r_sdp": "v=0\r\no=1001-jitsi.org 0 1 IN IP4 10.10.10.100\r\ns=-\r\nc=IN IP4 10.10.10.100\r\nt=0 0\r\nm=audio 5018 RTP/AVP 96 97 98 9 100 102 0 8 103 3 104 101\r\na=rtpmap:96 opus/48000/2\r\na=fmtp:96 usedtx=1\r\na=rtpmap:97 SILK/24000\r\na=rtpmap:98 SILK/16000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:100 speex/32000\r\na=rtpmap:102 speex/16000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:103 iLBC/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:104 speex/8000\r\na=rtpmap:101 telephone-event/8000\r\na=sendonly\r\na=ptime:20\r\na=extmap:1 urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=rtcp-xr:voip-metrics\r\nm=video 0 RTP/AVP 105 99\r\n",
- "rtp_use_codec_string": "PCMU,PCMA",
- "audio_media_flow": "recvonly",
- "remote_media_ip": "10.10.10.100",
- "remote_media_port": "5018",
- "rtp_audio_recv_pt": "0",
- "dtmf_type": "rfc2833",
- "rtp_2833_send_payload": "101",
- "rtp_2833_recv_payload": "101",
- "rtp_local_sdp_str": "v=0\r\no=FreeSWITCH 1515644781 1515644783 IN IP4 10.10.10.204\r\ns=FreeSWITCH\r\nc=IN IP4 10.10.10.204\r\nt=0 0\r\nm=audio 21566 RTP/AVP 0 101\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-16\r\na=ptime:20\r\na=recvonly\r\n",
- "sip_to_tag": "m3g4NZ4rXFX3p",
- "sip_from_tag": "f25afe20",
- "sip_cseq": "2",
- "sip_call_id": "818e26f805701988c1a330175d7d2629@0:0:0:0:0:0:0:0",
- "sip_full_via": "SIP/2.0/UDP 10.10.10.100:5060;branch=z9hG4bK-313838-2ee350643dea826b4a74f8049852f307",
- "sip_from_display": "1001",
- "sip_full_from": "\"1001\" ;tag=f25afe20",
- "sip_full_to": ";tag=m3g4NZ4rXFX3p",
- "sip_hangup_phrase": "OK",
- "last_bridge_hangup_cause": "NORMAL_CLEARING",
- "last_bridge_proto_specific_hangup_cause": "sip:200",
- "bridge_hangup_cause": "NORMAL_CLEARING",
- "hangup_cause": "NORMAL_CLEARING",
- "hangup_cause_q850": "16",
- "digits_dialed": "none",
- "start_stamp": "2018-01-11 11:25:44",
- "profile_start_stamp": "2018-01-11 11:25:44",
- "answer_stamp": "2018-01-11 11:25:47",
- "bridge_stamp": "2018-01-11 11:25:47",
- "hold_stamp": "2018-01-11 11:25:48",
- "progress_stamp": "2018-01-11 11:25:44",
- "progress_media_stamp": "2018-01-11 11:25:47",
- "hold_events": "{{1515666348363496,1515666415502648}}",
- "end_stamp": "2018-01-11 11:26:55",
- "start_epoch": "1515666344",
- "start_uepoch": "1515666344534355",
- "profile_start_epoch": "1515666344",
- "profile_start_uepoch": "1515666344534355",
- "answer_epoch": "1515666347",
- "answer_uepoch": "1515666347954373",
- "bridge_epoch": "1515666347",
- "bridge_uepoch": "1515666347954373",
- "last_hold_epoch": "1515666348",
- "last_hold_uepoch": "1515666348363496",
- "hold_accum_seconds": "67",
- "hold_accum_usec": "67139151",
- "hold_accum_ms": "67139",
- "resurrect_epoch": "0",
- "resurrect_uepoch": "0",
- "progress_epoch": "1515666344",
- "progress_uepoch": "1515666344594267",
- "progress_media_epoch": "1515666347",
- "progress_media_uepoch": "1515666347954373",
- "end_epoch": "1515666415",
- "end_uepoch": "1515666415494269",
- "last_app": "bridge",
- "last_arg": "user/1002@10.10.10.204",
- "caller_id": "\"1001\" <1001>",
- "duration": "71",
- "billsec": "68",
- "progresssec": "0",
- "answersec": "3",
- "waitsec": "3",
- "progress_mediasec": "3",
- "flow_billsec": "71",
- "mduration": "70960",
- "billmsec": "67540",
- "progressmsec": "60",
- "answermsec": "3420",
- "waitmsec": "3420",
- "progress_mediamsec": "3420",
- "flow_billmsec": "70960",
- "uduration": "70959914",
- "billusec": "67539896",
- "progressusec": "59912",
- "answerusec": "3420018",
- "waitusec": "3420018",
- "progress_mediausec": "3420018",
- "flow_billusec": "70959914",
- "sip_hangup_disposition": "send_bye",
- "rtp_audio_in_raw_bytes": "572588",
- "rtp_audio_in_media_bytes": "572588",
- "rtp_audio_in_packet_count": "3329",
- "rtp_audio_in_media_packet_count": "3329",
- "rtp_audio_in_skip_packet_count": "10",
- "rtp_audio_in_jitter_packet_count": "0",
- "rtp_audio_in_dtmf_packet_count": "0",
- "rtp_audio_in_cng_packet_count": "0",
- "rtp_audio_in_flush_packet_count": "0",
- "rtp_audio_in_largest_jb_size": "0",
- "rtp_audio_in_jitter_min_variance": "0.00",
- "rtp_audio_in_jitter_max_variance": "0.00",
- "rtp_audio_in_jitter_loss_rate": "0.00",
- "rtp_audio_in_jitter_burst_rate": "0.00",
- "rtp_audio_in_mean_interval": "0.00",
- "rtp_audio_in_flaw_total": "0",
- "rtp_audio_in_quality_percentage": "100.00",
- "rtp_audio_in_mos": "4.50",
- "rtp_audio_out_raw_bytes": "0",
- "rtp_audio_out_media_bytes": "0",
- "rtp_audio_out_packet_count": "0",
- "rtp_audio_out_media_packet_count": "0",
- "rtp_audio_out_skip_packet_count": "0",
- "rtp_audio_out_dtmf_packet_count": "0",
- "rtp_audio_out_cng_packet_count": "0",
- "rtp_audio_rtcp_packet_count": "0",
- "rtp_audio_rtcp_octet_count": "0"
- },
- "app_log": {
- "applications": [{
- "app_name": "park",
- "app_data": "",
- "app_stamp": "1515666344548466"
- }, {
- "app_name": "set",
- "app_data": "ringback=",
- "app_stamp": "1515666344575066"
- }, {
- "app_name": "set",
- "app_data": "call_timeout=30",
- "app_stamp": "1515666344576009"
- }, {
- "app_name": "bridge",
- "app_data": "user/1002@10.10.10.204",
- "app_stamp": "1515666344576703"
- }]
- },
- "callflow": [{
- "dialplan": "XML",
- "profile_index": "2",
- "extension": {
- "name": "Local_Extension",
- "number": "1002",
- "applications": [{
- "app_name": "set",
- "app_data": "ringback=${us-ring}"
- }, {
- "app_name": "set",
- "app_data": "call_timeout=30"
- }, {
- "app_name": "bridge",
- "app_data": "user/${destination_number}@${domain_name}"
- }]
- },
- "caller_profile": {
- "username": "1001",
- "dialplan": "XML",
- "caller_id_name": "1001",
- "ani": "1001",
- "aniii": "",
- "caller_id_number": "1001",
- "network_addr": "10.10.10.100",
- "rdnis": "1002",
- "destination_number": "1002",
- "uuid": "3da8bf84-c133-4959-9e24-e72875cb33a1",
- "source": "mod_sofia",
- "context": "default",
- "chan_name": "sofia/internal/1001@10.10.10.204",
- "originatee": {
- "originatee_caller_profiles": [{
- "username": "1001",
- "dialplan": "XML",
- "caller_id_name": "1001",
- "ani": "1001",
- "aniii": "",
- "caller_id_number": "1001",
- "network_addr": "10.10.10.100",
- "rdnis": "1002",
- "destination_number": "1002",
- "uuid": "f52c26f1-b018-4963-bf6d-a3111d1a0320",
- "source": "mod_sofia",
- "context": "default",
- "chan_name": "sofia/internal/1002@10.10.10.100:5060"
- }, {
- "username": "1001",
- "dialplan": "XML",
- "caller_id_name": "1001",
- "ani": "1001",
- "aniii": "",
- "caller_id_number": "1001",
- "network_addr": "10.10.10.100",
- "rdnis": "1002",
- "destination_number": "1002",
- "uuid": "f52c26f1-b018-4963-bf6d-a3111d1a0320",
- "source": "mod_sofia",
- "context": "default",
- "chan_name": "sofia/internal/1002@10.10.10.100:5060"
- }]
- }
- },
- "times": {
- "created_time": "1515666344534355",
- "profile_created_time": "1515666344534355",
- "progress_time": "1515666344594267",
- "progress_media_time": "1515666347954373",
- "answered_time": "1515666347954373",
- "bridged_time": "1515666347954373",
- "last_hold_time": "1515666348363496",
- "hold_accum_time": "67139151",
- "hangup_time": "1515666415494269",
- "resurrect_time": "0",
- "transfer_time": "0"
- }
- }, {
- "dialplan": "XML",
- "profile_index": "1",
- "extension": {
- "name": "CGRateS_Auth",
- "number": "1002",
- "applications": [{
- "app_name": "park",
- "app_data": ""
- }]
- },
- "caller_profile": {
- "username": "1001",
- "dialplan": "XML",
- "caller_id_name": "1001",
- "ani": "1001",
- "aniii": "",
- "caller_id_number": "1001",
- "network_addr": "10.10.10.100",
- "rdnis": "",
- "destination_number": "1002",
- "uuid": "3da8bf84-c133-4959-9e24-e72875cb33a1",
- "source": "mod_sofia",
- "context": "default",
- "chan_name": "sofia/internal/1001@10.10.10.204"
- },
- "times": {
- "created_time": "1515666344534355",
- "profile_created_time": "1515666344534355",
- "progress_time": "0",
- "progress_media_time": "0",
- "answered_time": "0",
- "bridged_time": "0",
- "last_hold_time": "0",
- "hold_accum_time": "0",
- "hangup_time": "0",
- "resurrect_time": "0",
- "transfer_time": "1515666344534355"
- }
- }]
-}`)
-
-var fsCdrCfg *config.CGRConfig
-
-func TestFsCdrFirstNonEmpty(t *testing.T) {
- fsCdrCfg = config.NewDefaultCGRConfig()
- reader := bytes.NewReader(body)
- fsCdr, err := NewFSCdr(reader, fsCdrCfg)
- if err != nil {
- t.Errorf("Error loading cdr: %v", err)
- }
- //fsc := fsCdr.(FSCdr)
- if _, ok := fsCdr.vars["cgr_notify"]; !ok {
- t.Error("Error parsing cdr: ", fsCdr)
- }
-}
-
-func TestFsCdrCDRFields(t *testing.T) {
- fsCdrCfg.CdrsCfg().ExtraFields = config.NewRSRParsersMustCompile("~*req.sip_user_agent", utils.FieldsSep)
- reader := bytes.NewReader(body)
- fsCdr, err := NewFSCdr(reader, fsCdrCfg)
- if err != nil {
- t.Errorf("Error loading cdr: %v", err)
- }
- setupTime, _ := utils.ParseTimeDetectLayout("1515666344", "")
- answerTime, _ := utils.ParseTimeDetectLayout("1515666347", "")
- expctCDR := &CDR{
- ToR: utils.MetaVoice,
- OriginID: "3da8bf84-c133-4959-9e24-e72875cb33a1",
- OriginHost: "",
- Source: "freeswitch_json",
- Category: "call",
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Account: "1001",
- Subject: "1001",
- Destination: "1002",
- SetupTime: setupTime,
- AnswerTime: answerTime,
- Usage: 68 * time.Second,
- Cost: -1,
- ExtraFields: map[string]string{"sip_user_agent": "Jitsi2.10.5550Linux"},
- }
- if CDR, err := fsCdr.AsCDR(""); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(expctCDR, CDR) {
- t.Errorf("Expecting: %+v, received: %+v", expctCDR, CDR)
- }
-}
-
-func TestFsCdrSearchExtraFieldLast(t *testing.T) {
- newReader := bytes.NewReader(body)
- fsCdr, err := NewFSCdr(newReader, fsCdrCfg)
- if err != nil {
- t.Error(err)
- }
- value := fsCdr.searchExtraField("progress_media_time", fsCdr.body)
- if value != "1515666347954373" {
- t.Error("Error finding extra field: ", value)
- }
-}
-
-func TestFsCdrSearchExtraField(t *testing.T) {
- newReader := bytes.NewReader(body)
- fsCdr, err := NewFSCdr(newReader, fsCdrCfg)
- if err != nil {
- t.Error(err)
- }
- fsCdrCfg.CdrsCfg().ExtraFields, err = config.NewRSRParsersFromSlice([]string{"~*req.caller_id_name"})
- if err != nil {
- t.Fatal(err)
- }
- extraFields := fsCdr.getExtraFields()
- if len(extraFields) != 1 || extraFields["caller_id_name"] != "1001" {
- t.Error("Error parsing extra fields: ", utils.ToJSON(extraFields))
- }
-
-}
-
-func TestFsCdrSearchExtraFieldInSlice(t *testing.T) {
- newReader := bytes.NewReader(body)
- if fsCdr, err := NewFSCdr(newReader, fsCdrCfg); err != nil {
- t.Error(err)
- } else if value := fsCdr.searchExtraField("floatfld1", map[string]interface{}{"floatfld1": 6.4}); value != "6.4" {
- t.Errorf("Expecting: 6.4, received: %s", value)
- }
-}
-
-func TestFsCdrSearchReplaceInExtraFields(t *testing.T) {
- fsCdrCfg.CdrsCfg().ExtraFields = config.NewRSRParsersMustCompile(`~*req.read_codec;~*req.sip_user_agent:s/([A-Za-z]*).+/$1/;~*req.write_codec`, utils.InfieldSep)
- newReader := bytes.NewReader(body)
- fsCdr, err := NewFSCdr(newReader, fsCdrCfg)
- if err != nil {
- t.Error(err)
- }
- extraFields := fsCdr.getExtraFields()
- if len(extraFields) != 3 {
- t.Error("Error parsing extra fields: ", extraFields)
- }
- if extraFields["sip_user_agent"] != "Jitsi" {
- t.Error("Error parsing extra fields: ", utils.ToJSON(extraFields))
- }
-}
-
-func TestFsCdrDDazRSRExtraFields(t *testing.T) {
- eFieldsCfg := `{"cdrs": {
- "extra_fields": ["~*req.effective_caller_id_number:s/(\\d+)/+$1/"],
-},}`
- simpleJSONCdr := []byte(`{
- "core-uuid": "feef0b51-7fdf-4c4a-878e-aff233752de2",
- "channel_data": {
- "state": "CS_REPORTING",
- "state_number": "11",
- "flags": "0=1;1=1;3=1;36=1;37=1;39=1;42=1;47=1;52=1;73=1;75=1;94=1",
- "caps": "1=1;2=1;3=1;4=1;5=1;6=1"
- },
- "variables": {
- "uuid": "86cfd6e2-dbda-45a3-b59d-f683ec368e8b",
- "session_id": "5",
- "accountcode": "1001",
- "user_context": "default",
- "effective_caller_id_name": "Extension 1001",
- "effective_caller_id_number": "4986517174963",
- "outbound_caller_id_name": "FreeSWITCH",
- "outbound_caller_id_number": "0000000000"
- },
- "times": {
- "created_time": "1396984221278217",
- "profile_created_time": "1396984221278217",
- "progress_time": "0",
- "progress_media_time": "0",
- "answered_time": "0",
- "hangup_time": "0",
- "resurrect_time": "0",
- "transfer_time": "1396984221377035"
- }
-}`)
- var err error
- fsCdrCfg, err = config.NewCGRConfigFromJSONStringWithDefaults(eFieldsCfg)
- expCdrExtra := config.NewRSRParsersMustCompile(`~*req.effective_caller_id_number:s/(\d+)/+$1/`, utils.InfieldSep)
- if err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(expCdrExtra[0], fsCdrCfg.CdrsCfg().ExtraFields[0]) { // Kinda deepEqual bug since without index does not match
- t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(expCdrExtra), utils.ToJSON(fsCdrCfg.CdrsCfg().ExtraFields))
- }
- newReader := bytes.NewReader(simpleJSONCdr)
- fsCdr, err := NewFSCdr(newReader, fsCdrCfg)
- if err != nil {
- t.Error("Could not parse cdr", err.Error())
- }
- extraFields := fsCdr.getExtraFields()
- if extraFields["effective_caller_id_number"] != "+4986517174963" {
- t.Errorf("Unexpected effective_caller_id_number received: %+v", extraFields["effective_caller_id_number"])
- }
-}
-
-func TestFsCdrFirstDefined(t *testing.T) {
- newReader := bytes.NewReader(body)
- fsCdr, _ := NewFSCdr(newReader, fsCdrCfg)
- value := fsCdr.firstDefined([]string{utils.CGRSubject, utils.CGRAccount, fsUsernameVar}, fsUsername)
- if value != "1001" {
- t.Errorf("Expecting: 1001, received: %s", value)
- }
- value = fsCdr.firstDefined([]string{utils.CGRAccount, fsUsernameVar}, fsUsername)
- if value != "1001" {
- t.Errorf("Expecting: 1001, received: %s", value)
- }
-}
-
-func TestFscdrAsCDR(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- cgrCfg.CdrsCfg().ExtraFields, err = config.NewRSRParsersFromSlice([]string{"~*req.PayPalAccount"})
- if err != nil {
- t.Error(err)
- }
- fsCdrByte := []byte(` {
- "variables": {
- "cgr_orderid": "123",
- "cgr_partial": "true",
- "cgr_prerated": "false"
- }
-}`)
- expectedCdr := &CDR{
- OrderID: 123,
- ToR: utils.MetaVoice,
- Source: fsCDRSource, Category: cgrCfg.GeneralCfg().DefaultCategory,
- Tenant: cgrCfg.GeneralCfg().DefaultTenant,
- RequestType: cgrCfg.GeneralCfg().DefaultReqType,
- Partial: true,
- PreRated: false,
- ExtraFields: map[string]string{
- "PayPalAccount": "",
- },
- Cost: -1,
- }
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else {
- if cdr, err := fsCdr.AsCDR(""); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(expectedCdr, cdr) {
- t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expectedCdr), utils.ToJSON(cdr))
- }
- }
-}
-
-func TestFscdrAsCdrOrderId(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- fsCdrByte := []byte(` {
- "variables": {
- "cgr_orderid": "123s"
- }
-}`)
- expectedErr := "strconv.ParseInt: parsing \"123s\": invalid syntax"
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else if _, err := fsCdr.AsCDR(""); err == nil || err.Error() != expectedErr {
- t.Errorf("Expected %+v \n, received %+v", expectedErr, err)
- }
-}
-
-func TestFscdrAsCdrSetupTime(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- fsCdrByte := []byte(` {
- "variables": {
- "start_epoch": "123ss"
- }
-}`)
- expectedErr := "Unsupported time format"
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else if _, err := fsCdr.AsCDR(""); err == nil || err.Error() != expectedErr {
- t.Errorf("Expected %+v \n, received %+v", expectedErr, err)
- }
-}
-
-func TestFscdrAsCdrAnswerTime(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- fsCdrByte := []byte(` {
- "variables": {
- "answer_epoch": "123ss"
- }
-}`)
- expectedErr := "Unsupported time format"
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else if _, err := fsCdr.AsCDR(""); err == nil || err.Error() != expectedErr {
- t.Errorf("Expected %+v \n, received %+v", expectedErr, err)
- }
-}
-
-func TestFscdrAsCdrUsage(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- fsCdrByte := []byte(` {
- "variables": {
- "billsec": "1ss"
- }
-}`)
- expectedErr := "time: unknown unit \"ss\" in duration \"1ss\""
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else if _, err := fsCdr.AsCDR(""); err == nil || err.Error() != expectedErr {
- t.Errorf("Expected %+v \n, received %+v", expectedErr, err)
- }
-}
-
-func TestFscdrAsCdrPartial(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- fsCdrByte := []byte(` {
- "variables": {
- "cgr_partial": "InvalidBoolFormat"
- }
-}`)
- expectedErr := "strconv.ParseBool: parsing \"InvalidBoolFormat\": invalid syntax"
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else if _, err := fsCdr.AsCDR(""); err == nil || err.Error() != expectedErr {
- t.Errorf("Expected %+v \n, received %+v", expectedErr, err)
- }
-}
-
-func TestFscdrAsCdrPreRated(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- fsCdrByte := []byte(` {
- "variables": {
- "cgr_prerated": "InvalidBoolFormat"
- }
-}`)
- expectedErr := "strconv.ParseBool: parsing \"InvalidBoolFormat\": invalid syntax"
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else if _, err := fsCdr.AsCDR(""); err == nil || err.Error() != expectedErr {
- t.Errorf("Expected %+v \n, received %+v", expectedErr, err)
- }
-}
-
-func TestFscdrAsCdrFirstDefined(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- fsCdrByte := []byte(` {
- "variables": {
- "cgr_account": "randomAccount"
- }
-}`)
- expectedCdr := &CDR{
- ToR: utils.MetaVoice,
- Source: fsCDRSource, Category: cgrCfg.GeneralCfg().DefaultCategory,
- Tenant: cgrCfg.GeneralCfg().DefaultTenant,
- RequestType: cgrCfg.GeneralCfg().DefaultReqType,
- Account: "randomAccount",
- Subject: "randomAccount",
- ExtraFields: map[string]string{},
- Cost: -1,
- }
- newReader := bytes.NewReader(fsCdrByte)
- if fsCdr, err := NewFSCdr(newReader, cgrCfg); err != nil {
- t.Error(err)
- } else {
- if cdr, err := fsCdr.AsCDR(""); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(expectedCdr, cdr) {
- t.Errorf("Expected %+v \n, redceived %+v", utils.ToJSON(expectedCdr), utils.ToJSON(cdr))
- }
- }
-}
-func TestNewFSCdrDecodeError(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- expectedErr := "EOF"
- newReader := bytes.NewReader(nil)
- if _, err := NewFSCdr(newReader, cgrCfg); err == nil || err.Error() != expectedErr {
- t.Errorf("Expected %+v, received %+v", expectedErr, err)
- }
-}
-
-func TestSearchExtraFieldDefaultType(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- newMap := map[string]interface{}{
- "variables": map[string]string{
- "cgr_orderid": "123",
- },
- }
- fsCdr := FSCdr{
- cgrCfg: cgrCfg,
- body: newMap,
- }
- fsCdr.searchExtraField(utils.EmptyString, newMap)
-}
-
-func TestSearchExtraFieldInterface(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- newMap := map[string]interface{}{ //There is a slice with no maps
- "variables": []interface{}{
- 2,
- "randomValue",
- true,
- },
- }
- fsCdr := FSCdr{
- cgrCfg: cgrCfg,
- body: newMap,
- }
- fsCdr.searchExtraField(utils.EmptyString, newMap)
-}
-
-func TestGetExtraFields(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
-
- cgrCfg.CdrsCfg().ExtraFields, err = config.NewRSRParsersFromSlice([]string{"PayPalAccount"})
- if err != nil {
- t.Error(err)
- }
- fsCdr := FSCdr{
- cgrCfg: cgrCfg,
- }
- expected := map[string]string{}
- if reply := fsCdr.getExtraFields(); !reflect.DeepEqual(reply, expected) {
- t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(reply))
- }
-}
diff --git a/engine/mapevent.go b/engine/mapevent.go
index b9ab97f80..97629fad2 100644
--- a/engine/mapevent.go
+++ b/engine/mapevent.go
@@ -19,10 +19,8 @@ along with this program. If not, see
package engine
import (
- "fmt"
"time"
- "github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
@@ -195,80 +193,6 @@ func (me MapEvent) AsMapString(ignoredFlds utils.StringSet) (mp map[string]strin
return
}
-// AsCDR exports the MapEvent as CDR
-func (me MapEvent) AsCDR(cfg *config.CGRConfig, tnt, tmz string) (cdr *CDR, err error) {
- cdr = &CDR{Tenant: tnt, Cost: -1.0, ExtraFields: make(map[string]string)}
- for k, v := range me {
- if !utils.MainCDRFields.Has(k) { // not primary field, populate extra ones
- cdr.ExtraFields[k] = utils.IfaceAsString(v)
- continue
- }
- switch k {
- default:
- // for the momment this return can not be reached because we implemented a case for every MainCDRField
- return nil, fmt.Errorf("unimplemented CDR field: <%s>", k)
- case utils.RunID:
- cdr.RunID = utils.IfaceAsString(v)
- case utils.OriginHost:
- cdr.OriginHost = utils.IfaceAsString(v)
- case utils.Source:
- cdr.Source = utils.IfaceAsString(v)
- case utils.OriginID:
- cdr.OriginID = utils.IfaceAsString(v)
- case utils.ToR:
- cdr.ToR = utils.IfaceAsString(v)
- case utils.RequestType:
- cdr.RequestType = utils.IfaceAsString(v)
- case utils.Tenant:
- cdr.Tenant = utils.IfaceAsString(v)
- case utils.Category:
- cdr.Category = utils.IfaceAsString(v)
- case utils.AccountField:
- cdr.Account = utils.IfaceAsString(v)
- case utils.Subject:
- cdr.Subject = utils.IfaceAsString(v)
- case utils.Destination:
- cdr.Destination = utils.IfaceAsString(v)
- case utils.SetupTime:
- if cdr.SetupTime, err = utils.IfaceAsTime(v, tmz); err != nil {
- return nil, err
- }
- case utils.AnswerTime:
- if cdr.AnswerTime, err = utils.IfaceAsTime(v, tmz); err != nil {
- return nil, err
- }
- case utils.Usage:
- if cdr.Usage, err = utils.IfaceAsDuration(v); err != nil {
- return nil, err
- }
- case utils.Partial:
- if cdr.Partial, err = utils.IfaceAsBool(v); err != nil {
- return nil, err
- }
- case utils.PreRated:
- if cdr.PreRated, err = utils.IfaceAsBool(v); err != nil {
- return nil, err
- }
- case utils.CostSource:
- cdr.CostSource = utils.IfaceAsString(v)
- case utils.Cost:
- if cdr.Cost, err = utils.IfaceAsFloat64(v); err != nil {
- return nil, err
- }
- case utils.ExtraInfo:
- cdr.ExtraInfo = utils.IfaceAsString(v)
- case utils.OrderID:
- if cdr.OrderID, err = utils.IfaceAsTInt64(v); err != nil {
- return nil, err
- }
- }
- }
- if cfg != nil {
- cdr.AddDefaults(cfg)
- }
- return
-}
-
// Data returns the MapEvent as a map[string]interface{}
func (me MapEvent) Data() map[string]interface{} {
return me
diff --git a/engine/suretax.go b/engine/suretax.go
deleted file mode 100644
index f86a95183..000000000
--- a/engine/suretax.go
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package engine
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "strconv"
- "strings"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/utils"
-)
-
-var sureTaxClient *http.Client // Cache the client here if in use
-
-// Init a new request to be sent out to SureTax
-func NewSureTaxRequest(cdr *CDR, stCfg *config.SureTaxCfg) (*SureTaxRequest, error) {
- if stCfg == nil {
- return nil, errors.New("invalid SureTax config")
- }
- aTimeLoc := cdr.AnswerTime.In(stCfg.Timezone)
- revenue := utils.Round(cdr.Cost, 4, utils.MetaRoundingMiddle)
- unts, err := strconv.ParseInt(cdr.FieldsAsString(stCfg.Units), 10, 64)
- if err != nil {
- return nil, err
- }
- taxExempt := []string{}
- definedTaxExtempt := cdr.FieldsAsString(stCfg.TaxExemptionCodeList)
- if len(definedTaxExtempt) != 0 {
- taxExempt = strings.Split(cdr.FieldsAsString(stCfg.TaxExemptionCodeList), ",")
- }
- stReq := new(STRequest)
- stReq.ClientNumber = stCfg.ClientNumber
- stReq.BusinessUnit = stCfg.BusinessUnit
- stReq.ValidationKey = stCfg.ValidationKey
- stReq.DataYear = strconv.Itoa(aTimeLoc.Year())
- stReq.DataMonth = strconv.Itoa(int(aTimeLoc.Month()))
- stReq.TotalRevenue = revenue
- stReq.ReturnFileCode = stCfg.ReturnFileCode
- stReq.ClientTracking = cdr.FieldsAsString(stCfg.ClientTracking)
- stReq.ResponseGroup = stCfg.ResponseGroup
- stReq.ResponseType = stCfg.ResponseType
- stReq.ItemList = []*STRequestItem{
- {
- CustomerNumber: cdr.FieldsAsString(stCfg.CustomerNumber),
- OrigNumber: cdr.FieldsAsString(stCfg.OrigNumber),
- TermNumber: cdr.FieldsAsString(stCfg.TermNumber),
- BillToNumber: cdr.FieldsAsString(stCfg.BillToNumber),
- Zipcode: cdr.FieldsAsString(stCfg.Zipcode),
- Plus4: cdr.FieldsAsString(stCfg.Plus4),
- P2PZipcode: cdr.FieldsAsString(stCfg.P2PZipcode),
- P2PPlus4: cdr.FieldsAsString(stCfg.P2PPlus4),
- TransDate: aTimeLoc.Format("2006-01-02T15:04:05"),
- Revenue: revenue,
- Units: unts,
- UnitType: cdr.FieldsAsString(stCfg.UnitType),
- Seconds: int64(cdr.Usage.Seconds()),
- TaxIncludedCode: cdr.FieldsAsString(stCfg.TaxIncluded),
- TaxSitusRule: cdr.FieldsAsString(stCfg.TaxSitusRule),
- TransTypeCode: cdr.FieldsAsString(stCfg.TransTypeCode),
- SalesTypeCode: cdr.FieldsAsString(stCfg.SalesTypeCode),
- RegulatoryCode: stCfg.RegulatoryCode,
- TaxExemptionCodeList: taxExempt,
- },
- }
- jsnContent, err := json.Marshal(stReq)
- if err != nil {
- return nil, err
- }
- return &SureTaxRequest{Request: string(jsnContent)}, nil
-}
-
-// SureTax JSON Request
-type SureTaxRequest struct {
- Request string `json:"request"` // SureTax Requires us to encapsulate the content into a request element
-}
-
-// SureTax JSON Response
-type SureTaxResponse struct {
- D string // SureTax requires encapsulating reply into a D object
-}
-
-// SureTax Request type
-type STRequest struct {
- ClientNumber string // Client ID Number – provided by SureTax. Required. Max Len: 10
- BusinessUnit string // Client’s Business Unit. Value for this field is not required. Max Len: 20
- ValidationKey string // Validation Key provided by SureTax. Required for client access to API function. Max Len: 36
- DataYear string // Required. YYYY – Year to use for tax calculation purposes
- DataMonth string // Required. MM – Month to use for tax calculation purposes. Leading zero is preferred.
- TotalRevenue float64 // Required. Format: $$$$$$$$$.CCCC. For Negative charges, the first position should have a minus ‘-‘ indicator.
- ReturnFileCode string // Required. 0 – Default.Q – Quote purposes – taxes are computed and returned in the response message for generating quotes.
- ClientTracking string // Field for client transaction tracking. This value will be provided in the response data. Value for this field is not required, but preferred. Max Len: 100
- IndustryExemption string // Reserved for future use.
- ResponseGroup string // Required. Determines how taxes are grouped for the response.
- ResponseType string // Required. Determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response.
- ItemList []*STRequestItem // List of Item records
-}
-
-// Part of SureTax Request
-type STRequestItem struct {
- LineNumber string // Used to identify an item within the request. If no value is provided, requests are numbered sequentially. Max Len: 40
- InvoiceNumber string // Used for tax aggregation by Invoice. Must be alphanumeric. Max Len: 40
- CustomerNumber string // Used for tax aggregation by Customer. Must be alphanumeric. Max Len: 40
- OrigNumber string // Required when using Tax Situs Rule 01 or 03. Format: NPANXXNNNN
- TermNumber string // Required when using Tax Situs Rule 01. Format: NPANXXNNNN
- BillToNumber string // Required when using Tax Situs Rule 01 or 02. Format: NPANXXNNNN
- Zipcode string // Required when using Tax Situs Rule 04, 05, or 14.
- Plus4 string // Zip code extension in format: 9999 (not applicable for Tax Situs Rule 14)
- P2PZipcode string // Secondary zip code in format: 99999 (US or US territory) or X9X9X9 (Canadian)
- P2PPlus4 string // Secondary zip code extension in format: 99999 (US or US territory) or X9X9X9 (Canadian)
- TransDate string // Required. Date of transaction. Valid date formats include: MM/DD/YYYY, MM-DD-YYYY, YYYY-MM-DDTHH:MM:SS
- Revenue float64 // Required. Format: $$$$$$$$$.CCCC. For Negative charges, the first position should have a minus ‘-‘indicator.
- Units int64 // Required. Units representing number of “lines” or unique charges contained within the revenue. This value is essentially a multiplier on unit-based fees (e.g. E911 fees). Format: 99999. Default should be 1 (one unit).
- UnitType string // Required. 00 – Default / Number of unique access lines.
- Seconds int64 // Required. Duration of call in seconds. Format 99999. Default should be 1.
- TaxIncludedCode string // Required. Values: 0 – Default (No Tax Included) 1 – Tax Included in Revenue
- TaxSitusRule string // Required.
- TransTypeCode string // Required. Transaction Type Indicator.
- SalesTypeCode string // Required. Values: R – Residential customer (default) B – Business customer I – Industrial customer L – Lifeline customer
- RegulatoryCode string // Required. Provider Type.
- TaxExemptionCodeList []string // Required. Tax Exemption to be applied to this item only.
-}
-
-type STResponse struct {
- Successful string // Response will be either ‘Y' or ‘N' : Y = Success / Success with Item error N = Failure
- ResponseCode string // ResponseCode: 9999 – Request was successful. 1101-1400 – Range of values for a failed request (no processing occurred) 9001 – Request was successful, but items within the request have errors. The specific items with errors are provided in the ItemMessages field.
- HeaderMessage string // Response message: For ResponseCode 9999 – “Success”For ResponseCode 9001 – “Success with Item errors”. For ResponseCode 1100-1400 – Unsuccessful / declined web request.
- ItemMessages []*STItemMessage // This field contains a list of items that were not able to be processed due to bad or invalid data (see Response Code of “9001”).
- ClientTracking string // Client transaction tracking provided in web request.
- TotalTax string // Total Tax – a total of all taxes included in the TaxList
- TransId int // Transaction ID – provided by SureTax
- GroupList []*STGroup // contains one-to-many Groups
-}
-
-// Part of the SureTax Response
-type STItemMessage struct {
- LineNumber string // value corresponding to the line number in the web request
- ResponseCode string // a value in the range 9100-9400
- Message string // the error message corresponding to the ResponseCode
-}
-
-// Part of the SureTax Response
-type STGroup struct {
- StateCode string // Tax State
- InvoiceNumber string // Invoice Number
- CustomerNumber string // Customer number
- TaxList []*STTaxItem // contains one-to-many Tax Items
-}
-
-// Part of the SureTax Response
-type STTaxItem struct {
- TaxTypeCode string // Tax Type Code
- TaxTypeDesc string // Tax Type Description
- TaxAmount string // Tax Amount
-}
-
-func SureTaxProcessCdr(cdr *CDR) error {
- stCfg := config.CgrConfig().SureTaxCfg()
- if stCfg == nil {
- return errors.New("Invalid SureTax configuration")
- }
- if sureTaxClient == nil { // First time used, init the client here
- sureTaxClient = &http.Client{
- Transport: httpPstrTransport,
- }
- }
- req, err := NewSureTaxRequest(cdr, stCfg)
- if err != nil {
- return err
- }
- jsnContent, err := json.Marshal(req)
- if err != nil {
- return err
- }
- resp, err := sureTaxClient.Post(stCfg.URL, "application/json", bytes.NewBuffer(jsnContent))
- if err != nil {
- return err
- }
- defer resp.Body.Close()
- respBody, err := io.ReadAll(resp.Body)
- if err != nil {
- return err
- }
- if resp.StatusCode > 299 {
- return fmt.Errorf("Unexpected status code received: %d", resp.StatusCode)
- }
- var respFull SureTaxResponse
- if err := json.Unmarshal(respBody, &respFull); err != nil {
- return err
- }
- var stResp STResponse
- if err := json.Unmarshal([]byte(respFull.D), &stResp); err != nil {
- return err
- }
- if stResp.ResponseCode != "9999" {
- cdr.ExtraInfo = stResp.HeaderMessage
- return nil // No error because the request was processed by SureTax, error will be in the ExtraInfo
- }
- // Write cost to CDR
- totalTax, err := strconv.ParseFloat(stResp.TotalTax, 64)
- if err != nil {
- cdr.ExtraInfo = err.Error()
- }
- if !stCfg.IncludeLocalCost {
- cdr.Cost = utils.Round(totalTax,
- config.CgrConfig().GeneralCfg().RoundingDecimals,
- utils.MetaRoundingMiddle)
- } else {
- cdr.Cost = utils.Round(cdr.Cost+totalTax,
- config.CgrConfig().GeneralCfg().RoundingDecimals,
- utils.MetaRoundingMiddle)
- }
- // Add response into extra fields to be available for later review
- cdr.ExtraFields[utils.MetaSureTax] = respFull.D
- return nil
-}
diff --git a/engine/suretax_test.go b/engine/suretax_test.go
deleted file mode 100644
index 1b12499e6..000000000
--- a/engine/suretax_test.go
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-package engine
-
-import (
- "encoding/json"
- "reflect"
- "testing"
- "time"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/utils"
-)
-
-func TestNewSureTaxRequest(t *testing.T) {
- cdr := &CDR{OrderID: 123, ToR: utils.MetaVoice,
- OriginID: "dsafdsaf", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001",
- Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault,
- Usage: 12 * time.Second,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- Cost: 1.01, PreRated: true,
- }
- cfg := config.NewDefaultCGRConfig()
- stCfg := cfg.SureTaxCfg()
- stCfg.ClientNumber = "000000000"
- stCfg.ValidationKey = "19491161-F004-4F44-BDB3-E976D6739A64"
- stCfg.Timezone = time.UTC
- eSTRequest := &STRequest{
- ClientNumber: "000000000",
- ValidationKey: "19491161-F004-4F44-BDB3-E976D6739A64",
- DataYear: "2013",
- DataMonth: "11",
- TotalRevenue: 1.01,
- ReturnFileCode: "0",
- ResponseGroup: "03",
- ResponseType: "D4",
- ItemList: []*STRequestItem{
- {
- CustomerNumber: "1001",
- OrigNumber: "1001",
- TermNumber: "1002",
- BillToNumber: "",
- TransDate: "2013-11-07T08:42:26",
- Revenue: 1.01,
- Units: 1,
- UnitType: "00",
- Seconds: 12,
- TaxIncludedCode: "0",
- TaxSitusRule: "04",
- TransTypeCode: "010101",
- SalesTypeCode: "R",
- RegulatoryCode: "03",
- TaxExemptionCodeList: []string{},
- },
- },
- }
- jsnReq, _ := json.Marshal(eSTRequest)
- eSureTaxRequest := &SureTaxRequest{Request: string(jsnReq)}
- if stReq, err := NewSureTaxRequest(cdr, stCfg); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eSureTaxRequest, stReq) {
- t.Errorf("Expecting:\n%s\nReceived:\n%s", string(eSureTaxRequest.Request), string(stReq.Request))
- }
-}
-
-func TestSuretaxNewSureTaxRequestNilCfg(t *testing.T) {
-
- cdr := &CDR{
- OrderID: 123,
- ToR: utils.MetaVoice,
- OriginID: "testOriginID",
- OriginHost: "192.168.1.1",
- Source: utils.UnitTest,
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Category: "call",
- Account: "1001",
- Subject: "1001",
- Destination: "1002",
- SetupTime: time.Date(2021, 1, 1, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2021, 1, 1, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault,
- Usage: 12 * time.Second,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- Cost: 1.01, PreRated: true,
- }
- var stCfg *config.SureTaxCfg
-
- experr := "invalid SureTax config"
- stReq, err := NewSureTaxRequest(cdr, stCfg)
-
- if err == nil || err.Error() != experr {
- t.Fatalf("\nExpected: %q, \nReceived: %q", experr, err)
- }
-
- if stReq != nil {
- t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>",
- nil, stReq)
- }
-}
-
-func TestSuretaxNewSureTaxRequestInvalidUnits(t *testing.T) {
- cdr := &CDR{OrderID: 123, ToR: utils.MetaVoice,
- OriginID: "testOriginID", OriginHost: "192.168.1.1",
- Source: utils.UnitTest, RequestType: utils.MetaRated,
- Tenant: "cgrates.org", Category: "call", Account: "1001",
- Subject: "1001", Destination: "1002",
- SetupTime: time.Date(2021, 1, 1, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2021, 1, 1, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault,
- Usage: 12 * time.Second,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- Cost: 1.01, PreRated: true,
- }
- cfg := config.NewDefaultCGRConfig()
- stCfg := cfg.SureTaxCfg()
- stCfg.Units = nil
- stCfg.ClientNumber = "000000000"
- stCfg.ValidationKey = "19491161-F004-4F44-BDB3-E976D6739A64"
- stCfg.Timezone = time.UTC
- experr := "strconv.ParseInt: parsing \"\": invalid syntax"
- stReq, err := NewSureTaxRequest(cdr, stCfg)
-
- if err == nil || err.Error() != experr {
- t.Fatalf("\nExpected: %q, \nReceived: %q", experr, err)
- }
-
- if stReq != nil {
- t.Errorf("\nExpected: <%+v>, \nReceived: <%+v>",
- nil, stReq)
- }
-}
-
-func TestSuretaxSureTaxProcessCdrPostErr(t *testing.T) {
- cdr := &CDR{
-
- OrderID: 123,
- ToR: utils.MetaVoice,
- OriginID: "testOriginID",
- OriginHost: "192.168.1.1",
- Source: utils.UnitTest,
- RequestType: utils.MetaRated,
- Tenant: "cgrates.org",
- Category: "call",
- Account: "1001",
- Subject: "1001",
- Destination: "1002",
- SetupTime: time.Date(2021, 1, 1, 8, 42, 20, 0, time.UTC),
- AnswerTime: time.Date(2021, 1, 1, 8, 42, 26, 0, time.UTC),
- RunID: utils.MetaDefault,
- Usage: 12 * time.Second,
- ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
- Cost: 1.01, PreRated: true,
- }
-
- experr := `Post "": unsupported protocol scheme ""`
- err := SureTaxProcessCdr(cdr)
-
- if err == nil || err.Error() != experr {
- t.Errorf("\nExpected: %q, \nReceived: %q", experr, err)
- }
-}
diff --git a/ers/sql_it_test.go b/ers/sql_it_test.go
deleted file mode 100644
index 4a0c6832f..000000000
--- a/ers/sql_it_test.go
+++ /dev/null
@@ -1,673 +0,0 @@
-//go:build integration
-// +build integration
-
-/*
-Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
-Copyright (C) ITsysCOM GmbH
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package ers
-
-import (
- "fmt"
- "reflect"
- "testing"
- "time"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
- "github.com/cgrates/cgrates/utils"
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- "gorm.io/gorm/logger"
-)
-
-var (
- sqlCfgPath string
- sqlCfg *config.CGRConfig
- sqlTests = []func(t *testing.T){
- testSQLInitConfig,
- testSQLInitDBs,
- testSQLInitCdrDb,
- testSQLInitDB,
- testSQLReader,
- testSQLEmptyTable,
- testSQLPoster,
-
- testSQLAddData,
- testSQLReader2,
-
- testSQLStop,
- }
- sqlTests2 = []func(t *testing.T){
- testSQLInitConfig2,
- testSQLInitDBs2,
- testSQLInitCdrDb2,
- testSQLInitDB2,
- testSQLReader3,
- testSQLEmptyTable2,
- testSQLPoster2,
-
- testSQLAddData2,
- testSQLReader4,
-
- testSQLStop2,
- }
- cdr = &engine.CDR{
- RunID: "RunID",
- }
- db *gorm.DB
- dbConnString = "cgrates:CGRateS.org@tcp(127.0.0.1:3306)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'"
-)
-
-func TestSQL(t *testing.T) {
- // sqlCfgPath = path.Join(*dataDir, "conf", "samples", "ers_reload", "disabled")
- for _, test := range sqlTests {
- t.Run("TestSQL", test)
- }
-}
-
-func testSQLInitConfig(t *testing.T) {
- var err error
- if sqlCfg, err = config.NewCGRConfigFromJSONStringWithDefaults(`{
- "stor_db": {
- "db_password": "CGRateS.org",
- },
- "ers": { // EventReaderService
- "enabled": true, // starts the EventReader service:
- "sessions_conns":["*localhost"],
- "readers": [
- {
- "id": "mysql", // identifier of the EventReader profile
- "type": "*sql", // reader type <*fileCSV>
- "run_delay": "1", // sleep interval in seconds between consecutive runs, -1 to use automation via inotify or 0 to disable running all together
- "concurrent_requests": 1024, // maximum simultaneous requests/files to process, 0 for unlimited
- "source_path": "*mysql://cgrates:CGRateS.org@127.0.0.1:3306", // read data from this path
- "opts": {
- "sqlDBName":"cgrates2",
- "sqlDBNameProcessed":"cgrates2",
- "sqlTableNameProcessed":"cdrs2",
- },
- "processed_path": "", // move processed data here
- "tenant": "cgrates.org", // tenant used by import
- "filters": [], // limit parsing based on the filters
- "flags": [], // flags to influence the event processing
- "fields":[ // import fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
- {"tag": "OriginID", "type": "*composed", "value": "~*req.OriginID", "path": "*cgreq.OriginID"},
- ],
- },
- ],
- },
- }`); err != nil {
- t.Fatal(err)
- }
- if err := sqlCfg.CheckConfigSanity(); err != nil {
- t.Fatal(err)
- }
-}
-
-func testSQLInitCdrDb(t *testing.T) {
- if err := engine.InitStorDB(sqlCfg); err != nil {
- t.Fatal(err)
- }
-}
-
-type testModelSql struct {
- ID int64
- RunID string
- OriginHost string
- Source string
- OriginID string
- ToR string
- RequestType string
- Tenant string
- Category string
- Account string
- Subject string
- Destination string
- SetupTime time.Time
- AnswerTime time.Time
- Usage int64
- ExtraFields string
- CostSource string
- Cost float64
- CostDetails string
- ExtraInfo string
- CreatedAt time.Time
- UpdatedAt time.Time
- DeletedAt *time.Time
-}
-
-func (_ *testModelSql) TableName() string {
- return "cdrs2"
-}
-
-func testSQLInitDBs(t *testing.T) {
- var err error
- var db2 *gorm.DB
- if db2, err = gorm.Open(mysql.Open(fmt.Sprintf(dbConnString, "cgrates")),
- &gorm.Config{
- AllowGlobalUpdate: true,
- Logger: logger.Default.LogMode(logger.Silent),
- }); err != nil {
- t.Fatal(err)
- }
-
- if err = db2.Exec(`CREATE DATABASE IF NOT EXISTS cgrates2;`).Error; err != nil {
- t.Fatal(err)
- }
-}
-func testSQLInitDB(t *testing.T) {
-
- var err error
- if db, err = gorm.Open(mysql.Open(fmt.Sprintf(dbConnString, "cgrates2")),
- &gorm.Config{
- AllowGlobalUpdate: true,
- Logger: logger.Default.LogMode(logger.Silent),
- }); err != nil {
- t.Fatal(err)
- }
- tx := db.Begin()
- if !tx.Migrator().HasTable("cdrs") {
- if err = tx.Migrator().CreateTable(new(engine.CDRsql)); err != nil {
- tx.Rollback()
- t.Fatal(err)
- }
- }
- if !tx.Migrator().HasTable("cdrs2") {
- if err = tx.Migrator().CreateTable(new(testModelSql)); err != nil {
- tx.Rollback()
- t.Fatal(err)
- }
- }
- tx.Commit()
- tx = db.Begin()
- tx = tx.Table(utils.CDRsTBL)
- cdrSql := cdr.AsCDRsql()
- cdrSql.CreatedAt = time.Now()
- saved := tx.Save(cdrSql)
- if saved.Error != nil {
- tx.Rollback()
- t.Fatal(err)
- }
- tx.Commit()
- time.Sleep(10 * time.Millisecond)
- var result int64
- db.Table(utils.CDRsTBL).Count(&result)
- if result != 1 {
- t.Fatal("Expected table to have only one result ", result)
- }
-}
-
-func testSQLAddData(t *testing.T) {
- tx := db.Begin()
- tx = tx.Table(utils.CDRsTBL)
- cdrSql := cdr.AsCDRsql()
- cdrSql.CreatedAt = time.Now()
- saved := tx.Save(cdrSql)
- if saved.Error != nil {
- tx.Rollback()
- t.Fatal(saved.Error)
- }
- tx.Commit()
- time.Sleep(10 * time.Millisecond)
-}
-func testSQLReader(t *testing.T) {
- rdrEvents = make(chan *erEvent, 1)
- rdrErr = make(chan error, 1)
- rdrExit = make(chan struct{}, 1)
- sqlER, err := NewEventReader(sqlCfg, 1, rdrEvents, make(chan *erEvent, 1), rdrErr, new(engine.FilterS), rdrExit)
- if err != nil {
- t.Fatal(err)
- }
- sqlER.Serve()
- select {
- case err = <-rdrErr:
- t.Error(err)
- case ev := <-rdrEvents:
- if ev.rdrCfg.ID != "mysql" {
- t.Errorf("Expected 'mysql' received `%s`", ev.rdrCfg.ID)
- }
- expected := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: ev.cgrEvent.ID,
- Event: map[string]interface{}{},
- APIOpts: map[string]interface{}{},
- }
- if !reflect.DeepEqual(ev.cgrEvent, expected) {
- t.Errorf("Expected %s ,received %s", utils.ToJSON(expected), utils.ToJSON(ev.cgrEvent))
- }
- case <-time.After(time.Second):
- t.Fatal("Timeout")
- }
-}
-
-func testSQLEmptyTable(t *testing.T) {
- time.Sleep(10 * time.Millisecond)
- var result int64
- db.Table(utils.CDRsTBL).Count(&result)
- if result != 0 {
- t.Fatal("Expected empty table ", result)
- }
-}
-
-func testSQLReader2(t *testing.T) {
- select {
- case err := <-rdrErr:
- t.Error(err)
- case ev := <-rdrEvents:
- if ev.rdrCfg.ID != "mysql" {
- t.Errorf("Expected 'mysql' received `%s`", ev.rdrCfg.ID)
- }
- expected := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: ev.cgrEvent.ID,
- Event: map[string]interface{}{},
- APIOpts: map[string]interface{}{},
- }
- if !reflect.DeepEqual(ev.cgrEvent, expected) {
- t.Errorf("Expected %s ,received %s", utils.ToJSON(expected), utils.ToJSON(ev.cgrEvent))
- }
- case <-time.After(time.Second):
- t.Fatal("Timeout")
- }
-}
-
-func testSQLPoster(t *testing.T) {
- rows, err := db.Table("cdrs2").Select("*").Rows()
- if err != nil {
- t.Fatal(err)
- }
- colNames, err := rows.Columns()
- if err != nil {
- t.Fatal(err)
- }
- for rows.Next() {
- columns := make([]interface{}, len(colNames))
- columnPointers := make([]interface{}, len(colNames))
- for i := range columns {
- columnPointers[i] = &columns[i]
- }
- if err = rows.Scan(columnPointers...); err != nil {
- t.Fatal(err)
- }
- msg := make(map[string]interface{})
- for i, colName := range colNames {
- msg[colName] = columns[i]
- }
- db.Table("cdrs2").Delete(msg)
- }
-}
-
-func testSQLStop(t *testing.T) {
- close(rdrExit)
- if err := db.Migrator().DropTable("cdrs2"); err != nil {
- t.Fatal(err)
- }
- if err := db.Migrator().DropTable("cdrs"); err != nil {
- t.Fatal(err)
- }
- if err := db.Exec(`DROP DATABASE cgrates2;`).Error; err != nil {
- t.Fatal(err)
- }
- if db2, err := db.DB(); err != nil {
- t.Fatal(err)
- } else if err = db2.Close(); err != nil {
- t.Fatal(err)
- }
-
-}
-
-func TestSQLReaderServeBadTypeErr(t *testing.T) {
- rdr := &SQLEventReader{
- connType: "badType",
- }
- expected := "db type not supported"
- err := rdr.Serve()
- if err == nil || err.Error() != expected {
- t.Errorf("\nExpected: <%+v>, \nreceived: <%+v>", expected, err)
- }
-}
-
-func TestSQL2(t *testing.T) {
- // sqlCfgPath = path.Join(*dataDir, "conf", "samples", "ers_reload", "disabled")
- for _, test := range sqlTests2 {
- t.Run("TestSQL", test)
- }
-}
-
-func testSQLInitConfig2(t *testing.T) {
- var err error
- if sqlCfg, err = config.NewCGRConfigFromJSONStringWithDefaults(`{
- "stor_db": {
- "db_password": "CGRateS.org",
- },
- "ers": { // EventReaderService
- "enabled": true, // starts the EventReader service:
- "readers": [
- {
- "id": "mysql", // identifier of the EventReader profile
- "type": "*sql", // reader type <*fileCSV>
- "run_delay": "1", // sleep interval in seconds between consecutive runs, -1 to use automation via inotify or 0 to disable running all together
- "concurrent_requests": 1024, // maximum simultaneous requests/files to process, 0 for unlimited
- "source_path": "*mysql://cgrates:CGRateS.org@127.0.0.1:3306", // read data from this path
- "opts": {
- "sqlDBName":"cgrates2",
- "sqlDBNameProcessed":"cgrates2",
- "sqlTableNameProcessed":"cdrs2",
- },
- "processed_path": "", // move processed data here
- "tenant": "cgrates.org", // tenant used by import
- "filters": [], // limit parsing based on the filters
- "flags": [], // flags to influence the event processing
- "fields":[ // import fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
- {"tag": "OriginID", "type": "*composed", "value": "~*req.OriginID", "path": "*cgreq.OriginID"},
- ],
- },
- ],
- },
- }`); err != nil {
- t.Fatal(err)
- }
-}
-
-func testSQLInitCdrDb2(t *testing.T) {
- if err := engine.InitStorDB(sqlCfg); err != nil {
- t.Fatal(err)
- }
-}
-
-func testSQLInitDBs2(t *testing.T) {
- var err error
- var db2 *gorm.DB
- if db2, err = gorm.Open(mysql.Open(fmt.Sprintf(dbConnString, "cgrates")),
- &gorm.Config{
- AllowGlobalUpdate: true,
- Logger: logger.Default.LogMode(logger.Silent),
- }); err != nil {
- t.Fatal(err)
- }
-
- if err = db2.Exec(`CREATE DATABASE IF NOT EXISTS cgrates2;`).Error; err != nil {
- t.Fatal(err)
- }
-}
-func testSQLInitDB2(t *testing.T) {
- var err error
- if db, err = gorm.Open(mysql.Open(fmt.Sprintf(dbConnString, "cgrates2")),
- &gorm.Config{
- AllowGlobalUpdate: true,
- Logger: logger.Default.LogMode(logger.Silent),
- }); err != nil {
- t.Fatal(err)
- }
- tx := db.Begin()
- if !tx.Migrator().HasTable("cdrs") {
- if err = tx.Migrator().CreateTable(new(engine.CDRsql)); err != nil {
- tx.Rollback()
- t.Fatal(err)
- }
- }
- if !tx.Migrator().HasTable("cdrs2") {
- if err = tx.Migrator().CreateTable(new(testModelSql)); err != nil {
- tx.Rollback()
- t.Fatal(err)
- }
- }
- tx.Commit()
- tx = db.Begin()
- tx = tx.Table(utils.CDRsTBL)
- cdrSql := cdr.AsCDRsql()
- cdrSql.CreatedAt = time.Now()
- saved := tx.Save(cdrSql)
- if saved.Error != nil {
- tx.Rollback()
- t.Fatal(err)
- }
- tx.Commit()
- time.Sleep(10 * time.Millisecond)
- var result int64
- db.Table(utils.CDRsTBL).Count(&result)
- if result != 1 {
- t.Fatal("Expected table to have only one result ", result)
- }
-}
-
-func testSQLAddData2(t *testing.T) {
- tx := db.Begin()
- tx = tx.Table(utils.CDRsTBL)
- cdrSql := cdr.AsCDRsql()
- cdrSql.CreatedAt = time.Now()
- saved := tx.Save(cdrSql)
- if saved.Error != nil {
- tx.Rollback()
- t.Fatal(saved.Error)
- }
- tx.Commit()
- time.Sleep(10 * time.Millisecond)
-}
-func testSQLReader3(t *testing.T) {
- rdrEvents = make(chan *erEvent, 1)
- rdrErr = make(chan error, 1)
- rdrExit = make(chan struct{}, 1)
- sqlER, err := NewEventReader(sqlCfg, 1, rdrEvents, make(chan *erEvent, 1), rdrErr, new(engine.FilterS), rdrExit)
- if err != nil {
- t.Fatal(err)
- }
- sqlER.Serve()
-
- select {
- case err = <-rdrErr:
- t.Error(err)
- case ev := <-rdrEvents:
- if ev.rdrCfg.ID != "mysql" {
- t.Errorf("Expected 'mysql' received `%s`", ev.rdrCfg.ID)
- }
- expected := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: ev.cgrEvent.ID,
- Event: map[string]interface{}{},
- APIOpts: map[string]interface{}{},
- }
- if !reflect.DeepEqual(ev.cgrEvent, expected) {
- t.Errorf("Expected %s ,received %s", utils.ToJSON(expected), utils.ToJSON(ev.cgrEvent))
- }
- case <-time.After(time.Second):
- t.Fatal("Timeout")
- }
-}
-
-func testSQLEmptyTable2(t *testing.T) {
- time.Sleep(10 * time.Millisecond)
- var result int64
- db.Table(utils.CDRsTBL).Count(&result)
- if result != 0 {
- t.Fatal("Expected empty table ", result)
- }
-}
-
-func testSQLReader4(t *testing.T) {
- select {
- case err := <-rdrErr:
- t.Error(err)
- case ev := <-rdrEvents:
- if ev.rdrCfg.ID != "mysql" {
- t.Errorf("Expected 'mysql' received `%s`", ev.rdrCfg.ID)
- }
- expected := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: ev.cgrEvent.ID,
- Event: map[string]interface{}{},
- APIOpts: map[string]interface{}{},
- }
- if !reflect.DeepEqual(ev.cgrEvent, expected) {
- t.Errorf("Expected %s ,received %s", utils.ToJSON(expected), utils.ToJSON(ev.cgrEvent))
- }
- case <-time.After(time.Second):
- t.Fatal("Timeout")
- }
-}
-
-func testSQLPoster2(t *testing.T) {
- rows, err := db.Table("cdrs2").Select("*").Rows()
- if err != nil {
- t.Fatal(err)
- }
- colNames, err := rows.Columns()
- if err != nil {
- t.Fatal(err)
- }
- for rows.Next() {
- columns := make([]interface{}, len(colNames))
- columnPointers := make([]interface{}, len(colNames))
- for i := range columns {
- columnPointers[i] = &columns[i]
- }
- if err = rows.Scan(columnPointers...); err != nil {
- t.Fatal(err)
- }
- msg := make(map[string]interface{})
- for i, colName := range colNames {
- msg[colName] = columns[i]
- }
- db.Table("cdrs2").Delete(msg)
-
- }
-}
-
-func testSQLStop2(t *testing.T) {
- close(rdrExit)
- if err := db.Migrator().DropTable("cdrs2"); err != nil {
- t.Fatal(err)
- }
- if err := db.Migrator().DropTable("cdrs"); err != nil {
- t.Fatal(err)
- }
- if err := db.Exec(`DROP DATABASE cgrates2;`).Error; err != nil {
- t.Fatal(err)
- }
- if db2, err := db.DB(); err != nil {
- t.Fatal(err)
- } else if err = db2.Close(); err != nil {
- t.Fatal(err)
- }
-
-}
-
-func TestSQLProcessMessageError(t *testing.T) {
- cfg := config.NewDefaultCGRConfig()
- testSQLEventReader := &SQLEventReader{
- cgrCfg: cfg,
- cfgIdx: 0,
- fltrS: &engine.FilterS{},
- connString: "",
- connType: "",
- tableName: "testName",
- expConnString: "",
- expConnType: utils.Postgres,
- expTableName: "",
- rdrEvents: nil,
- rdrExit: nil,
- rdrErr: nil,
- cap: nil,
- }
-
- msgTest := map[string]interface{}{}
- err := testSQLEventReader.processMessage(msgTest)
- expected := "NOT_FOUND:ToR"
- if err == nil || err.Error() != expected {
- t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
- }
-}
-
-func TestSQLSetURLError(t *testing.T) {
- cfg := config.NewDefaultCGRConfig()
- testSQLEventReader := &SQLEventReader{
- cgrCfg: cfg,
- cfgIdx: 0,
- fltrS: &engine.FilterS{},
- connString: "",
- connType: "",
- tableName: "testName",
- expConnString: "",
- expConnType: utils.Postgres,
- expTableName: "",
- rdrEvents: nil,
- rdrExit: nil,
- rdrErr: nil,
- cap: nil,
- }
- err := testSQLEventReader.setURL("http://user^:passwo^rd@foo.com/", "", nil)
- expected := `parse "http://user^:passwo^rd@foo.com/": net/url: invalid userinfo`
- if err == nil || err.Error() != expected {
- t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
- }
-}
-
-func TestSQLSetURLError2(t *testing.T) {
- cfg := config.NewDefaultCGRConfig()
- testSQLEventReader := &SQLEventReader{
- cgrCfg: cfg,
- cfgIdx: 0,
- fltrS: &engine.FilterS{},
- connString: "",
- connType: "",
- tableName: "testName",
- expConnString: "",
- expConnType: utils.Postgres,
- expTableName: "",
- rdrEvents: nil,
- rdrExit: nil,
- rdrErr: nil,
- cap: nil,
- }
- err := testSQLEventReader.setURL("*mysql://cgrates:CGRateS.org@127.0.0.1:3306", "http://user^:passwo^rd@foo.com/", nil)
- expected := `parse "http://user^:passwo^rd@foo.com/": net/url: invalid userinfo`
- if err == nil || err.Error() != expected {
- t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
- }
-}
-
-func TestErsSqlPostCDRS(t *testing.T) {
- tmp := logger.Default
- logger.Default = logger.Default.LogMode(logger.Silent)
- cfg := config.NewDefaultCGRConfig()
- fltr := &engine.FilterS{}
- reader := cfg.ERsCfg().Readers[0].Clone()
- reader.Type = utils.MetaSQL
- reader.ID = "file_reader"
- reader.ConcurrentReqs = -1
- reader.Opts = &config.EventReaderOpts{
- SQLDBName: utils.StringPointer("cgrates2"),
- }
- reader.SourcePath = "*mysql://cgrates:CGRateS.org@127.0.0.1:3306"
- reader.ProcessedPath = ""
- cfg.ERsCfg().Readers = append(cfg.ERsCfg().Readers, reader)
- if len(cfg.ERsCfg().Readers) != 2 {
- t.Errorf("Expecting: <2>, received: <%+v>", len(cfg.ERsCfg().Readers))
- }
- sqlEvReader, err := NewSQLEventReader(cfg, 1, nil, nil, nil, fltr, nil)
- if err != nil {
- t.Errorf("Expecting: , received: <%+v>", err)
- }
- sqlEvReader.(*SQLEventReader).expConnType = utils.MySQL
- result := sqlEvReader.(*SQLEventReader).postCDR([]interface{}{})
- expected := "Error 1045: Access denied for user ''@'localhost' (using password: NO)"
- if result == nil {
- t.Errorf("\nExpected: <%+v>, \nreceived: <%+v>", expected, result)
- }
- logger.Default = tmp
-}