From de7b4811f6c948f4b3fd628696b23ac7f9faed20 Mon Sep 17 00:00:00 2001 From: DanB Date: Wed, 1 Jun 2016 18:42:45 +0200 Subject: [PATCH 01/11] Test fixes for multiple cdrc, CheckVersion taking now db as input, InitDataDb saving also version --- apier/v1/apier_local_test.go | 2 +- cmd/cgr-engine/cgr-engine.go | 2 +- engine/libtest.go | 1 + engine/version.go | 11 +++++++---- general_tests/multiplecdrc_local_test.go | 25 ++++++++++++------------ 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 50e71ef13..34028cfd0 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -1274,7 +1274,7 @@ func TestApierLoadTariffPlanFromFolder(t *testing.T) { } else if reply != "OK" { t.Error("Calling ApierV1.LoadTariffPlanFromFolder got reply: ", reply) } - time.Sleep(time.Duration(2**waitRater) * time.Millisecond) + time.Sleep(time.Duration(3**waitRater) * time.Millisecond) } func TestApierResetDataAfterLoadFromFolder(t *testing.T) { diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 1a1af55a1..8c0f62af0 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -508,7 +508,7 @@ func main() { } defer accountDb.Close() engine.SetAccountingStorage(accountDb) - if err := engine.CheckVersion(); err != nil { + if err := engine.CheckVersion(nil); err != nil { fmt.Println(err.Error()) return } diff --git a/engine/libtest.go b/engine/libtest.go index 99877e0be..f45288566 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -48,6 +48,7 @@ func InitDataDb(cfg *config.CGRConfig) error { } } ratingDb.CacheRatingAll() + CheckVersion(accountDb) // Write version before starting return nil } diff --git a/engine/version.go b/engine/version.go index 08849db5c..6d69f6f6b 100644 --- a/engine/version.go +++ b/engine/version.go @@ -7,13 +7,16 @@ import ( "github.com/cgrates/cgrates/utils" ) -func CheckVersion() error { +func CheckVersion(acntDB AccountingStorage) error { // get current db version - dbVersion, err := accountingStorage.GetStructVersion() + if acntDB == nil { + acntDB = accountingStorage + } + dbVersion, err := acntDB.GetStructVersion() if err != nil { - if lhList, err := accountingStorage.GetLoadHistory(1, true); err != nil || len(lhList) == 0 { + if lhList, err := acntDB.GetLoadHistory(1, true); err != nil || len(lhList) == 0 { // no data, write version - if err := accountingStorage.SetStructVersion(CurrentVersion); err != nil { + if err := acntDB.SetStructVersion(CurrentVersion); err != nil { utils.Logger.Warning(fmt.Sprintf("Could not write current version to db: %v", err)) } } else { diff --git a/general_tests/multiplecdrc_local_test.go b/general_tests/multiplecdrc_local_test.go index 651404bda..0804282a3 100644 --- a/general_tests/multiplecdrc_local_test.go +++ b/general_tests/multiplecdrc_local_test.go @@ -77,23 +77,22 @@ func TestMCDRCLoadConfig(t *testing.T) { } } +// Remove data in both rating and accounting db +func TestMCDRCResetDataDb(t *testing.T) { + if !*testLocal { + return + } + if err := engine.InitDataDb(cfg); err != nil { + t.Fatal(err) + } +} + func TestMCDRCEmptyTables(t *testing.T) { if !*testLocal { return } - if *storDbType != utils.MYSQL { - t.Fatal("Unsupported storDbType") - } - mysql, err := engine.NewMySQLStorage(cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns) - if err != nil { - t.Fatal("Error on opening database connection: ", err) - } - if err := mysql.CreateTablesFromScript(path.Join(*dataDir, "storage", *storDbType, utils.CREATE_CDRS_TABLES_SQL)); err != nil { - t.Fatal("Error on mysql creation: ", err.Error()) - return // No point in going further - } - if _, err := mysql.Db.Query(fmt.Sprintf("SELECT 1 from %s", utils.TBL_CDRS)); err != nil { - t.Fatal(err.Error()) + if err := engine.InitStorDb(cfg); err != nil { + t.Fatal(err) } } From 1095b5a822fa5a1e7a2cf94f82d2fc74180a4d4b Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 3 Jun 2016 16:41:58 +0200 Subject: [PATCH 02/11] SMGenericV1 methods change: GetMaxUsage->MaxUsage, GetLcrSuppliers->LCRSuppliers, SessionStart->InitiateSession, SessionUpdate->UpdateSession, SessionEnd->TerminateSession, ProcessCdr->ProcessCDR --- agents/dmtagent.go | 8 +++--- apier/v1/smgenericbirpcv1.go | 36 ++++++++++++------------ apier/v1/smgenericv1.go | 48 +++++++++++++++---------------- apier/v1/smgenericv1_it_test.go | 2 +- sessionmanager/data_it_test.go | 50 ++++++++++++++++----------------- sessionmanager/smg_it_test.go | 36 ++++++++++++------------ sessionmanager/smgeneric.go | 14 ++++----- 7 files changed, 97 insertions(+), 97 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index cb927bbd3..c2708bd1a 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -130,13 +130,13 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro } else { // Find out maxUsage over APIs switch ccr.CCRequestType { case 1: - err = self.smg.Call("SMGenericV1.SessionStart", smgEv, &maxUsage) + err = self.smg.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage) case 2: - err = self.smg.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage) + err = self.smg.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage) case 3, 4: // Handle them together since we generate CDR for them var rpl string if ccr.CCRequestType == 3 { - err = self.smg.Call("SMGenericV1.SessionEnd", smgEv, &rpl) + err = self.smg.Call("SMGenericV1.TerminateSession", smgEv, &rpl) } else if ccr.CCRequestType == 4 { err = self.smg.Call("SMGenericV1.ChargeEvent", smgEv, &maxUsage) if maxUsage == 0 { @@ -144,7 +144,7 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro } } if self.cgrCfg.DiameterAgentCfg().CreateCDR { - if errCdr := self.smg.Call("SMGenericV1.ProcessCdr", smgEv, &rpl); errCdr != nil { + if errCdr := self.smg.Call("SMGenericV1.ProcessCDR", smgEv, &rpl); errCdr != nil { err = errCdr } } diff --git a/apier/v1/smgenericbirpcv1.go b/apier/v1/smgenericbirpcv1.go index 035d55b86..c5e5e40a5 100644 --- a/apier/v1/smgenericbirpcv1.go +++ b/apier/v1/smgenericbirpcv1.go @@ -37,18 +37,18 @@ type SMGenericBiRpcV1 struct { // Publishes methods exported by SMGenericBiRpcV1 as SMGenericV1 (so we can handle standard RPC methods via birpc socket) func (self *SMGenericBiRpcV1) Handlers() map[string]interface{} { return map[string]interface{}{ - "SMGenericV1.GetMaxUsage": self.GetMaxUsage, - "SMGenericV1.GetLcrSuppliers": self.GetLcrSuppliers, - "SMGenericV1.SessionStart": self.SessionStart, - "SMGenericV1.SessionUpdate": self.SessionUpdate, - "SMGenericV1.SessionEnd": self.SessionEnd, - "SMGenericV1.ProcessCdr": self.ProcessCdr, + "SMGenericV1.MaxUsage": self.MaxUsage, + "SMGenericV1.LCRSuppliers": self.LCRSuppliers, + "SMGenericV1.InitiateSession": self.InitiateSession, + "SMGenericV1.UpdateSession": self.UpdateSession, + "SMGenericV1.TerminateSession": self.TerminateSession, + "SMGenericV1.ProcessCDR": self.ProcessCDR, } } /// Returns MaxUsage (for calls in seconds), -1 for no limit -func (self *SMGenericBiRpcV1) GetMaxUsage(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - maxUsageDur, err := self.sm.GetMaxUsage(ev, clnt) +func (self *SMGenericBiRpcV1) MaxUsage(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { + maxUsageDur, err := self.sm.MaxUsage(ev, clnt) if err != nil { return utils.NewErrServerError(err) } @@ -61,8 +61,8 @@ func (self *SMGenericBiRpcV1) GetMaxUsage(clnt *rpc2.Client, ev sessionmanager.S } /// Returns list of suppliers which can be used for the request -func (self *SMGenericBiRpcV1) GetLcrSuppliers(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, suppliers *[]string) error { - if supls, err := self.sm.GetLcrSuppliers(ev, clnt); err != nil { +func (self *SMGenericBiRpcV1) LCRSuppliers(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, suppliers *[]string) error { + if supls, err := self.sm.LCRSuppliers(ev, clnt); err != nil { return utils.NewErrServerError(err) } else { *suppliers = supls @@ -71,8 +71,8 @@ func (self *SMGenericBiRpcV1) GetLcrSuppliers(clnt *rpc2.Client, ev sessionmanag } // Called on session start, returns the maximum number of seconds the session can last -func (self *SMGenericBiRpcV1) SessionStart(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if minMaxUsage, err := self.sm.SessionStart(ev, clnt); err != nil { +func (self *SMGenericBiRpcV1) InitiateSession(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { + if minMaxUsage, err := self.sm.InitiateSession(ev, clnt); err != nil { return utils.NewErrServerError(err) } else { *maxUsage = minMaxUsage.Seconds() @@ -81,8 +81,8 @@ func (self *SMGenericBiRpcV1) SessionStart(clnt *rpc2.Client, ev sessionmanager. } // Interim updates, returns remaining duration from the rater -func (self *SMGenericBiRpcV1) SessionUpdate(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if minMaxUsage, err := self.sm.SessionUpdate(ev, clnt); err != nil { +func (self *SMGenericBiRpcV1) UpdateSession(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { + if minMaxUsage, err := self.sm.UpdateSession(ev, clnt); err != nil { return utils.NewErrServerError(err) } else { *maxUsage = minMaxUsage.Seconds() @@ -91,8 +91,8 @@ func (self *SMGenericBiRpcV1) SessionUpdate(clnt *rpc2.Client, ev sessionmanager } // Called on session end, should stop debit loop -func (self *SMGenericBiRpcV1) SessionEnd(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, reply *string) error { - if err := self.sm.SessionEnd(ev, clnt); err != nil { +func (self *SMGenericBiRpcV1) TerminateSession(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, reply *string) error { + if err := self.sm.TerminateSession(ev, clnt); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK @@ -110,8 +110,8 @@ func (self *SMGenericBiRpcV1) ChargeEvent(clnt *rpc2.Client, ev sessionmanager.S } // Called on session end, should send the CDR to CDRS -func (self *SMGenericBiRpcV1) ProcessCdr(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, reply *string) error { - if err := self.sm.ProcessCdr(ev); err != nil { +func (self *SMGenericBiRpcV1) ProcessCDR(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, reply *string) error { + if err := self.sm.ProcessCDR(ev); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK diff --git a/apier/v1/smgenericv1.go b/apier/v1/smgenericv1.go index 08471bc3d..07d09a2fa 100644 --- a/apier/v1/smgenericv1.go +++ b/apier/v1/smgenericv1.go @@ -18,8 +18,8 @@ type SMGenericV1 struct { } // Returns MaxUsage (for calls in seconds), -1 for no limit -func (self *SMGenericV1) GetMaxUsage(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - maxUsageDur, err := self.sm.GetMaxUsage(ev, nil) +func (self *SMGenericV1) MaxUsage(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { + maxUsageDur, err := self.sm.MaxUsage(ev, nil) if err != nil { return utils.NewErrServerError(err) } @@ -32,8 +32,8 @@ func (self *SMGenericV1) GetMaxUsage(ev sessionmanager.SMGenericEvent, maxUsage } // Returns list of suppliers which can be used for the request -func (self *SMGenericV1) GetLcrSuppliers(ev sessionmanager.SMGenericEvent, suppliers *[]string) error { - if supls, err := self.sm.GetLcrSuppliers(ev, nil); err != nil { +func (self *SMGenericV1) LCRSuppliers(ev sessionmanager.SMGenericEvent, suppliers *[]string) error { + if supls, err := self.sm.LCRSuppliers(ev, nil); err != nil { return utils.NewErrServerError(err) } else { *suppliers = supls @@ -42,8 +42,8 @@ func (self *SMGenericV1) GetLcrSuppliers(ev sessionmanager.SMGenericEvent, suppl } // Called on session start, returns the maximum number of seconds the session can last -func (self *SMGenericV1) SessionStart(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if minMaxUsage, err := self.sm.SessionStart(ev, nil); err != nil { +func (self *SMGenericV1) InitiateSession(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { + if minMaxUsage, err := self.sm.InitiateSession(ev, nil); err != nil { return utils.NewErrServerError(err) } else { *maxUsage = minMaxUsage.Seconds() @@ -52,8 +52,8 @@ func (self *SMGenericV1) SessionStart(ev sessionmanager.SMGenericEvent, maxUsage } // Interim updates, returns remaining duration from the rater -func (self *SMGenericV1) SessionUpdate(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if minMaxUsage, err := self.sm.SessionUpdate(ev, nil); err != nil { +func (self *SMGenericV1) UpdateSession(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { + if minMaxUsage, err := self.sm.UpdateSession(ev, nil); err != nil { return utils.NewErrServerError(err) } else { *maxUsage = minMaxUsage.Seconds() @@ -62,8 +62,8 @@ func (self *SMGenericV1) SessionUpdate(ev sessionmanager.SMGenericEvent, maxUsag } // Called on session end, should stop debit loop -func (self *SMGenericV1) SessionEnd(ev sessionmanager.SMGenericEvent, reply *string) error { - if err := self.sm.SessionEnd(ev, nil); err != nil { +func (self *SMGenericV1) TerminateSession(ev sessionmanager.SMGenericEvent, reply *string) error { + if err := self.sm.TerminateSession(ev, nil); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK @@ -81,8 +81,8 @@ func (self *SMGenericV1) ChargeEvent(ev sessionmanager.SMGenericEvent, maxUsage } // Called on session end, should send the CDR to CDRS -func (self *SMGenericV1) ProcessCdr(ev sessionmanager.SMGenericEvent, reply *string) error { - if err := self.sm.ProcessCdr(ev); err != nil { +func (self *SMGenericV1) ProcessCDR(ev sessionmanager.SMGenericEvent, reply *string) error { + if err := self.sm.ProcessCDR(ev); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK @@ -143,7 +143,7 @@ func (self *SMGenericV1) ActiveSessionsCount(attrs utils.AttrSMGGetActiveSession // rpcclient.RpcClientConnection interface func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply interface{}) error { switch serviceMethod { - case "SMGenericV1.GetMaxUsage": + case "SMGenericV1.MaxUsage": argsConverted, canConvert := args.(sessionmanager.SMGenericEvent) if !canConvert { return rpcclient.ErrWrongArgsType @@ -152,8 +152,8 @@ func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply inte if !canConvert { return rpcclient.ErrWrongReplyType } - self.GetMaxUsage(argsConverted, replyConverted) - case "SMGenericV1.GetLcrSuppliers": + self.MaxUsage(argsConverted, replyConverted) + case "SMGenericV1.LCRSuppliers": argsConverted, canConvert := args.(sessionmanager.SMGenericEvent) if !canConvert { return rpcclient.ErrWrongArgsType @@ -162,8 +162,8 @@ func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply inte if !canConvert { return rpcclient.ErrWrongReplyType } - return self.GetLcrSuppliers(argsConverted, replyConverted) - case "SMGenericV1.SessionStart": + return self.LCRSuppliers(argsConverted, replyConverted) + case "SMGenericV1.InitiateSession": argsConverted, canConvert := args.(sessionmanager.SMGenericEvent) if !canConvert { return rpcclient.ErrWrongArgsType @@ -172,8 +172,8 @@ func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply inte if !canConvert { return rpcclient.ErrWrongReplyType } - return self.SessionStart(argsConverted, replyConverted) - case "SMGenericV1.SessionUpdate": + return self.InitiateSession(argsConverted, replyConverted) + case "SMGenericV1.UpdateSession": argsConverted, canConvert := args.(sessionmanager.SMGenericEvent) if !canConvert { return rpcclient.ErrWrongArgsType @@ -182,8 +182,8 @@ func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply inte if !canConvert { return rpcclient.ErrWrongReplyType } - return self.SessionUpdate(argsConverted, replyConverted) - case "SMGenericV1.SessionEnd": + return self.UpdateSession(argsConverted, replyConverted) + case "SMGenericV1.TerminateSession": argsConverted, canConvert := args.(sessionmanager.SMGenericEvent) if !canConvert { return rpcclient.ErrWrongArgsType @@ -192,7 +192,7 @@ func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply inte if !canConvert { return rpcclient.ErrWrongReplyType } - return self.SessionEnd(argsConverted, replyConverted) + return self.TerminateSession(argsConverted, replyConverted) case "SMGenericV1.ChargeEvent": argsConverted, canConvert := args.(sessionmanager.SMGenericEvent) if !canConvert { @@ -203,7 +203,7 @@ func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply inte return rpcclient.ErrWrongReplyType } return self.ChargeEvent(argsConverted, replyConverted) - case "SMGenericV1.ProcessCdr": + case "SMGenericV1.ProcessCDR": argsConverted, canConvert := args.(sessionmanager.SMGenericEvent) if !canConvert { return rpcclient.ErrWrongArgsType @@ -212,7 +212,7 @@ func (self *SMGenericV1) Call(serviceMethod string, args interface{}, reply inte if !canConvert { return rpcclient.ErrWrongReplyType } - return self.ProcessCdr(argsConverted, replyConverted) + return self.ProcessCDR(argsConverted, replyConverted) case "SMGenericV1.ActiveSessions": argsConverted, canConvert := args.(utils.AttrSMGGetActiveSessions) if !canConvert { diff --git a/apier/v1/smgenericv1_it_test.go b/apier/v1/smgenericv1_it_test.go index 17da136f8..f1cc270d0 100644 --- a/apier/v1/smgenericv1_it_test.go +++ b/apier/v1/smgenericv1_it_test.go @@ -149,7 +149,7 @@ func TestSMGV1GetMaxUsage(t *testing.T) { setupReq := &sessionmanager.SMGenericEvent{utils.REQTYPE: utils.META_PREPAID, utils.TENANT: "cgrates.org", utils.ACCOUNT: "1003", utils.DESTINATION: "1002", utils.SETUP_TIME: "2015-11-10T15:20:00Z"} var maxTime float64 - if err := smgV1Rpc.Call("SMGenericV1.GetMaxUsage", setupReq, &maxTime); err != nil { + if err := smgV1Rpc.Call("SMGenericV1.MaxUsage", setupReq, &maxTime); err != nil { t.Error(err) } else if maxTime != 2700 { t.Errorf("Calling ApierV2.MaxUsage got maxTime: %f", maxTime) diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go index ee73c7f38..9f7633780 100644 --- a/sessionmanager/data_it_test.go +++ b/sessionmanager/data_it_test.go @@ -109,7 +109,7 @@ func TestSMGDataLastUsedData(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -137,7 +137,7 @@ func TestSMGDataLastUsedData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -165,7 +165,7 @@ func TestSMGDataLastUsedData(t *testing.T) { utils.LastUsed: "0", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 49999979520.000000 //20480 @@ -204,7 +204,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -236,7 +236,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -267,7 +267,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -298,7 +298,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -329,7 +329,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -360,7 +360,7 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) { utils.LastUsed: "0", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 49999897600.000000 @@ -404,7 +404,7 @@ func TestSMGDataDerivedChargingNoCredit(t *testing.T) { utils.USAGE: "100", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } // the second derived charging run has no credit @@ -448,7 +448,7 @@ func TestSMGDataTTLExpired(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -497,7 +497,7 @@ func TestSMGDataTTLExpiredMultiUpdates(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -530,7 +530,7 @@ func TestSMGDataTTLExpiredMultiUpdates(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "20000", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -585,7 +585,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -617,7 +617,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -648,7 +648,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -679,7 +679,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -710,7 +710,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "0", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -741,7 +741,7 @@ func TestSMGDataMultipleDataNoUsage(t *testing.T) { utils.LastUsed: "0", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 49997767680.000000 // refunded @@ -785,7 +785,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -818,7 +818,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -849,7 +849,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -880,7 +880,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -911,7 +911,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.USAGE: "1048576", utils.LastUsed: "600", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 1.048576e+06 { @@ -942,7 +942,7 @@ func TestSMGDataMultipleDataConstantUsage(t *testing.T) { utils.LastUsed: "0", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 49997757440.000000 // 10240 (from the start) diff --git a/sessionmanager/smg_it_test.go b/sessionmanager/smg_it_test.go index b14e4adf0..1ae469fbf 100644 --- a/sessionmanager/smg_it_test.go +++ b/sessionmanager/smg_it_test.go @@ -130,7 +130,7 @@ func TestSMGVoiceMonetaryRefund(t *testing.T) { utils.USAGE: "1m30s", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 90 { @@ -160,7 +160,7 @@ func TestSMGVoiceMonetaryRefund(t *testing.T) { utils.USAGE: "1m", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 8.8 @@ -191,7 +191,7 @@ func TestSMGVoiceVoiceRefund(t *testing.T) { utils.USAGE: "1m30s", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 90 { @@ -221,7 +221,7 @@ func TestSMGVoiceVoiceRefund(t *testing.T) { utils.USAGE: "1m", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 150.0 @@ -259,7 +259,7 @@ func TestSMGVoiceMixedRefund(t *testing.T) { utils.USAGE: "1m30s", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 90 { @@ -291,7 +291,7 @@ func TestSMGVoiceMixedRefund(t *testing.T) { utils.USAGE: "1m", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eVoiceVal = 90.0 @@ -334,7 +334,7 @@ func TestSMGVoiceLastUsed(t *testing.T) { utils.USAGE: "2m", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -360,7 +360,7 @@ func TestSMGVoiceLastUsed(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "1m30s", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -386,7 +386,7 @@ func TestSMGVoiceLastUsed(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "2m30s", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -412,7 +412,7 @@ func TestSMGVoiceLastUsed(t *testing.T) { utils.USAGE: "1m", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 7.59 @@ -451,7 +451,7 @@ func TestSMGVoiceLastUsedEnd(t *testing.T) { utils.USAGE: "2m", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -477,7 +477,7 @@ func TestSMGVoiceLastUsedEnd(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "30s", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -503,7 +503,7 @@ func TestSMGVoiceLastUsedEnd(t *testing.T) { utils.LastUsed: "0s", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 6.590000 @@ -542,7 +542,7 @@ func TestSMGVoiceLastUsedNotFixed(t *testing.T) { utils.USAGE: "2m", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -568,7 +568,7 @@ func TestSMGVoiceLastUsedNotFixed(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "13s", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -594,7 +594,7 @@ func TestSMGVoiceLastUsedNotFixed(t *testing.T) { utils.LastUsed: "0s", } var rpl string - if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK { + if err = smgRPC.Call("SMGenericV1.TerminateSession", smgEv, &rpl); err != nil || rpl != utils.OK { t.Error(err) } eAcntVal = 5.590000 @@ -633,7 +633,7 @@ func TestSMGVoiceSessionTTL(t *testing.T) { utils.USAGE: "2m", } var maxUsage float64 - if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { @@ -667,7 +667,7 @@ func TestSMGVoiceSessionTTL(t *testing.T) { utils.USAGE: "2m", utils.LastUsed: "30s", } - if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil { + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { t.Error(err) } if maxUsage != 120 { diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index eb4873bd8..005750af1 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -258,7 +258,7 @@ func (self *SMGeneric) sessionRelocate(sessionID, initialID string) error { // Methods to apply on sessions, mostly exported through RPC/Bi-RPC //Calculates maximum usage allowed for gevent -func (self *SMGeneric) GetMaxUsage(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { +func (self *SMGeneric) MaxUsage(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { gev[utils.EVENT_NAME] = utils.CGR_AUTHORIZATION storedCdr := gev.AsStoredCdr(config.CgrConfig(), self.timezone) var maxDur float64 @@ -268,7 +268,7 @@ func (self *SMGeneric) GetMaxUsage(gev SMGenericEvent, clnt *rpc2.Client) (time. return time.Duration(maxDur), nil } -func (self *SMGeneric) GetLcrSuppliers(gev SMGenericEvent, clnt *rpc2.Client) ([]string, error) { +func (self *SMGeneric) LCRSuppliers(gev SMGenericEvent, clnt *rpc2.Client) ([]string, error) { gev[utils.EVENT_NAME] = utils.CGR_LCR_REQUEST cd, err := gev.AsLcrRequest().AsCallDescriptor(self.timezone) cd.CgrID = gev.GetCgrId(self.timezone) @@ -287,12 +287,12 @@ func (self *SMGeneric) GetLcrSuppliers(gev SMGenericEvent, clnt *rpc2.Client) ([ } // Called on session start -func (self *SMGeneric) SessionStart(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { +func (self *SMGeneric) InitiateSession(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { if err := self.sessionStart(gev, getClientConnId(clnt)); err != nil { self.sessionEnd(gev.GetUUID(), 0) return nilDuration, err } - d, err := self.SessionUpdate(gev, clnt) + d, err := self.UpdateSession(gev, clnt) if err != nil || d == 0 { self.sessionEnd(gev.GetUUID(), 0) } @@ -300,7 +300,7 @@ func (self *SMGeneric) SessionStart(gev SMGenericEvent, clnt *rpc2.Client) (time } // Execute debits for usage/maxUsage -func (self *SMGeneric) SessionUpdate(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { +func (self *SMGeneric) UpdateSession(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { self.resetTerminatorTimer(gev.GetUUID(), gev.GetSessionTTL(), gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage()) if initialID, err := gev.GetFieldAsString(utils.InitialOriginID); err == nil { err := self.sessionRelocate(gev.GetUUID(), initialID) @@ -342,7 +342,7 @@ func (self *SMGeneric) SessionUpdate(gev SMGenericEvent, clnt *rpc2.Client) (tim } // Called on session end, should stop debit loop -func (self *SMGeneric) SessionEnd(gev SMGenericEvent, clnt *rpc2.Client) error { +func (self *SMGeneric) TerminateSession(gev SMGenericEvent, clnt *rpc2.Client) error { if initialID, err := gev.GetFieldAsString(utils.InitialOriginID); err == nil { err := self.sessionRelocate(gev.GetUUID(), initialID) if err == utils.ErrNotFound { // Session was already relocated, create a new session with this update @@ -488,7 +488,7 @@ func (self *SMGeneric) ChargeEvent(gev SMGenericEvent, clnt *rpc2.Client) (maxDu return maxDur, nil } -func (self *SMGeneric) ProcessCdr(gev SMGenericEvent) error { +func (self *SMGeneric) ProcessCDR(gev SMGenericEvent) error { var reply string if err := self.cdrsrv.Call("CdrsV1.ProcessCdr", gev.AsStoredCdr(self.cgrCfg, self.timezone), &reply); err != nil { return err From d3c3bcc622558440189738830b76513120108b63 Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 5 Jun 2016 15:49:36 +0200 Subject: [PATCH 03/11] SMG - Fix session timeouts in case of session relocation --- apier/v1/accounts.go | 23 +------ console/balance_set.go | 5 +- sessionmanager/smg_it_test.go | 116 ++++++++++++++++++++++++++++++++++ sessionmanager/smgeneric.go | 3 +- utils/apitpdata.go | 19 ++++++ 5 files changed, 141 insertions(+), 25 deletions(-) diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index 620b64c48..0085dec86 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -458,26 +458,7 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st return nil } -type AttrSetBalance struct { - Tenant string - Account string - BalanceType string - BalanceUUID *string - BalanceID *string - Directions *string - Value *float64 - ExpiryTime *string - RatingSubject *string - Categories *string - DestinationIds *string - TimingIds *string - Weight *float64 - SharedGroups *string - Blocker *bool - Disabled *bool -} - -func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error { +func (self *ApierV1) SetBalance(attr *utils.AttrSetBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } @@ -548,7 +529,7 @@ func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error { return nil } -func (self *ApierV1) RemoveBalances(attr *AttrSetBalance, reply *string) error { +func (self *ApierV1) RemoveBalances(attr *utils.AttrSetBalance, reply *string) error { if missing := utils.MissingStructFields(attr, []string{"Tenant", "Account", "BalanceType"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } diff --git a/console/balance_set.go b/console/balance_set.go index bc52e8489..0cbd862e7 100644 --- a/console/balance_set.go +++ b/console/balance_set.go @@ -19,7 +19,6 @@ along with this program. If not, see package console import ( - "github.com/cgrates/cgrates/apier/v1" "github.com/cgrates/cgrates/utils" ) @@ -36,7 +35,7 @@ func init() { type CmdSetBalance struct { name string rpcMethod string - rpcParams *v1.AttrSetBalance + rpcParams *utils.AttrSetBalance *CommandExecuter } @@ -50,7 +49,7 @@ func (self *CmdSetBalance) RpcMethod() string { func (self *CmdSetBalance) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { - self.rpcParams = &v1.AttrSetBalance{BalanceType: utils.MONETARY} + self.rpcParams = &utils.AttrSetBalance{BalanceType: utils.MONETARY} } return self.rpcParams } diff --git a/sessionmanager/smg_it_test.go b/sessionmanager/smg_it_test.go index 1ae469fbf..bf6025dae 100644 --- a/sessionmanager/smg_it_test.go +++ b/sessionmanager/smg_it_test.go @@ -708,3 +708,119 @@ func TestSMGVoiceSessionTTL(t *testing.T) { } } } + +func TestSMGVoiceSessionTTLWithRelocate(t *testing.T) { + if !*testIntegration { + return + } + attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", Account: "TestTTLWithRelocate", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestTTLWithRelocate"), + Value: utils.Float64Pointer(300), RatingSubject: utils.StringPointer("*zero50ms")} + var reply string + if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Received: %s", reply) + } + var acnt *engine.Account + attrs := &utils.AttrGetAccount{Tenant: attrSetBalance.Tenant, Account: attrSetBalance.Account} + eAcntVal := 300.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + smgEv := SMGenericEvent{ + utils.EVENT_NAME: "TEST_EVENT_SESSION_TTL_RELOCATE", + utils.TOR: utils.VOICE, + utils.ACCID: "12361", + utils.DIRECTION: utils.OUT, + utils.ACCOUNT: "TestTTLWithRelocate", + utils.SUBJECT: "TestTTLWithRelocate", + utils.DESTINATION: "1009", + utils.CATEGORY: "call", + utils.TENANT: "cgrates.org", + utils.REQTYPE: utils.META_PREPAID, + utils.SETUP_TIME: "2016-01-05 18:30:49", + utils.ANSWER_TIME: "2016-01-05 18:31:05", + utils.USAGE: "2m", + } + var maxUsage float64 + if err := smgRPC.Call("SMGenericV1.InitiateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 120 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 180.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + var aSessions []*ActiveSession + if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{RunID: utils.StringPointer(utils.META_DEFAULT), OriginID: utils.StringPointer(smgEv.GetUUID())}, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } else if aSessions[0].Usage != time.Duration(120)*time.Second { + t.Errorf("Expecting 2m, received usage: %v", aSessions[0].Usage) + } + smgEv = SMGenericEvent{ + utils.EVENT_NAME: smgEv[utils.EVENT_NAME], + utils.TOR: smgEv[utils.TOR], + utils.InitialOriginID: smgEv[utils.ACCID], + utils.ACCID: "12362", + utils.DIRECTION: smgEv[utils.DIRECTION], + utils.ACCOUNT: smgEv[utils.ACCOUNT], + utils.SUBJECT: smgEv[utils.SUBJECT], + utils.DESTINATION: smgEv[utils.DESTINATION], + utils.CATEGORY: smgEv[utils.CATEGORY], + utils.TENANT: smgEv[utils.TENANT], + utils.REQTYPE: smgEv[utils.REQTYPE], + utils.USAGE: "2m", + utils.LastUsed: "30s", + } + if err := smgRPC.Call("SMGenericV1.UpdateSession", smgEv, &maxUsage); err != nil { + t.Error(err) + } + if maxUsage != 120 { + t.Error("Bad max usage: ", maxUsage) + } + eAcntVal = 150.0 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{RunID: utils.StringPointer(utils.META_DEFAULT), OriginID: utils.StringPointer(smgEv.GetUUID())}, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } else if aSessions[0].Usage != time.Duration(150)*time.Second { + t.Errorf("Expecting 2m30s, received usage: %v", aSessions[0].Usage) + } + time.Sleep(100 * time.Millisecond) + eAcntVal = 149.95 + if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil { + t.Error(err) + } else if acnt.BalanceMap[utils.VOICE].GetTotalValue() != eAcntVal { + t.Errorf("Expecting: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.VOICE].GetTotalValue()) + } + if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{RunID: utils.StringPointer(utils.META_DEFAULT), OriginID: utils.StringPointer(smgEv.GetUUID())}, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 0 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } + var cdrs []*engine.ExternalCDR + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} + if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { + t.Error("Unexpected error: ", err.Error()) + } else if len(cdrs) != 1 { + t.Error("Unexpected number of CDRs returned: ", len(cdrs)) + } else { + if cdrs[0].Usage != "150.05" { + t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) + } + } + +} diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index 005750af1..de1135168 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -246,6 +246,7 @@ func (self *SMGeneric) sessionRelocate(sessionID, initialID string) error { return nil, utils.ErrNotFound } for i, s := range ss { + s.eventStart[utils.ACCID] = sessionID // Overwrite initialSessionID with new one self.indexSession(sessionID, s) if i == 0 { self.unindexSession(initialID) @@ -301,7 +302,6 @@ func (self *SMGeneric) InitiateSession(gev SMGenericEvent, clnt *rpc2.Client) (t // Execute debits for usage/maxUsage func (self *SMGeneric) UpdateSession(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { - self.resetTerminatorTimer(gev.GetUUID(), gev.GetSessionTTL(), gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage()) if initialID, err := gev.GetFieldAsString(utils.InitialOriginID); err == nil { err := self.sessionRelocate(gev.GetUUID(), initialID) if err == utils.ErrNotFound { // Session was already relocated, create a new session with this update @@ -311,6 +311,7 @@ func (self *SMGeneric) UpdateSession(gev SMGenericEvent, clnt *rpc2.Client) (tim return nilDuration, err } } + self.resetTerminatorTimer(gev.GetUUID(), gev.GetSessionTTL(), gev.GetSessionTTLLastUsed(), gev.GetSessionTTLUsage()) var lastUsed *time.Duration evLastUsed, err := gev.GetLastUsed(utils.META_DEFAULT) if err != nil && err != utils.ErrNotFound { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 18bbf5c23..ed9cee7f6 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -1178,3 +1178,22 @@ type AttrRateCDRs struct { SendToStatS *bool // Set to true if the CDRs should be sent to stats server ReplicateCDRs *bool // Replicate results } + +type AttrSetBalance struct { + Tenant string + Account string + BalanceType string + BalanceUUID *string + BalanceID *string + Directions *string + Value *float64 + ExpiryTime *string + RatingSubject *string + Categories *string + DestinationIds *string + TimingIds *string + Weight *float64 + SharedGroups *string + Blocker *bool + Disabled *bool +} From 0bf06880636b97c9c67a1f9daa49b8d5c580e1e3 Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 5 Jun 2016 19:07:12 +0200 Subject: [PATCH 04/11] Revenue protection through Min-/MaxCost filters to GetLCR APIs, fixes #411 --- apier/v1/lcr.go | 4 ++-- engine/calldesc.go | 10 +++++++++- engine/lcr.go | 6 ++++++ engine/lcr_test.go | 4 ++-- engine/responder.go | 3 ++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apier/v1/lcr.go b/apier/v1/lcr.go index 2b3850eef..638f24234 100644 --- a/apier/v1/lcr.go +++ b/apier/v1/lcr.go @@ -32,7 +32,7 @@ func (self *ApierV1) GetLcr(lcrReq engine.LcrRequest, lcrReply *engine.LcrReply) return err } var lcrQried engine.LCRCost - if err := self.Responder.GetLCR(&engine.AttrGetLcr{CallDescriptor: cd, Paginator: lcrReq.Paginator}, &lcrQried); err != nil { + if err := self.Responder.GetLCR(&engine.AttrGetLcr{CallDescriptor: cd, LCRFilter: lcrReq.LCRFilter, Paginator: lcrReq.Paginator}, &lcrQried); err != nil { return utils.NewErrServerError(err) } if lcrQried.Entry == nil { @@ -65,7 +65,7 @@ func (self *ApierV1) GetLcrSuppliers(lcrReq engine.LcrRequest, suppliers *string return err } var lcrQried engine.LCRCost - if err := self.Responder.GetLCR(&engine.AttrGetLcr{CallDescriptor: cd, Paginator: lcrReq.Paginator}, &lcrQried); err != nil { + if err := self.Responder.GetLCR(&engine.AttrGetLcr{CallDescriptor: cd, LCRFilter: lcrReq.LCRFilter, Paginator: lcrReq.Paginator}, &lcrQried); err != nil { return utils.NewErrServerError(err) } if lcrQried.HasErrors() { diff --git a/engine/calldesc.go b/engine/calldesc.go index d62a0005e..0f4097277 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -966,7 +966,7 @@ func (cd *CallDescriptor) GetLCRFromStorage() (*LCR, error) { return nil, utils.ErrNotFound } -func (cd *CallDescriptor) GetLCR(stats rpcclient.RpcClientConnection, p *utils.Paginator) (*LCRCost, error) { +func (cd *CallDescriptor) GetLCR(stats rpcclient.RpcClientConnection, lcrFltr *LCRFilter, p *utils.Paginator) (*LCRCost, error) { cd.account = nil // make sure it's not cached lcr, err := cd.GetLCRFromStorage() if err != nil { @@ -1259,6 +1259,14 @@ func (cd *CallDescriptor) GetLCR(stats rpcclient.RpcClientConnection, p *utils.P }) continue } else { + if lcrFltr != nil { + if lcrFltr.MinCost != nil && cc.Cost < *lcrFltr.MinCost { + continue // MinCost not reached, ignore the supplier + } + if lcrFltr.MaxCost != nil && cc.Cost >= *lcrFltr.MaxCost { + continue // Equal or higher than MaxCost allowed, ignore the supplier + } + } supplCost := &LCRSupplierCost{ Supplier: fullSupplier, Cost: cc.Cost, diff --git a/engine/lcr.go b/engine/lcr.go index 2a50c6003..f3de6183f 100644 --- a/engine/lcr.go +++ b/engine/lcr.go @@ -58,9 +58,15 @@ type LcrRequest struct { Duration string IgnoreErrors bool ExtraFields map[string]string + *LCRFilter *utils.Paginator } +type LCRFilter struct { + MinCost *float64 + MaxCost *float64 +} + func (self *LcrRequest) AsCallDescriptor(timezone string) (*CallDescriptor, error) { if len(self.Account) == 0 || len(self.Destination) == 0 { return nil, utils.ErrMandatoryIeMissing diff --git a/engine/lcr_test.go b/engine/lcr_test.go index 49f201cff..e5a2e5377 100644 --- a/engine/lcr_test.go +++ b/engine/lcr_test.go @@ -204,7 +204,7 @@ func TestLcrGet(t *testing.T) { Account: "rif", Subject: "rif", } - lcr, err := cd.GetLCR(nil, nil) + lcr, err := cd.GetLCR(nil, nil, nil) if err != nil || lcr == nil { t.Errorf("Bad lcr: %+v, %v", lcr, err) } @@ -222,7 +222,7 @@ func TestLcrGetPrefix(t *testing.T) { Account: "rif", Subject: "rifus", } - lcr, err := cd.GetLCR(nil, nil) + lcr, err := cd.GetLCR(nil, nil, nil) if err != nil || lcr == nil { t.Errorf("Bad lcr: %+v, %v", lcr, err) } diff --git a/engine/responder.go b/engine/responder.go index f85daa733..6de7c4d53 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -43,6 +43,7 @@ type SessionRun struct { type AttrGetLcr struct { *CallDescriptor + *LCRFilter *utils.Paginator } @@ -543,7 +544,7 @@ func (rs *Responder) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error { rs.getCache().Cache(cacheKey, &cache2go.CacheItem{Err: err}) return err } - lcrCost, err := attrs.CallDescriptor.GetLCR(rs.Stats, attrs.Paginator) + lcrCost, err := attrs.CallDescriptor.GetLCR(rs.Stats, attrs.LCRFilter, attrs.Paginator) if err != nil { rs.getCache().Cache(cacheKey, &cache2go.CacheItem{Err: err}) return err From eeb9be6174533d207639749595269e8a656f5e31 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 6 Jun 2016 11:45:50 +0200 Subject: [PATCH 05/11] Using *any in tutorial/tariffplan samples --- data/tariffplans/tutorial/RatingPlans.csv | 6 +++--- data/tariffplans/tutorial/Timings.csv | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/data/tariffplans/tutorial/RatingPlans.csv b/data/tariffplans/tutorial/RatingPlans.csv index b983bf4ba..59dc663d7 100644 --- a/data/tariffplans/tutorial/RatingPlans.csv +++ b/data/tariffplans/tutorial/RatingPlans.csv @@ -3,7 +3,7 @@ RP_RETAIL1,DR_FS_40CNT,PEAK,10 RP_RETAIL1,DR_FS_10CNT,OFFPEAK_MORNING,10 RP_RETAIL1,DR_FS_10CNT,OFFPEAK_EVENING,10 RP_RETAIL1,DR_FS_10CNT,OFFPEAK_WEEKEND,10 -RP_RETAIL1,DR_1007_MAXCOST_DISC,ALWAYS,10 +RP_RETAIL1,DR_1007_MAXCOST_DISC,*any,10 RP_RETAIL2,DR_1002_20CNT,PEAK,10 RP_RETAIL2,DR_1003_20CNT,PEAK,10 RP_RETAIL2,DR_FS_40CNT,PEAK,10 @@ -16,6 +16,6 @@ RP_RETAIL2,DR_1003_10CNT,OFFPEAK_WEEKEND,10 RP_RETAIL2,DR_FS_10CNT,OFFPEAK_MORNING,10 RP_RETAIL2,DR_FS_10CNT,OFFPEAK_EVENING,10 RP_RETAIL2,DR_FS_10CNT,OFFPEAK_WEEKEND,10 -RP_RETAIL2,DR_1007_MAXCOST_FREE,ALWAYS,10 -RP_SPECIAL_1002,DR_SPECIAL_1002,ALWAYS,10 +RP_RETAIL2,DR_1007_MAXCOST_FREE,*any,10 +RP_SPECIAL_1002,DR_SPECIAL_1002,*any,10 RP_GENERIC,DR_GENERIC,*any,10 \ No newline at end of file diff --git a/data/tariffplans/tutorial/Timings.csv b/data/tariffplans/tutorial/Timings.csv index d5018f529..5ab820810 100644 --- a/data/tariffplans/tutorial/Timings.csv +++ b/data/tariffplans/tutorial/Timings.csv @@ -1,6 +1,4 @@ #Tag,Years,Months,MonthDays,WeekDays,Time -ALWAYS,*any,*any,*any,*any,00:00:00 -ASAP,*any,*any,*any,*any,*asap PEAK,*any,*any,*any,1;2;3;4;5,08:00:00 OFFPEAK_MORNING,*any,*any,*any,1;2;3;4;5,00:00:00 OFFPEAK_EVENING,*any,*any,*any,1;2;3;4;5,19:00:00 From 81f21e0bc904863925c3ab21a7d23916beac17bb Mon Sep 17 00:00:00 2001 From: Errol Samuels Date: Tue, 7 Jun 2016 12:56:44 +0100 Subject: [PATCH 06/11] Update CONTRIBUTORS.md --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5a7a3d429..bd29f099b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -44,6 +44,7 @@ information, please see the [`CONTRIBUTING.md`](CONTRIBUTING.md) file. | @elfranne | Tom Braarup Cuykens | | @rbarrabe | Régis Barrabé | | @J0hnSteel | John Koce Steel | +| @ewsamuels | Errol Samuels | From db529892563d945a2cb3f0ff843156f3729ae1da Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 9 Jun 2016 15:56:01 +0200 Subject: [PATCH 07/11] CDRE - remove default configuration for FieldID since it makes no sense there --- config/config_defaults.go | 77 +++++++++++++++++---------------- config/config_json_test.go | 79 ++++++++++++++-------------------- data/conf/cgrates/cgrates.json | 74 +++++++++++++++---------------- 3 files changed, 108 insertions(+), 122 deletions(-) diff --git a/config/config_defaults.go b/config/config_defaults.go index 5b1ea8175..a63292c69 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -133,43 +133,6 @@ const CGRATES_CFG_JSON = ` }, -"cdre": { - "*default": { - "cdr_format": "csv", // exported CDRs format - "field_separator": ",", - "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) - "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) - "mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems) - "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) - "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT - "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding - "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) - "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export - "mask_length": 0, // length of the destination suffix to be masked - "export_folder": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed - "header_fields": [], // template of the exported header fields - "content_fields": [ // template of the exported content fields - {"tag": "CGRID", "field_id": "CGRID", "type": "*composed", "value": "CGRID"}, - {"tag":"RunID", "field_id": "RunID", "type": "*composed", "value": "RunID"}, - {"tag":"TOR", "field_id": "ToR", "type": "*composed", "value": "ToR"}, - {"tag":"OriginID", "field_id": "OriginID", "type": "*composed", "value": "OriginID"}, - {"tag":"RequestType", "field_id": "RequestType", "type": "*composed", "value": "RequestType"}, - {"tag":"Direction", "field_id": "Direction", "type": "*composed", "value": "Direction"}, - {"tag":"Tenant", "field_id": "Tenant", "type": "*composed", "value": "Tenant"}, - {"tag":"Category", "field_id": "Category", "type": "*composed", "value": "Category"}, - {"tag":"Account", "field_id": "Account", "type": "*composed", "value": "Account"}, - {"tag":"Subject", "field_id": "Subject", "type": "*composed", "value": "Subject"}, - {"tag":"Destination", "field_id": "Destination", "type": "*composed", "value": "Destination"}, - {"tag":"SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"}, - {"tag":"AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"}, - {"tag":"Usage", "field_id": "Usage", "type": "*composed", "value": "Usage"}, - {"tag":"Cost", "field_id": "Cost", "type": "*composed", "value": "Cost"}, - ], - "trailer_fields": [], // template of the exported trailer fields - } -}, - - "cdrc": [ { "id": "*default", // identifier of the CDRC runner @@ -187,7 +150,7 @@ const CGRATES_CFG_JSON = ` "cdr_in_dir": "/var/log/cgrates/cdrc/in", // absolute path towards the directory where the CDRs are stored "cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved "failed_calls_prefix": "missed_calls", // used in case of flatstore CDRs to avoid searching for BYE records - "cdr_path": "", // path towards one CDR element in case of XML CDRs + "cdr_path": "", // path towards one CDR element in case of XML CDRs "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database "cdr_filter": "", // filter CDR records to import "continue_on_success": false, // continue to the next template if executed @@ -211,6 +174,44 @@ const CGRATES_CFG_JSON = ` }, ], + +"cdre": { + "*default": { + "cdr_format": "csv", // exported CDRs format + "field_separator": ",", + "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) + "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) + "mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems) + "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) + "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT + "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding + "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) + "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export + "mask_length": 0, // length of the destination suffix to be masked + "export_folder": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed + "header_fields": [], // template of the exported header fields + "content_fields": [ // template of the exported content fields + {"tag": "CGRID", "type": "*composed", "value": "CGRID"}, + {"tag":"RunID", "type": "*composed", "value": "RunID"}, + {"tag":"TOR", "type": "*composed", "value": "ToR"}, + {"tag":"OriginID", "type": "*composed", "value": "OriginID"}, + {"tag":"RequestType", "type": "*composed", "value": "RequestType"}, + {"tag":"Direction", "type": "*composed", "value": "Direction"}, + {"tag":"Tenant", "type": "*composed", "value": "Tenant"}, + {"tag":"Category", "type": "*composed", "value": "Category"}, + {"tag":"Account", "type": "*composed", "value": "Account"}, + {"tag":"Subject", "type": "*composed", "value": "Subject"}, + {"tag":"Destination", "type": "*composed", "value": "Destination"}, + {"tag":"SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"Usage", "type": "*composed", "value": "Usage"}, + {"tag":"Cost", "type": "*composed", "value": "Cost"}, + ], + "trailer_fields": [], // template of the exported trailer fields + }, +}, + + "sm_generic": { "enabled": false, // starts SessionManager service: "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests diff --git a/config/config_json_test.go b/config/config_json_test.go index 2d84fe02f..dc0070849 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -188,67 +188,52 @@ func TestDfCdreJsonCfgs(t *testing.T) { eFields := []*CdrFieldJsonCfg{} eContentFlds := []*CdrFieldJsonCfg{ &CdrFieldJsonCfg{Tag: utils.StringPointer("CGRID"), - Field_id: utils.StringPointer(utils.CGRID), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.CGRID)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.CGRID)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("RunID"), - Field_id: utils.StringPointer(utils.MEDI_RUNID), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.MEDI_RUNID)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.MEDI_RUNID)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), - Field_id: utils.StringPointer(utils.TOR), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.TOR)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.TOR)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("OriginID"), - Field_id: utils.StringPointer(utils.ACCID), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.ACCID)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.ACCID)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("RequestType"), - Field_id: utils.StringPointer(utils.REQTYPE), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.REQTYPE)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.REQTYPE)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Direction"), - Field_id: utils.StringPointer(utils.DIRECTION), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.DIRECTION)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.DIRECTION)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Tenant"), - Field_id: utils.StringPointer(utils.TENANT), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.TENANT)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.TENANT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Category"), - Field_id: utils.StringPointer(utils.CATEGORY), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.CATEGORY)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.CATEGORY)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), - Field_id: utils.StringPointer(utils.ACCOUNT), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.ACCOUNT)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.ACCOUNT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), - Field_id: utils.StringPointer(utils.SUBJECT), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.SUBJECT)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.SUBJECT)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), - Field_id: utils.StringPointer(utils.DESTINATION), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.DESTINATION)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.DESTINATION)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), - Field_id: utils.StringPointer(utils.SETUP_TIME), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.SETUP_TIME), - Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.SETUP_TIME), + Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, &CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"), - Field_id: utils.StringPointer(utils.ANSWER_TIME), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.ANSWER_TIME), - Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.ANSWER_TIME), + Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"), - Field_id: utils.StringPointer(utils.USAGE), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.USAGE)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.USAGE)}, &CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"), - Field_id: utils.StringPointer(utils.COST), - Type: utils.StringPointer(utils.META_COMPOSED), - Value: utils.StringPointer(utils.COST)}, + Type: utils.StringPointer(utils.META_COMPOSED), + Value: utils.StringPointer(utils.COST)}, } eCfg := map[string]*CdreJsonCfg{ utils.META_DEFAULT: &CdreJsonCfg{ diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index 53e3e8910..65ee76346 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -112,43 +112,6 @@ // }, -// "cdre": { -// "*default": { -// "cdr_format": "csv", // exported CDRs format -// "field_separator": ",", -// "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) -// "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) -// "mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems) -// "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) -// "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT -// "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding -// "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) -// "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export -// "mask_length": 0, // length of the destination suffix to be masked -// "export_folder": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed -// "header_fields": [], // template of the exported header fields -// "content_fields": [ // template of the exported content fields -// {"tag": "CGRID", "field_id": "CGRID", "type": "*composed", "value": "CGRID"}, -// {"tag":"RunID", "field_id": "RunID", "type": "*composed", "value": "RunID"}, -// {"tag":"TOR", "field_id": "ToR", "type": "*composed", "value": "ToR"}, -// {"tag":"OriginID", "field_id": "OriginID", "type": "*composed", "value": "OriginID"}, -// {"tag":"RequestType", "field_id": "RequestType", "type": "*composed", "value": "RequestType"}, -// {"tag":"Direction", "field_id": "Direction", "type": "*composed", "value": "Direction"}, -// {"tag":"Tenant", "field_id": "Tenant", "type": "*composed", "value": "Tenant"}, -// {"tag":"Category", "field_id": "Category", "type": "*composed", "value": "Category"}, -// {"tag":"Account", "field_id": "Account", "type": "*composed", "value": "Account"}, -// {"tag":"Subject", "field_id": "Subject", "type": "*composed", "value": "Subject"}, -// {"tag":"Destination", "field_id": "Destination", "type": "*composed", "value": "Destination"}, -// {"tag":"SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"}, -// {"tag":"AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"}, -// {"tag":"Usage", "field_id": "Usage", "type": "*composed", "value": "Usage"}, -// {"tag":"Cost", "field_id": "Cost", "type": "*composed", "value": "Cost"}, -// ], -// "trailer_fields": [], // template of the exported trailer fields -// } -// }, - - // "cdrc": [ // { // "id": "*default", // identifier of the CDRC runner @@ -191,6 +154,43 @@ // ], +// "cdre": { +// "*default": { +// "cdr_format": "csv", // exported CDRs format +// "field_separator": ",", +// "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) +// "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) +// "mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems) +// "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) +// "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT +// "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding +// "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) +// "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export +// "mask_length": 0, // length of the destination suffix to be masked +// "export_folder": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed +// "header_fields": [], // template of the exported header fields +// "content_fields": [ // template of the exported content fields +// {"tag": "CGRID", "type": "*composed", "value": "CGRID"}, +// {"tag":"RunID", "type": "*composed", "value": "RunID"}, +// {"tag":"TOR", "type": "*composed", "value": "ToR"}, +// {"tag":"OriginID", "type": "*composed", "value": "OriginID"}, +// {"tag":"RequestType", "type": "*composed", "value": "RequestType"}, +// {"tag":"Direction", "type": "*composed", "value": "Direction"}, +// {"tag":"Tenant", "type": "*composed", "value": "Tenant"}, +// {"tag":"Category", "type": "*composed", "value": "Category"}, +// {"tag":"Account", "type": "*composed", "value": "Account"}, +// {"tag":"Subject", "type": "*composed", "value": "Subject"}, +// {"tag":"Destination", "type": "*composed", "value": "Destination"}, +// {"tag":"SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"}, +// {"tag":"AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"}, +// {"tag":"Usage", "type": "*composed", "value": "Usage"}, +// {"tag":"Cost", "type": "*composed", "value": "Cost"}, +// ], +// "trailer_fields": [], // template of the exported trailer fields +// }, +// }, + + // "sm_generic": { // "enabled": false, // starts SessionManager service: // "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests From 0229e47bb079d07e721f8754ba0d2f71575842de Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 9 Jun 2016 20:57:44 +0200 Subject: [PATCH 08/11] Initial apierv2/tp_it_test file --- apier/v2/tp_it_test.go | 100 ++++++++++++++++++ data/conf/samples/tutmongo/cgrates.json | 71 +++++++++++++ .../{tutlocal => tutmysql}/cgrates.json | 0 data/conf/samples/tutpostgres/cgrates.json | 56 ++++++++++ general_tests/dest_management_it_test.go | 2 +- general_tests/tp_it_test.go | 2 +- general_tests/tutorial_local_test.go | 2 +- 7 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 apier/v2/tp_it_test.go create mode 100644 data/conf/samples/tutmongo/cgrates.json rename data/conf/samples/{tutlocal => tutmysql}/cgrates.json (100%) create mode 100644 data/conf/samples/tutpostgres/cgrates.json diff --git a/apier/v2/tp_it_test.go b/apier/v2/tp_it_test.go new file mode 100644 index 000000000..805e56c79 --- /dev/null +++ b/apier/v2/tp_it_test.go @@ -0,0 +1,100 @@ +/* +Real-time Charging System for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can Storagetribute 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 WITH*out 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 v2 + +import ( + "flag" + "net/rpc" + "net/rpc/jsonrpc" + "path" + "testing" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +var testIT = flag.Bool("integration", false, "Perform the tests in integration mode, not by default.") +var storDBType = flag.String("stordb_type", utils.MYSQL, "Perform the tests for MongoDB, not by default.") + +var tpCfgPath string +var tpCfg *config.CGRConfig +var tpRPC *rpc.Client + +func TestTPitLoadConfig(t *testing.T) { + if !*testIT { + return + } + var err error + switch *storDBType { + case utils.MYSQL: + tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql") + case utils.POSTGRES: + tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutpostgres") + case utils.MONGO: + tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutmongo") + default: + t.Fatalf("Unsupported stordb_type: %s", *storDBType) + } + if tpCfg, err = config.NewCGRConfigFromFolder(tpCfgPath); err != nil { + t.Error(err) + } +} + +// Remove data in both rating and accounting db +func TestTPitResetDataDb(t *testing.T) { + if !*testIT { + return + } + if err := engine.InitDataDb(tpCfg); err != nil { + t.Fatal(err) + } +} + +// Wipe out the cdr database +func TestTPitResetStorDb(t *testing.T) { + if !*testIT { + return + } + if err := engine.InitStorDb(tpCfg); err != nil { + t.Fatal(err) + } +} + +// Start CGR Engine +func TestTPitStartEngine(t *testing.T) { + if !*testIT { + return + } + if _, err := engine.StopStartEngine(tpCfgPath, *waitRater); err != nil { + t.Fatal(err) + } +} + +// Connect rpc client to rater +func TestTPitRpcConn(t *testing.T) { + if !*testIT { + return + } + var err error + tpRPC, err = jsonrpc.Dial("tcp", tpCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal(err) + } +} diff --git a/data/conf/samples/tutmongo/cgrates.json b/data/conf/samples/tutmongo/cgrates.json new file mode 100644 index 000000000..0e50d9c17 --- /dev/null +++ b/data/conf/samples/tutmongo/cgrates.json @@ -0,0 +1,71 @@ +{ +// CGRateS Configuration file +// +// Used for cgradmin +// Starts rater, scheduler + +"listen": { + "rpc_json": ":2012", // RPC JSON listening address + "rpc_gob": ":2013", // RPC GOB listening address + "http": ":2080", // HTTP listening address +}, + + "tariffplan_db": { // database used to store active tariff plan configuration + "db_type": "mongo", // stor database type to use: + "db_port": 27017, // the port to reach the stordb + "db_name": "tpdb", +}, + + +"data_db": { // database used to store runtime data (eg: accounts, cdr stats) + "db_type": "mongo", // stor database type to use: + "db_port": 27017, // the port to reach the stordb + "db_name": "datadb", +}, + +"stor_db": { + "db_type": "mongo", // stor database type to use: + "db_port": 27017, // the port to reach the stordb + "db_name": "stordb", +}, + + +"rals": { + "enabled": true, // enable Rater service: + "cdrstats_conns": [ + {"address": "*internal"} + ], + "pubsubs_conns": [ + {"address": "*internal"} + ], + "users_conns": [ + {"address": "*internal"} + ], +}, + +"scheduler": { + "enabled": true, // start Scheduler service: +}, + +"cdrs": { + "enabled": true, // start the CDR Server service: + "cdrstats_conns": [ + {"address": "*internal"} + ], +}, + +"cdrstats": { + "enabled": true, // starts the cdrstats service: +}, + +"pubsubs": { + "enabled": true, // starts PubSub service: . +}, + + +"users": { + "enabled": true, // starts User service: . + "indexes": ["Uuid"], // user profile field indexes +}, + +} diff --git a/data/conf/samples/tutlocal/cgrates.json b/data/conf/samples/tutmysql/cgrates.json similarity index 100% rename from data/conf/samples/tutlocal/cgrates.json rename to data/conf/samples/tutmysql/cgrates.json diff --git a/data/conf/samples/tutpostgres/cgrates.json b/data/conf/samples/tutpostgres/cgrates.json new file mode 100644 index 000000000..7f60b4b5d --- /dev/null +++ b/data/conf/samples/tutpostgres/cgrates.json @@ -0,0 +1,56 @@ +{ +// CGRateS Configuration file +// +// Used for cgradmin +// Starts rater, scheduler + +"listen": { + "rpc_json": ":2012", // RPC JSON listening address + "rpc_gob": ":2013", // RPC GOB listening address + "http": ":2080", // HTTP listening address +}, + +"stor_db": { + "db_type": "postgres", // stor database type to use: + "db_port": 5432, // the port to reach the stordb +}, + +"rals": { + "enabled": true, // enable Rater service: + "cdrstats_conns": [ + {"address": "*internal"} + ], + "pubsubs_conns": [ + {"address": "*internal"} + ], + "users_conns": [ + {"address": "*internal"} + ], +}, + +"scheduler": { + "enabled": true, // start Scheduler service: +}, + +"cdrs": { + "enabled": true, // start the CDR Server service: + "cdrstats_conns": [ + {"address": "*internal"} + ], +}, + +"cdrstats": { + "enabled": true, // starts the cdrstats service: +}, + +"pubsubs": { + "enabled": true, // starts PubSub service: . +}, + + +"users": { + "enabled": true, // starts User service: . + "indexes": ["Uuid"], // user profile field indexes +}, + +} diff --git a/general_tests/dest_management_it_test.go b/general_tests/dest_management_it_test.go index c895241a7..eb364f9c4 100644 --- a/general_tests/dest_management_it_test.go +++ b/general_tests/dest_management_it_test.go @@ -22,7 +22,7 @@ func TestDestManagInitCfg(t *testing.T) { if !*testIntegration { return } - destCfgPath = path.Join(*dataDir, "conf", "samples", "tutlocal") + destCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql") // Init config first var err error destCfg, err = config.NewCGRConfigFromFolder(destCfgPath) diff --git a/general_tests/tp_it_test.go b/general_tests/tp_it_test.go index 03bd8c9d8..3e44567e9 100644 --- a/general_tests/tp_it_test.go +++ b/general_tests/tp_it_test.go @@ -23,7 +23,7 @@ func TestTpInitCfg(t *testing.T) { if !*testIntegration { return } - tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutlocal") + tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql") // Init config first var err error tpCfg, err = config.NewCGRConfigFromFolder(tpCfgPath) diff --git a/general_tests/tutorial_local_test.go b/general_tests/tutorial_local_test.go index d57ce2fdd..0f04f18e5 100644 --- a/general_tests/tutorial_local_test.go +++ b/general_tests/tutorial_local_test.go @@ -41,7 +41,7 @@ func TestTutLocalInitCfg(t *testing.T) { if !*testLocal { return } - tutLocalCfgPath = path.Join(*dataDir, "conf", "samples", "tutlocal") + tutLocalCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql") // Init config first var err error tutFsLocalCfg, err = config.NewCGRConfigFromFolder(tutLocalCfgPath) From 8bbb584b5dad7611f0cd59abace5237ca9f0a329 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 13 Jun 2016 17:07:29 +0200 Subject: [PATCH 09/11] Adding ApierV2 TPTimings tests for various dbs --- apier/v2/tp_it_test.go | 135 +++++++++++++++++++++++++++++++++++------ engine/libtest.go | 2 + local_test.sh | 11 +++- utils/consts.go | 10 ++- 4 files changed, 132 insertions(+), 26 deletions(-) diff --git a/apier/v2/tp_it_test.go b/apier/v2/tp_it_test.go index 805e56c79..2998a30fd 100644 --- a/apier/v2/tp_it_test.go +++ b/apier/v2/tp_it_test.go @@ -23,43 +23,45 @@ import ( "net/rpc" "net/rpc/jsonrpc" "path" + "reflect" "testing" + "github.com/cgrates/cgrates/apier/v1" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" ) -var testIT = flag.Bool("integration", false, "Perform the tests in integration mode, not by default.") -var storDBType = flag.String("stordb_type", utils.MYSQL, "Perform the tests for MongoDB, not by default.") +var testTP = flag.Bool("tp", false, "Perform the tests in integration mode, not by default.") +var configDIR = flag.String("config_dir", "tutmysql", "Relative path towards a config directory under samples prefix") var tpCfgPath string var tpCfg *config.CGRConfig var tpRPC *rpc.Client +var err error + +var testTPid = "V2TestTPit" +var delay int func TestTPitLoadConfig(t *testing.T) { - if !*testIT { + if !*testTP { return } - var err error - switch *storDBType { - case utils.MYSQL: - tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql") - case utils.POSTGRES: - tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutpostgres") - case utils.MONGO: - tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutmongo") - default: - t.Fatalf("Unsupported stordb_type: %s", *storDBType) - } + tpCfgPath = path.Join(*dataDir, "conf", "samples", *configDIR) if tpCfg, err = config.NewCGRConfigFromFolder(tpCfgPath); err != nil { t.Error(err) } + switch *configDIR { + case "tutmongo": // Mongo needs more time to reset db, need to investigate + delay = 4000 + default: + delay = *waitRater + } } // Remove data in both rating and accounting db func TestTPitResetDataDb(t *testing.T) { - if !*testIT { + if !*testTP { return } if err := engine.InitDataDb(tpCfg); err != nil { @@ -69,7 +71,7 @@ func TestTPitResetDataDb(t *testing.T) { // Wipe out the cdr database func TestTPitResetStorDb(t *testing.T) { - if !*testIT { + if !*testTP { return } if err := engine.InitStorDb(tpCfg); err != nil { @@ -79,17 +81,17 @@ func TestTPitResetStorDb(t *testing.T) { // Start CGR Engine func TestTPitStartEngine(t *testing.T) { - if !*testIT { + if !*testTP { return } - if _, err := engine.StopStartEngine(tpCfgPath, *waitRater); err != nil { + if _, err := engine.StopStartEngine(tpCfgPath, delay); err != nil { // Mongo requires more time to start t.Fatal(err) } } // Connect rpc client to rater func TestTPitRpcConn(t *testing.T) { - if !*testIT { + if !*testTP { return } var err error @@ -98,3 +100,98 @@ func TestTPitRpcConn(t *testing.T) { t.Fatal(err) } } + +func TestTPitTimings(t *testing.T) { + if !*testTP { + return + } + // PEAK,*any,*any,*any,1;2;3;4;5,08:00:00 + tmPeak := &utils.ApierTPTiming{ + TPid: testTPid, + TimingId: "PEAK", + Years: "*any", + Months: "*any", + MonthDays: "*any", + WeekDays: "1;2;3;4;5", + Time: "08:00:00", + } + // OFFPEAK_MORNING,*any,*any,*any,1;2;3;4;5,00:00:00 + tmOffPeakMorning := &utils.ApierTPTiming{ + TPid: testTPid, + TimingId: "OFFPEAK_MORNING", + Years: "*any", + Months: "*any", + MonthDays: "*any", + WeekDays: "1;2;3;4;5", + Time: "00:00:00", + } + // OFFPEAK_EVENING,*any,*any,*any,1;2;3;4;5,19:00:00 + tmOffPeakEvening := &utils.ApierTPTiming{ + TPid: testTPid, + TimingId: "OFFPEAK_EVENING", + Years: "*any", + Months: "*any", + MonthDays: "*any", + WeekDays: "1;2;3;4;5", + Time: "19:00:00", + } + // OFFPEAK_WEEKEND,*any,*any,*any,6;7,00:00:00 + tmOffPeakWeekend := &utils.ApierTPTiming{ + TPid: testTPid, + TimingId: "OFFPEAK_WEEKEND", + Years: "*any", + Months: "*any", + MonthDays: "*any", + WeekDays: "6;7", + Time: "00:00:00", + } + // DUMMY, only used for the purpose of testing remove function + tmDummyRemove := &utils.ApierTPTiming{ + TPid: testTPid, + TimingId: "DUMMY_REMOVE", + Years: "*any", + Months: "*any", + MonthDays: "*any", + WeekDays: "*any", + Time: "01:00:00", + } + // Test set + reply := "" + for _, tm := range []*utils.ApierTPTiming{tmPeak, tmOffPeakMorning, tmOffPeakEvening, tmOffPeakWeekend, tmDummyRemove} { + if err := tpRPC.Call("ApierV2.SetTPTiming", tm, &reply); err != nil { + t.Error("Got error on ApierV2.SetTPTiming: ", err.Error()) + } else if reply != utils.OK { + t.Error("Unexpected reply received when calling ApierV2.SetTPTiming: ", reply) + } + } + // Test get + var rplyTmDummy *utils.ApierTPTiming + if err := tpRPC.Call("ApierV2.GetTPTiming", v1.AttrGetTPTiming{tmDummyRemove.TPid, tmDummyRemove.TimingId}, &rplyTmDummy); err != nil { + t.Error("Calling ApierV2.GetTPTiming, got error: ", err.Error()) + } else if !reflect.DeepEqual(tmDummyRemove, rplyTmDummy) { + t.Errorf("Calling ApierV2.GetTPTiming expected: %v, received: %v", tmDummyRemove, rplyTmDummy) + } + // Test remove + if err := tpRPC.Call("ApierV2.RemTPTiming", v1.AttrGetTPTiming{tmDummyRemove.TPid, tmDummyRemove.TimingId}, &reply); err != nil { + t.Error("Calling ApierV2.RemTPTiming, got error: ", err.Error()) + } else if reply != utils.OK { + t.Error("Calling ApierV2.RemTPTiming received: ", reply) + } + // Test getIds + var rplyTmIDs []string + expectedTmIDs := []string{"OFFPEAK_EVENING", "OFFPEAK_MORNING", "OFFPEAK_WEEKEND", "PEAK"} + if err := tpRPC.Call("ApierV1.GetTPTimingIds", v1.AttrGetTPTimingIds{testTPid, utils.Paginator{}}, &rplyTmIDs); err != nil { + t.Error("Calling ApierV1.GetTPTimingIds, got error: ", err.Error()) + } else if len(expectedTmIDs) != len(rplyTmIDs) { + t.Errorf("Calling ApierV1.GetTPTimingIds expected: %v, received: %v", expectedTmIDs, rplyTmIDs) + } +} + +func TestTPitKillEngine(t *testing.T) { + if !*testTP { + return + } + if err := engine.KillEngine(delay); err != nil { + t.Error(err) + } +} diff --git a/engine/libtest.go b/engine/libtest.go index f45288566..59f904091 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -71,9 +71,11 @@ func StartEngine(cfgPath string, waitEngine int) (*exec.Cmd, error) { return nil, err } engine := exec.Command(enginePath, "-config_dir", cfgPath) + utils.Logger.Debug(fmt.Sprintf("Before engine.Start(), time: %+v", time.Now())) if err := engine.Start(); err != nil { return nil, err } + utils.Logger.Debug(fmt.Sprintf("After engine.Start(), time: %+v", time.Now())) time.Sleep(time.Duration(waitEngine) * time.Millisecond) // Give time to rater to fire up return engine, nil } diff --git a/local_test.sh b/local_test.sh index 05577d629..6ead276dc 100755 --- a/local_test.sh +++ b/local_test.sh @@ -7,6 +7,15 @@ ap1=$? echo 'go test github.com/cgrates/cgrates/apier/v2 -local' go test github.com/cgrates/cgrates/apier/v2 -local ap2=$? +echo 'go test github.com/cgrates/cgrates/apier/v2 -tp -config_dir=tutmysql' +go test github.com/cgrates/cgrates/apier/v2 -tp -config_dir=tutmysql +tpmysql=$? +echo 'go test github.com/cgrates/cgrates/apier/v2 -tp -config_dir=tutpostgres' +go test github.com/cgrates/cgrates/apier/v2 -tp -config_dir=tutpostgres +tppg=$? +echo 'go test github.com/cgrates/cgrates/apier/v2 -tp -config_dir=tutmongo' +go test github.com/cgrates/cgrates/apier/v2 -tp -config_dir=tutmongo +tpmongo=$? echo 'go test github.com/cgrates/cgrates/engine -local -integration' go test github.com/cgrates/cgrates/engine -local -integration en=$? @@ -29,4 +38,4 @@ echo 'go test github.com/cgrates/cgrates/sessionmanager -integration' go test github.com/cgrates/cgrates/sessionmanager -integration smg=$? -exit $gen && $ap1 && $ap2 && $en && $cdrc && $cfg && $utl && $gnr && $agts && $smg +exit $gen && $ap1 && $ap2 && $tpmysql && $tppg && $tpmongo && $en && $cdrc && $cfg && $utl && $gnr && $agts && $smg diff --git a/utils/consts.go b/utils/consts.go index 087194491..3b2edf4f7 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -32,6 +32,10 @@ var ( ErrUserNotFound = errors.New("USER_NOT_FOUND") ErrInsufficientCredit = errors.New("INSUFFICENT_CREDIT") ErrNotConvertible = errors.New("NOT_CONVERTIBLE") + + CdreCdrFormats = []string{CSV, DRYRUN, CDRE_FIXED_WIDTH} + PrimaryCdrFields = []string{CGRID, CDRSOURCE, CDRHOST, ACCID, TOR, REQTYPE, DIRECTION, TENANT, CATEGORY, ACCOUNT, SUBJECT, DESTINATION, SETUP_TIME, PDD, ANSWER_TIME, USAGE, + SUPPLIER, DISCONNECT_CAUSE, COST, RATED} ) const ( @@ -288,9 +292,3 @@ const ( HandlerSubstractUsage = "*substract_usage" XML = "xml" ) - -var ( - CdreCdrFormats = []string{CSV, DRYRUN, CDRE_FIXED_WIDTH} - PrimaryCdrFields = []string{CGRID, CDRSOURCE, CDRHOST, ACCID, TOR, REQTYPE, DIRECTION, TENANT, CATEGORY, ACCOUNT, SUBJECT, DESTINATION, SETUP_TIME, PDD, ANSWER_TIME, USAGE, - SUPPLIER, DISCONNECT_CAUSE, COST, RATED} -) From e6387bbf43f70c14ab3b8af23ac57ae17051e214 Mon Sep 17 00:00:00 2001 From: rbarrabe Date: Tue, 14 Jun 2016 11:51:22 +0200 Subject: [PATCH 10/11] Change mode for mongo connection From Monotonic to Strong --- engine/storage_mongo_datadb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index 1879c3b1e..9d00c226c 100644 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -125,7 +125,7 @@ func NewMongoStorage(host, port, db, user, pass string, cdrsIndexes []string) (* } ndb := session.DB(db) - session.SetMode(mgo.Monotonic, true) + session.SetMode(mgo.Strong, true) index := mgo.Index{ Key: []string{"key"}, Unique: true, // Prevent two documents from having the same index key From 179da9c54e938fdf6d96de914bfa0b8370ae7d74 Mon Sep 17 00:00:00 2001 From: DanB Date: Tue, 14 Jun 2016 16:24:24 +0200 Subject: [PATCH 11/11] Fix caching panic when item has errors --- apier/v2/tp_it_test.go | 2 +- engine/cdrs.go | 4 +++- engine/responder.go | 24 ++++++++++++++++++------ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/apier/v2/tp_it_test.go b/apier/v2/tp_it_test.go index 2998a30fd..b2918fca4 100644 --- a/apier/v2/tp_it_test.go +++ b/apier/v2/tp_it_test.go @@ -32,7 +32,7 @@ import ( "github.com/cgrates/cgrates/utils" ) -var testTP = flag.Bool("tp", false, "Perform the tests in integration mode, not by default.") +var testTP = flag.Bool("tp", false, "Perform the tests for TariffPlans, not by default.") // Separate from integration so we can run on multiple DBs without involving all other tests on each run var configDIR = flag.String("config_dir", "tutmysql", "Relative path towards a config directory under samples prefix") var tpCfgPath string diff --git a/engine/cdrs.go b/engine/cdrs.go index d296df1a0..5dc77035f 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -497,7 +497,9 @@ func (self *CdrServer) RateCDRs(cdrFltr *utils.CDRsFilter, sendToStats bool) err func (self *CdrServer) V1ProcessCDR(cdr *CDR, reply *string) error { cacheKey := "ProcessCdr" + cdr.CGRID if item, err := self.getCache().Get(cacheKey); err == nil && item != nil { - *reply = item.Value.(string) + if item.Value != nil { + *reply = item.Value.(string) + } return item.Err } if err := self.LocalProcessCdr(cdr); err != nil { diff --git a/engine/responder.go b/engine/responder.go index 6de7c4d53..7bfb72cb9 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -150,7 +150,9 @@ func (rs *Responder) Debit(arg *CallDescriptor, reply *CallCost) (err error) { func (rs *Responder) MaxDebit(arg *CallDescriptor, reply *CallCost) (err error) { cacheKey := utils.MAX_DEBIT_CACHE_PREFIX + arg.CgrID + arg.RunID + arg.DurationIndex.String() if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { - *reply = *(item.Value.(*CallCost)) + if item.Value != nil { + *reply = *(item.Value.(*CallCost)) + } return item.Err } if arg.Subject == "" { @@ -198,7 +200,9 @@ func (rs *Responder) MaxDebit(arg *CallDescriptor, reply *CallCost) (err error) func (rs *Responder) RefundIncrements(arg *CallDescriptor, reply *float64) (err error) { cacheKey := utils.REFUND_INCR_CACHE_PREFIX + arg.CgrID + arg.RunID if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { - *reply = *(item.Value.(*float64)) + if item.Value != nil { + *reply = *(item.Value.(*float64)) + } return item.Err } if arg.Subject == "" { @@ -240,7 +244,9 @@ func (rs *Responder) RefundIncrements(arg *CallDescriptor, reply *float64) (err func (rs *Responder) RefundRounding(arg *CallDescriptor, reply *float64) (err error) { cacheKey := utils.REFUND_ROUND_CACHE_PREFIX + arg.CgrID + arg.RunID + arg.DurationIndex.String() if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { - *reply = *(item.Value.(*float64)) + if item.Value != nil { + *reply = *(item.Value.(*float64)) + } return item.Err } if arg.Subject == "" { @@ -317,7 +323,9 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *CDR, reply *float64) error { } cacheKey := utils.GET_DERIV_MAX_SESS_TIME + ev.CGRID + ev.RunID if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { - *reply = *(item.Value.(*float64)) + if item.Value != nil { + *reply = *(item.Value.(*float64)) + } return item.Err } if ev.Subject == "" { @@ -423,7 +431,9 @@ func (rs *Responder) GetSessionRuns(ev *CDR, sRuns *[]*SessionRun) error { } cacheKey := utils.GET_SESS_RUNS_CACHE_PREFIX + ev.CGRID if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { - *sRuns = *(item.Value.(*[]*SessionRun)) + if item.Value != nil { + *sRuns = *(item.Value.(*[]*SessionRun)) + } return item.Err } if ev.Subject == "" { @@ -519,7 +529,9 @@ func (rs *Responder) GetDerivedChargers(attrs *utils.AttrDerivedChargers, dcs *u func (rs *Responder) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error { cacheKey := utils.LCRCachePrefix + attrs.CgrID + attrs.RunID if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { - *reply = *(item.Value.(*LCRCost)) + if item.Value != nil { + *reply = *(item.Value.(*LCRCost)) + } return item.Err } if attrs.CallDescriptor.Subject == "" {