Moving Cdr* from utils to engine package so we can attach CostDetails to StoredCdr

This commit is contained in:
DanB
2015-03-22 18:04:38 +01:00
parent 54e95dc929
commit 44fa456eb5
54 changed files with 870 additions and 844 deletions

View File

@@ -35,14 +35,14 @@ var (
)
// Returns error if not able to properly store the CDR, mediation is async since we can always recover offline
func storeAndMediate(storedCdr *utils.StoredCdr) error {
func storeAndMediate(storedCdr *StoredCdr) error {
if !cfg.CDRSStoreDisable {
if err := storage.SetCdr(storedCdr); err != nil {
return err
}
}
if stats != nil {
go func(storedCdr *utils.StoredCdr) {
go func(storedCdr *StoredCdr) {
if err := stats.AppendCDR(storedCdr, nil); err != nil {
Logger.Err(fmt.Sprintf("<CDRS> Could not append cdr to stats: %s", err.Error()))
}
@@ -52,7 +52,7 @@ func storeAndMediate(storedCdr *utils.StoredCdr) error {
replicateCdr(storedCdr, cfg.CDRSCdrReplication)
}
if cfg.CDRSMediator == utils.INTERNAL {
go func(storedCdr *utils.StoredCdr) {
go func(storedCdr *StoredCdr) {
if err := medi.RateCdr(storedCdr, true); err != nil {
Logger.Err(fmt.Sprintf("<CDRS> Could not run mediation on CDR: %s", err.Error()))
}
@@ -62,13 +62,13 @@ func storeAndMediate(storedCdr *utils.StoredCdr) error {
}
// ToDo: Add websocket support
func replicateCdr(cdr *utils.StoredCdr, replCfgs []*config.CdrReplicationCfg) error {
func replicateCdr(cdr *StoredCdr, replCfgs []*config.CdrReplicationCfg) error {
for _, rplCfg := range replCfgs {
switch rplCfg.Transport {
case utils.META_HTTP_POST:
httpClient := new(http.Client)
errChan := make(chan error)
go func(cdr *utils.StoredCdr, rplCfg *config.CdrReplicationCfg, errChan chan error) {
go func(cdr *StoredCdr, rplCfg *config.CdrReplicationCfg, errChan chan error) {
if _, err := httpClient.PostForm(fmt.Sprintf("http://%s/cdr_post", rplCfg.Server), cdr.AsHttpForm()); err != nil {
Logger.Err(fmt.Sprintf("<CDRReplicator> Replicating CDR: %+v, got error: %s", cdr, err.Error()))
errChan <- err
@@ -85,7 +85,7 @@ func replicateCdr(cdr *utils.StoredCdr, replCfgs []*config.CdrReplicationCfg) er
// Handler for generic cgr cdr http
func cgrCdrHandler(w http.ResponseWriter, r *http.Request) {
cgrCdr, err := utils.NewCgrCdrFromHttpReq(r)
cgrCdr, err := NewCgrCdrFromHttpReq(r)
if err != nil {
Logger.Err(fmt.Sprintf("<CDRS> Could not create CDR entry: %s", err.Error()))
}
@@ -134,6 +134,6 @@ func (cdrs *CDRS) RegisterHanlersToServer(server *Server) {
}
// Used to internally process CDR
func (cdrs *CDRS) ProcessCdr(cdr *utils.StoredCdr) error {
func (cdrs *CDRS) ProcessCdr(cdr *StoredCdr) error {
return storeAndMediate(cdr)
}

View File

@@ -90,7 +90,7 @@ func TestCdrsHttpJsonRpcCdrReplication(t *testing.T) {
if err != nil {
t.Fatal("Could not connect to rater: ", err.Error())
}
testCdr1 := &utils.StoredCdr{CgrId: utils.Sha1("httpjsonrpc1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()),
testCdr1 := &StoredCdr{CgrId: utils.Sha1("httpjsonrpc1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()),
TOR: utils.VOICE, AccId: "httpjsonrpc1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_PSEUDOPREPAID,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
@@ -102,7 +102,7 @@ func TestCdrsHttpJsonRpcCdrReplication(t *testing.T) {
} else if reply != utils.OK {
t.Error("Unexpected reply received: ", reply)
}
var rcvedCdrs []*utils.CgrExtCdr
var rcvedCdrs []*CgrExtCdr
if err := cdrsHttpJsonRpc.Call("ApierV2.GetCdrs", utils.RpcCdrsFilter{CgrIds: []string{testCdr1.CgrId}}, &rcvedCdrs); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if len(rcvedCdrs) != 1 {
@@ -111,7 +111,7 @@ func TestCdrsHttpJsonRpcCdrReplication(t *testing.T) {
}
/*
&utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
&StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,

View File

@@ -75,7 +75,7 @@ type CdrStats struct {
Triggers ActionTriggerPriotityList
}
func (cs *CdrStats) AcceptCdr(cdr *utils.StoredCdr) bool {
func (cs *CdrStats) AcceptCdr(cdr *StoredCdr) bool {
if cdr == nil {
return false
}

77
engine/cgrcdr.go Normal file
View File

@@ -0,0 +1,77 @@
/*
Rating system designed to be used in VoIP Carriers World
Copyright (C) 2012-2015 ITsysCOM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
import (
"github.com/cgrates/cgrates/utils"
"net/http"
)
func NewCgrCdrFromHttpReq(req *http.Request) (CgrCdr, error) {
if req.Form == nil {
if err := req.ParseForm(); err != nil {
return nil, err
}
}
cgrCdr := make(CgrCdr)
cgrCdr[utils.CDRHOST] = req.RemoteAddr
for k, vals := range req.Form {
cgrCdr[k] = vals[0] // We only support the first value for now, if more are provided it is considered remote's fault
}
return cgrCdr, nil
}
type CgrCdr map[string]string
func (cgrCdr CgrCdr) getCgrId() string {
setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME])
return utils.Sha1(cgrCdr[utils.ACCID], setupTime.UTC().String())
}
func (cgrCdr CgrCdr) getExtraFields() map[string]string {
extraFields := make(map[string]string)
for k, v := range cgrCdr {
if !utils.IsSliceMember(utils.PrimaryCdrFields, k) {
extraFields[k] = v
}
}
return extraFields
}
func (cgrCdr CgrCdr) AsStoredCdr() *StoredCdr {
storCdr := new(StoredCdr)
storCdr.CgrId = cgrCdr.getCgrId()
storCdr.TOR = cgrCdr[utils.TOR]
storCdr.AccId = cgrCdr[utils.ACCID]
storCdr.CdrHost = cgrCdr[utils.CDRHOST]
storCdr.CdrSource = cgrCdr[utils.CDRSOURCE]
storCdr.ReqType = cgrCdr[utils.REQTYPE]
storCdr.Direction = "*out"
storCdr.Tenant = cgrCdr[utils.TENANT]
storCdr.Category = cgrCdr[utils.CATEGORY]
storCdr.Account = cgrCdr[utils.ACCOUNT]
storCdr.Subject = cgrCdr[utils.SUBJECT]
storCdr.Destination = cgrCdr[utils.DESTINATION]
storCdr.SetupTime, _ = utils.ParseTimeDetectLayout(cgrCdr[utils.SETUP_TIME]) // Not interested to process errors, should do them if necessary in a previous step
storCdr.AnswerTime, _ = utils.ParseTimeDetectLayout(cgrCdr[utils.ANSWER_TIME])
storCdr.Usage, _ = utils.ParseDurationWithSecs(cgrCdr[utils.USAGE])
storCdr.ExtraFields = cgrCdr.getExtraFields()
storCdr.Cost = -1
return storCdr
}

53
engine/cgrcdr_test.go Normal file
View File

@@ -0,0 +1,53 @@
/*
Rating system designed to be used in VoIP Carriers World
Copyright (C) 2012-2015 ITsysCOM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
import (
"github.com/cgrates/cgrates/utils"
"reflect"
"testing"
"time"
)
/*
curl --data "accid=asbfdsaf&cdrhost=192.168.1.1&reqtype=rated&direction=*out&tenant=cgrates.org&tor=call&account=1001&subject=1001&destination=1002&time_answer=1383813746&duration=10&field_extr1=val_extr1&fieldextr2=valextr2" http://ipbxdev:2080/cgr
*/
func TestCgrCdrInterfaces(t *testing.T) {
var _ RawCdr = make(CgrCdr)
}
func TestCgrCdrAsStoredCdr(t *testing.T) {
cgrCdr := CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "dsafdsaf", utils.CDRHOST: "192.168.1.1", utils.CDRSOURCE: "internal_test", utils.REQTYPE: utils.META_RATED,
utils.DIRECTION: utils.OUT,
utils.TENANT: "cgrates.org", utils.CATEGORY: "call",
utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-07T08:42:20Z", utils.ANSWER_TIME: "2013-11-07T08:42:26Z",
utils.USAGE: "10",
"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr["setup_time"])
expctRtCdr := &StoredCdr{CgrId: utils.Sha1(cgrCdr["accid"], setupTime.String()), TOR: utils.VOICE, AccId: cgrCdr["accid"], CdrHost: cgrCdr["cdrhost"], CdrSource: cgrCdr["cdrsource"],
ReqType: cgrCdr["reqtype"],
Direction: cgrCdr[utils.DIRECTION], Tenant: cgrCdr["tenant"], Category: cgrCdr[utils.CATEGORY], Account: cgrCdr["account"], Subject: cgrCdr["subject"],
Destination: cgrCdr["destination"], SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second,
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: -1}
if storedCdr := cgrCdr.AsStoredCdr(); !reflect.DeepEqual(expctRtCdr, storedCdr) {
t.Errorf("Expecting %v, received: %v", expctRtCdr, storedCdr)
}
}

51
engine/event.go Normal file
View File

@@ -0,0 +1,51 @@
/*
Rating system designed to be used in VoIP Carriers World
Copyright (C) 2012-2015 ITsysCOM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
import (
"github.com/cgrates/cgrates/utils"
"time"
)
type Event interface {
GetName() string
GetCgrId() string
GetUUID() string
GetSessionIds() []string // Returns identifiers needed to control a session (eg disconnect)
GetDirection(string) string
GetSubject(string) string
GetAccount(string) string
GetDestination(string) string
GetCallDestNr(string) string
GetCategory(string) string
GetTenant(string) string
GetReqType(string) string
GetSetupTime(string) (time.Time, error)
GetAnswerTime(string) (time.Time, error)
GetEndTime() (time.Time, error)
GetDuration(string) (time.Duration, error)
GetOriginatorIP(string) string
GetExtraFields() map[string]string
MissingParameter() bool
ParseEventValue(*utils.RSRField) string
PassesFieldFilter(*utils.RSRField) (bool, string)
AsStoredCdr() *StoredCdr
String() string
AsEvent(string) Event
}

View File

@@ -120,8 +120,8 @@ func (fsCdr FSCdr) searchExtraField(field string, body map[string]interface{}) (
return
}
func (fsCdr FSCdr) AsStoredCdr() *utils.StoredCdr {
storCdr := new(utils.StoredCdr)
func (fsCdr FSCdr) AsStoredCdr() *StoredCdr {
storCdr := new(StoredCdr)
storCdr.CgrId = fsCdr.getCgrId()
storCdr.TOR = utils.VOICE
storCdr.AccId = fsCdr.vars[FS_UUID]

File diff suppressed because one or more lines are too long

View File

@@ -47,9 +47,6 @@ var accountDbCsv, accountDbStor, accountDbApier AccountingStorage // Each rating
var storDb LoadStorage
var lCfg *config.CGRConfig
// Arguments received via test command
var testLocal = flag.Bool("local", false, "Perform the tests only on local test environment, not by default.") // This flag will be passed here via "go test -local" args
var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
var tpCsvScenario = flag.String("tp_scenario", "prepaid1centpsec", "Use this scenario folder to import tp csv data from")
// Create connection to ratingDb

View File

@@ -71,7 +71,7 @@ func (self *Mediator) getCostsFromDB(cgrid, runId string) (cc *CallCost, err err
}
// Retrive the cost from engine
func (self *Mediator) getCostFromRater(storedCdr *utils.StoredCdr) (*CallCost, error) {
func (self *Mediator) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) {
cc := &CallCost{}
var err error
if storedCdr.Usage == time.Duration(0) { // failed call, returning empty callcost, no error
@@ -103,7 +103,7 @@ func (self *Mediator) getCostFromRater(storedCdr *utils.StoredCdr) (*CallCost, e
return cc, err
}
func (self *Mediator) rateCDR(storedCdr *utils.StoredCdr) error {
func (self *Mediator) rateCDR(storedCdr *StoredCdr) error {
var qryCC *CallCost
var errCost error
if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, storedCdr.ReqType) { // ToDo: Get rid of PREPAID as soon as we don't want to support it backwards
@@ -121,9 +121,9 @@ func (self *Mediator) rateCDR(storedCdr *utils.StoredCdr) error {
return nil
}
func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr, sendToStats bool) error {
func (self *Mediator) RateCdr(storedCdr *StoredCdr, sendToStats bool) error {
storedCdr.MediationRunId = utils.META_DEFAULT
cdrRuns := []*utils.StoredCdr{storedCdr} // Start with initial storCdr, will add here all to be mediated
cdrRuns := []*StoredCdr{storedCdr} // Start with initial storCdr, will add here all to be mediated
attrsDC := utils.AttrDerivedChargers{Tenant: storedCdr.Tenant, Category: storedCdr.Category, Direction: storedCdr.Direction,
Account: storedCdr.Account, Subject: storedCdr.Subject}
var dcs utils.DerivedChargers
@@ -157,7 +157,7 @@ func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr, sendToStats bool) erro
forkedCdr, err := storedCdr.ForkCdr(dc.RunId, dcReqTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcATimeFld, dcDurFld,
[]*utils.RSRField{}, true)
if err != nil { // Errors on fork, cannot calculate further, write that into db for later analysis
self.cdrDb.SetRatedCdr(&utils.StoredCdr{CgrId: storedCdr.CgrId, CdrSource: utils.FORKED_CDR, MediationRunId: dc.RunId, Cost: -1},
self.cdrDb.SetRatedCdr(&StoredCdr{CgrId: storedCdr.CgrId, CdrSource: utils.FORKED_CDR, MediationRunId: dc.RunId, Cost: -1},
err.Error()) // Cannot fork CDR, important just runid and error
continue
}
@@ -178,7 +178,7 @@ func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr, sendToStats bool) erro
}
}
if sendToStats && self.stats != nil { // We send to stats only after saving to db since there are chances we cannot store and then no way to reproduce stats offline
go func(cdr *utils.StoredCdr) { // Pass it by value since the variable will be overwritten by for
go func(cdr *StoredCdr) { // Pass it by value since the variable will be overwritten by for
if err := self.stats.AppendCDR(cdr, nil); err != nil {
Logger.Err(fmt.Sprintf("<Mediator> Could not append cdr to stats: %s", err.Error()))
}

View File

@@ -174,13 +174,13 @@ func TestMediInjectCdrs(t *testing.T) {
if !*testLocal {
return
}
cgrCdr1 := utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaaaadsafdsaf", "cdrsource": TEST_SQL, utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out",
cgrCdr1 := CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaaaadsafdsaf", "cdrsource": TEST_SQL, utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out",
utils.TENANT: "cgrates.org", utils.CATEGORY: "call", utils.ACCOUNT: "dan", utils.SUBJECT: "dan", utils.DESTINATION: "+4986517174963",
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "10"}
cgrCdr2 := utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "baaaadsafdsaf", "cdrsource": TEST_SQL, utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out",
cgrCdr2 := CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "baaaadsafdsaf", "cdrsource": TEST_SQL, utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out",
utils.TENANT: "cgrates.org", utils.CATEGORY: "call", utils.ACCOUNT: "dan", utils.SUBJECT: "dan", utils.DESTINATION: "+4986517173964",
utils.ANSWER_TIME: "2013-11-07T09:42:26Z", utils.USAGE: "20"}
for _, cdr := range []utils.CgrCdr{cgrCdr1, cgrCdr2} {
for _, cdr := range []CgrCdr{cgrCdr1, cgrCdr2} {
if err := cdrStor.SetCdr(cdr.AsStoredCdr()); err != nil {
t.Error(err)
}

24
engine/rawcdr.go Normal file
View File

@@ -0,0 +1,24 @@
/*
Rating system designed to be used in VoIP Carriers World
Copyright (C) 2012-2015 ITsysCOM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
// RawCDR is the original CDR received from external sources (eg: FreeSWITCH)
type RawCdr interface {
AsStoredCdr() *StoredCdr // Convert the inbound Cdr into internally used one, CgrCdr
}

View File

@@ -126,7 +126,7 @@ func (rs *Responder) GetMaxSessionTime(arg CallDescriptor, reply *float64) (err
}
// Returns MaxSessionTime for an event received in SessionManager, considering DerivedCharging for it
func (rs *Responder) GetDerivedMaxSessionTime(ev utils.StoredCdr, reply *float64) error {
func (rs *Responder) GetDerivedMaxSessionTime(ev StoredCdr, reply *float64) error {
if rs.Bal != nil {
return errors.New("Unsupported method on the balancer")
}
@@ -184,7 +184,7 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev utils.StoredCdr, reply *float64
}
// Used by SM to get all the prepaid CallDescriptors attached to a session
func (rs *Responder) GetSessionRuns(ev utils.StoredCdr, sRuns *[]*SessionRun) error {
func (rs *Responder) GetSessionRuns(ev StoredCdr, sRuns *[]*SessionRun) error {
if rs.Bal != nil {
return errors.New("Unsupported method on the balancer")
}
@@ -230,7 +230,7 @@ func (rs *Responder) GetDerivedChargers(attrs utils.AttrDerivedChargers, dcs *ut
return nil
}
func (rs *Responder) ProcessCdr(cdr *utils.StoredCdr, reply *string) error {
func (rs *Responder) ProcessCdr(cdr *StoredCdr, reply *string) error {
if rs.CdrSrv == nil {
return errors.New("CDR_SERVER_NOT_RUNNING")
}
@@ -397,9 +397,9 @@ type Connector interface {
RefundIncrements(CallDescriptor, *float64) error
GetMaxSessionTime(CallDescriptor, *float64) error
GetDerivedChargers(utils.AttrDerivedChargers, *utils.DerivedChargers) error
GetDerivedMaxSessionTime(utils.StoredCdr, *float64) error
GetSessionRuns(utils.StoredCdr, *[]*SessionRun) error
ProcessCdr(*utils.StoredCdr, *string) error
GetDerivedMaxSessionTime(StoredCdr, *float64) error
GetSessionRuns(StoredCdr, *[]*SessionRun) error
ProcessCdr(*StoredCdr, *string) error
}
type RPCClientConnector struct {
@@ -426,11 +426,11 @@ func (rcc *RPCClientConnector) GetMaxSessionTime(cd CallDescriptor, resp *float6
return rcc.Client.Call("Responder.GetMaxSessionTime", cd, resp)
}
func (rcc *RPCClientConnector) GetDerivedMaxSessionTime(ev utils.StoredCdr, reply *float64) error {
func (rcc *RPCClientConnector) GetDerivedMaxSessionTime(ev StoredCdr, reply *float64) error {
return rcc.Client.Call("Responder.GetDerivedMaxSessionTime", ev, reply)
}
func (rcc *RPCClientConnector) GetSessionRuns(ev utils.StoredCdr, sRuns *[]*SessionRun) error {
func (rcc *RPCClientConnector) GetSessionRuns(ev StoredCdr, sRuns *[]*SessionRun) error {
return rcc.Client.Call("Responder.GetSessionRuns", ev, sRuns)
}
@@ -438,6 +438,6 @@ func (rcc *RPCClientConnector) GetDerivedChargers(attrs utils.AttrDerivedCharger
return rcc.Client.Call("ApierV1.GetDerivedChargers", attrs, dcs)
}
func (rcc *RPCClientConnector) ProcessCdr(cdr *utils.StoredCdr, reply *string) error {
func (rcc *RPCClientConnector) ProcessCdr(cdr *StoredCdr, reply *string) error {
return rcc.Client.Call("CDRSV1.ProcessCdr", cdr, reply)
}

View File

@@ -56,7 +56,7 @@ func TestResponderGetDerivedChargers(t *testing.T) {
func TestGetDerivedMaxSessionTime(t *testing.T) {
testTenant := "vdf"
cdr := utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
cdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan", Subject: "dan",
Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
@@ -123,7 +123,7 @@ func TestGetDerivedMaxSessionTime(t *testing.T) {
func TestGetSessionRuns(t *testing.T) {
testTenant := "vdf"
cdr := utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
cdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_PREPAID, Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan2", Subject: "dan2",
Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},

View File

@@ -30,7 +30,7 @@ import (
type StatsInterface interface {
GetValues(string, *map[string]float64) error
GetQueueIds(int, *[]string) error
AppendCDR(*utils.StoredCdr, *int) error
AppendCDR(*StoredCdr, *int) error
AddQueue(*CdrStats, *int) error
ReloadQueues([]string, *int) error
ResetQueues([]string, *int) error
@@ -163,7 +163,7 @@ func (s *Stats) UpdateQueues(css []*CdrStats, out *int) error {
return nil
}
func (s *Stats) AppendCDR(cdr *utils.StoredCdr, out *int) error {
func (s *Stats) AppendCDR(cdr *StoredCdr, out *int) error {
s.mux.RLock()
defer s.mux.RUnlock()
for _, sq := range s.queues {
@@ -189,7 +189,7 @@ func (ps *ProxyStats) GetValues(sqID string, values *map[string]float64) error {
return ps.Client.Call("Stats.GetValues", sqID, values)
}
func (ps *ProxyStats) AppendCDR(cdr *utils.StoredCdr, out *int) error {
func (ps *ProxyStats) AppendCDR(cdr *StoredCdr, out *int) error {
return ps.Client.Call("Stats.AppendCDR", cdr, out)
}

View File

@@ -22,8 +22,6 @@ import (
"strings"
"sync"
"time"
"github.com/cgrates/cgrates/utils"
)
type StatsQueue struct {
@@ -72,7 +70,7 @@ func (sq *StatsQueue) UpdateConf(conf *CdrStats) {
}
}
func (sq *StatsQueue) AppendCDR(cdr *utils.StoredCdr) {
func (sq *StatsQueue) AppendCDR(cdr *StoredCdr) {
sq.mux.Lock()
defer sq.mux.Unlock()
if sq.conf.AcceptCdr(cdr) {
@@ -117,7 +115,7 @@ func (sq *StatsQueue) removeFromMetrics(cdr *QCdr) {
}
}
func (sq *StatsQueue) simplifyCdr(cdr *utils.StoredCdr) *QCdr {
func (sq *StatsQueue) simplifyCdr(cdr *StoredCdr) *QCdr {
return &QCdr{
SetupTime: cdr.SetupTime,
AnswerTime: cdr.AnswerTime,

View File

@@ -34,7 +34,7 @@ func TestStatsQueueInit(t *testing.T) {
func TestStatsValue(t *testing.T) {
sq := NewStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, ACC}})
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
Usage: 10 * time.Second,
Cost: 1,
@@ -53,7 +53,7 @@ func TestStatsValue(t *testing.T) {
}
func TestStatsSimplifyCDR(t *testing.T) {
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
TOR: "tor",
AccId: "accid",
CdrHost: "cdrhost",
@@ -82,7 +82,7 @@ func TestStatsSimplifyCDR(t *testing.T) {
func TestAcceptCdr(t *testing.T) {
sq := NewStatsQueue(nil)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
TOR: "tor",
AccId: "accid",
CdrHost: "cdrhost",
@@ -196,7 +196,7 @@ func TestStatsQueueIds(t *testing.T) {
func TestStatsAppendCdr(t *testing.T) {
cdrStats := NewStats(dataStorage)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
@@ -216,7 +216,7 @@ func TestStatsAppendCdr(t *testing.T) {
func TestStatsGetValues(t *testing.T) {
cdrStats := NewStats(dataStorage)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
@@ -225,7 +225,7 @@ func TestStatsGetValues(t *testing.T) {
Cost: 10,
}
cdrStats.AppendCDR(cdr, nil)
cdr = &utils.StoredCdr{
cdr = &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
@@ -245,7 +245,7 @@ func TestStatsGetValues(t *testing.T) {
func TestStatsReloadQueues(t *testing.T) {
cdrStats := NewStats(dataStorage)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
@@ -280,7 +280,7 @@ func TestStatsReloadQueuesWithDefault(t *testing.T) {
cdrStats.AddQueue(&CdrStats{
Id: utils.META_DEFAULT,
}, nil)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
@@ -313,7 +313,7 @@ func TestStatsReloadQueuesWithDefault(t *testing.T) {
func TestStatsReloadQueuesWithIds(t *testing.T) {
cdrStats := NewStats(dataStorage)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
@@ -345,7 +345,7 @@ func TestStatsReloadQueuesWithIds(t *testing.T) {
func TestStatsResetQueues(t *testing.T) {
cdrStats := NewStats(dataStorage)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
@@ -377,7 +377,7 @@ func TestStatsResetQueues(t *testing.T) {
func TestStatsResetQueuesWithIds(t *testing.T) {
cdrStats := NewStats(dataStorage)
cdr := &utils.StoredCdr{
cdr := &StoredCdr{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),

View File

@@ -112,9 +112,9 @@ type AccountingStorage interface {
type CdrStorage interface {
Storage
SetCdr(*utils.StoredCdr) error
SetRatedCdr(*utils.StoredCdr, string) error
GetStoredCdrs(*utils.CdrsFilter) ([]*utils.StoredCdr, int64, error)
SetCdr(*StoredCdr) error
SetRatedCdr(*StoredCdr, string) error
GetStoredCdrs(*utils.CdrsFilter) ([]*StoredCdr, int64, error)
RemStoredCdrs([]string) error
}

View File

@@ -103,7 +103,7 @@ func (self *MySQLStorage) LogCallCost(cgrid, source, runid string, cc *CallCost)
return nil
}
func (self *MySQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string) (err error) {
func (self *MySQLStorage) SetRatedCdr(storedCdr *StoredCdr, extraInfo string) (err error) {
_, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s (cgrid,runid,reqtype,direction,tenant,category,account,subject,destination,setup_time,answer_time,`usage`,cost,extra_info,created_at) VALUES ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%v,%f,'%s','%s') ON DUPLICATE KEY UPDATE reqtype=values(reqtype),direction=values(direction),tenant=values(tenant),category=values(category),account=values(account),subject=values(subject),destination=values(destination),setup_time=values(setup_time),answer_time=values(answer_time),`usage`=values(`usage`),cost=values(cost),extra_info=values(extra_info), updated_at='%s'",
utils.TBL_RATED_CDRS,
storedCdr.CgrId,

View File

@@ -431,50 +431,50 @@ func TestMySQLSetCdr(t *testing.T) {
if !*testLocal {
return
}
cgrCdr1 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
cgrCdr1 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:20Z",
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: TEST_SQL}
cgrCdr2 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
cgrCdr2 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:22Z",
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
cgrCdr3 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
cgrCdr3 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
utils.CATEGORY: "premium_call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "1001", utils.SETUP_TIME: "2013-11-07T08:42:24Z",
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
cgrCdr4 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
cgrCdr4 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "+4986517174964", utils.SETUP_TIME: "2013-11-07T08:42:21Z",
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
cgrCdr5 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
cgrCdr5 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
utils.CATEGORY: "call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "+4986517174963", utils.SETUP_TIME: "2013-11-07T08:42:25Z",
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
for _, cdr := range []*utils.CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} {
for _, cdr := range []*CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} {
if err := mysqlDb.SetCdr(cdr.AsStoredCdr()); err != nil {
t.Error(err.Error())
}
}
strCdr1 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
strCdr2 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID,
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
strCdr3 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} {
for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} {
if err := mysqlDb.SetCdr(cdr); err != nil {
t.Error(err.Error())
}
@@ -485,26 +485,26 @@ func TestMySQLSetRatedCdr(t *testing.T) {
if !*testLocal {
return
}
strCdr1 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
strCdr2 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID,
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
strCdr3 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: "wholesale_run", Cost: 1.201}
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} {
for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} {
if err := mysqlDb.SetRatedCdr(cdr, ""); err != nil {
t.Error(err.Error())
}

View File

@@ -120,7 +120,7 @@ func (self *PostgresStorage) LogCallCost(cgrid, source, runid string, cc *CallCo
return nil
}
func (self *PostgresStorage) SetRatedCdr(cdr *utils.StoredCdr, extraInfo string) (err error) {
func (self *PostgresStorage) SetRatedCdr(cdr *StoredCdr, extraInfo string) (err error) {
tx := self.db.Begin()
saved := tx.Save(&TblRatedCdr{
Cgrid: cdr.CgrId,

View File

@@ -433,50 +433,50 @@ func TestPSQLSetCdr(t *testing.T) {
if !*testLocal {
return
}
cgrCdr1 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
cgrCdr1 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa1", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:20Z",
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", utils.CDRSOURCE: TEST_SQL}
cgrCdr2 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
cgrCdr2 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa2", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_PREPAID, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "1002", utils.SETUP_TIME: "2013-11-08T08:42:22Z",
utils.ANSWER_TIME: "2013-11-08T08:42:26Z", utils.USAGE: "20", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
cgrCdr3 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
cgrCdr3 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa3", utils.CDRHOST: "192.168.1.1", utils.REQTYPE: utils.META_RATED, utils.DIRECTION: "*out", utils.TENANT: "cgrates.org",
utils.CATEGORY: "premium_call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "1001", utils.SETUP_TIME: "2013-11-07T08:42:24Z",
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "60s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
cgrCdr4 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
cgrCdr4 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa4", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_PSEUDOPREPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
utils.CATEGORY: "call", utils.ACCOUNT: "1001", utils.SUBJECT: "1001", utils.DESTINATION: "+4986517174964", utils.SETUP_TIME: "2013-11-07T08:42:21Z",
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "1m2s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
cgrCdr5 := &utils.CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
cgrCdr5 := &CgrCdr{utils.TOR: utils.VOICE, utils.ACCID: "aaa5", utils.CDRHOST: "192.168.1.2", utils.REQTYPE: utils.META_POSTPAID, utils.DIRECTION: "*out", utils.TENANT: "itsyscom.com",
utils.CATEGORY: "call", utils.ACCOUNT: "1002", utils.SUBJECT: "1002", utils.DESTINATION: "+4986517174963", utils.SETUP_TIME: "2013-11-07T08:42:25Z",
utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.USAGE: "15s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL}
for _, cdr := range []*utils.CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} {
for _, cdr := range []*CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} {
if err := psqlDb.SetCdr(cdr.AsStoredCdr()); err != nil {
t.Error(err.Error())
}
}
strCdr1 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
strCdr2 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID,
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN2", ReqType: utils.META_PREPAID,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
strCdr3 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1000", Destination: "+4986517174963",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} {
for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} {
if err := psqlDb.SetCdr(cdr); err != nil {
t.Error(err.Error())
}
@@ -531,26 +531,26 @@ func TestPSQLSetRatedCdr(t *testing.T) {
if !*testLocal {
return
}
strCdr1 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
strCdr1 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb1", CdrHost: "192.168.1.1", CdrSource: "UNKNOWN", ReqType: utils.META_RATED,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 1.201}
strCdr1.CgrId = utils.Sha1(strCdr1.AccId, strCdr1.SetupTime.String())
strCdr2 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID,
strCdr2 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb2", CdrHost: "192.168.1.2", CdrSource: "UNKNOWN", ReqType: utils.META_PREPAID,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(12) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: utils.DEFAULT_RUNID, Cost: 0.201}
strCdr2.CgrId = utils.Sha1(strCdr2.AccId, strCdr2.SetupTime.String())
strCdr3 := &utils.StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
strCdr3 := &StoredCdr{TOR: utils.VOICE, AccId: "bbb3", CdrHost: "192.168.1.1", CdrSource: TEST_SQL, ReqType: utils.META_RATED,
Direction: "*out", Tenant: "itsyscom.com", Category: "call", Account: "1002", Subject: "1002", Destination: "+4986517174964",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
MediationRunId: "wholesale_run", Cost: 1.201}
strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String())
for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} {
for _, cdr := range []*StoredCdr{strCdr1, strCdr2, strCdr3} {
if err := psqlDb.SetRatedCdr(cdr, ""); err != nil {
t.Error(err.Error())
}

View File

@@ -716,7 +716,7 @@ func (self *SQLStorage) LogActionTiming(source string, at *ActionTiming, as Acti
}
func (self *SQLStorage) LogError(uuid, source, runid, errstr string) (err error) { return }
func (self *SQLStorage) SetCdr(cdr *utils.StoredCdr) error {
func (self *SQLStorage) SetCdr(cdr *StoredCdr) error {
extraFields, err := json.Marshal(cdr.ExtraFields)
if err != nil {
return err
@@ -752,12 +752,12 @@ func (self *SQLStorage) SetCdr(cdr *utils.StoredCdr) error {
return nil
}
func (self *SQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string) error {
func (self *SQLStorage) SetRatedCdr(storedCdr *StoredCdr, extraInfo string) error {
return errors.New(utils.ERR_NOT_IMPLEMENTED)
}
func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*utils.StoredCdr, int64, error) {
var cdrs []*utils.StoredCdr
func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*StoredCdr, int64, error) {
var cdrs []*StoredCdr
// Select string
var selectStr string
if qryFltr.IgnoreDerived { // We use different tables to query account data in case of derived
@@ -999,7 +999,7 @@ func (self *SQLStorage) GetStoredCdrs(qryFltr *utils.CdrsFilter) ([]*utils.Store
}
}
usageDur, _ := time.ParseDuration(strconv.FormatFloat(usage.Float64, 'f', -1, 64) + "s")
storCdr := &utils.StoredCdr{
storCdr := &StoredCdr{
CgrId: cgrid.String, OrderId: orderid, TOR: tor.String, AccId: accid.String, CdrHost: cdrhost.String, CdrSource: cdrsrc.String, ReqType: reqtype.String,
Direction: direction.String, Tenant: tenant.String,
Category: category.String, Account: account.String, Subject: subject.String, Destination: destination.String,

509
engine/storedcdr.go Normal file
View File

@@ -0,0 +1,509 @@
/*
Real-time Charging System for Telecom & ISP environments
Copyright (C) 2012-2015 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, ornt
(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 <http://www.gnu.org/licenses/>
*/
package engine
import (
"encoding/json"
"errors"
"fmt"
"math"
"net/url"
"strconv"
"strings"
"time"
"github.com/cgrates/cgrates/utils"
)
// Kinda standard of internal CDR, complies to CDR interface also
type StoredCdr struct {
CgrId string
OrderId int64 // Stor order id used as export order id
TOR string // type of record, meta-field, should map to one of the TORs hardcoded inside the server <*voice|*data|*sms>
AccId string // represents the unique accounting id given by the telecom switch generating the CDR
CdrHost string // represents the IP address of the host generating the CDR (automatically populated by the server)
CdrSource string // formally identifies the source of the CDR (free form field)
ReqType string // matching the supported request types by the **CGRateS**, accepted values are hardcoded in the server <prepaid|postpaid|pseudoprepaid|rated>.
Direction string // matching the supported direction identifiers of the CGRateS <*out>
Tenant string // tenant whom this record belongs
Category string // free-form filter for this record, matching the category defined in rating profiles.
Account string // account id (accounting subsystem) the record should be attached to
Subject string // rating subject (rating subsystem) this record should be attached to
Destination string // destination to be charged
SetupTime time.Time // set-up time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp.
AnswerTime time.Time // answer time of the event. Supported formats: datetime RFC3339 compatible, SQL datetime (eg: MySQL), unix timestamp.
Usage time.Duration // event usage information (eg: in case of tor=*voice this will represent the total duration of a call)
ExtraFields map[string]string // Extra fields to be stored in CDR
MediationRunId string
RatedAccount string // Populated out of rating data
RatedSubject string
Cost float64
CostDetails *CallCost // Attach the cost details to CDR when possible
Rated bool // Mark the CDR as rated so we do not process it during mediation
}
// Used to multiply usage on export
func (storedCdr *StoredCdr) UsageMultiply(multiplyFactor float64, roundDecimals int) {
storedCdr.Usage = time.Duration(int(utils.Round(float64(storedCdr.Usage.Nanoseconds())*multiplyFactor, roundDecimals, utils.ROUNDING_MIDDLE))) // Rounding down could introduce a slight loss here but only at nanoseconds level
}
// Used to multiply cost on export
func (storedCdr *StoredCdr) CostMultiply(multiplyFactor float64, roundDecimals int) {
storedCdr.Cost = utils.Round(storedCdr.Cost*multiplyFactor, roundDecimals, utils.ROUNDING_MIDDLE)
}
// Format cost as string on export
func (storedCdr *StoredCdr) FormatCost(shiftDecimals, roundDecimals int) string {
cost := storedCdr.Cost
if shiftDecimals != 0 {
cost = cost * math.Pow10(shiftDecimals)
}
return strconv.FormatFloat(cost, 'f', roundDecimals, 64)
}
// Formats usage on export
func (storedCdr *StoredCdr) FormatUsage(layout string) string {
if utils.IsSliceMember([]string{utils.DATA, utils.SMS}, storedCdr.TOR) {
return strconv.FormatFloat(utils.Round(storedCdr.Usage.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64)
}
switch layout {
default:
return strconv.FormatFloat(float64(storedCdr.Usage.Nanoseconds())/1000000000, 'f', -1, 64)
}
}
// Used to retrieve fields as string, primary fields are const labeled
func (storedCdr *StoredCdr) FieldAsString(rsrFld *utils.RSRField) string {
switch rsrFld.Id {
case utils.CGRID:
return rsrFld.ParseValue(storedCdr.CgrId)
case utils.ORDERID:
return rsrFld.ParseValue(strconv.FormatInt(storedCdr.OrderId, 10))
case utils.TOR:
return rsrFld.ParseValue(storedCdr.TOR)
case utils.ACCID:
return rsrFld.ParseValue(storedCdr.AccId)
case utils.CDRHOST:
return rsrFld.ParseValue(storedCdr.CdrHost)
case utils.CDRSOURCE:
return rsrFld.ParseValue(storedCdr.CdrSource)
case utils.REQTYPE:
return rsrFld.ParseValue(storedCdr.ReqType)
case utils.DIRECTION:
return rsrFld.ParseValue(storedCdr.Direction)
case utils.TENANT:
return rsrFld.ParseValue(storedCdr.Tenant)
case utils.CATEGORY:
return rsrFld.ParseValue(storedCdr.Category)
case utils.ACCOUNT:
return rsrFld.ParseValue(storedCdr.Account)
case utils.SUBJECT:
return rsrFld.ParseValue(storedCdr.Subject)
case utils.DESTINATION:
return rsrFld.ParseValue(storedCdr.Destination)
case utils.SETUP_TIME:
return rsrFld.ParseValue(storedCdr.SetupTime.Format(time.RFC3339))
case utils.ANSWER_TIME:
return rsrFld.ParseValue(storedCdr.AnswerTime.Format(time.RFC3339))
case utils.USAGE:
return strconv.FormatFloat(utils.Round(storedCdr.Usage.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64)
case utils.MEDI_RUNID:
return rsrFld.ParseValue(storedCdr.MediationRunId)
case utils.RATED_ACCOUNT:
return rsrFld.ParseValue(storedCdr.RatedAccount)
case utils.RATED_SUBJECT:
return rsrFld.ParseValue(storedCdr.RatedSubject)
case utils.COST:
return rsrFld.ParseValue(strconv.FormatFloat(storedCdr.Cost, 'f', -1, 64)) // Recommended to use FormatCost
default:
return rsrFld.ParseValue(storedCdr.ExtraFields[rsrFld.Id])
}
}
func (storedCdr *StoredCdr) PassesFieldFilter(fieldFilter *utils.RSRField) (bool, string) {
if fieldFilter == nil {
return true, ""
}
if fieldFilter.IsStatic() && storedCdr.FieldAsString(&utils.RSRField{Id: fieldFilter.Id}) == storedCdr.FieldAsString(fieldFilter) {
return true, storedCdr.FieldAsString(&utils.RSRField{Id: fieldFilter.Id})
}
preparedFilter := &utils.RSRField{Id: fieldFilter.Id, RSRules: make([]*utils.ReSearchReplace, len(fieldFilter.RSRules))} // Reset rules so they do not point towards same structures as original fieldFilter
for idx := range fieldFilter.RSRules {
// Hardcode the template with maximum of 5 groups ordered
preparedFilter.RSRules[idx] = &utils.ReSearchReplace{SearchRegexp: fieldFilter.RSRules[idx].SearchRegexp, ReplaceTemplate: utils.FILTER_REGEXP_TPL}
}
preparedVal := storedCdr.FieldAsString(preparedFilter)
filteredValue := storedCdr.FieldAsString(fieldFilter)
if preparedFilter.RegexpMatched() && (len(preparedVal) == 0 || preparedVal == filteredValue) {
return true, filteredValue
}
return false, ""
}
func (storedCdr *StoredCdr) AsStoredCdr() *StoredCdr {
return storedCdr
}
// Ability to send the CgrCdr remotely to another CDR server, we do not include rating variables for now
func (storedCdr *StoredCdr) AsHttpForm() url.Values {
v := url.Values{}
for fld, val := range storedCdr.ExtraFields {
v.Set(fld, val)
}
v.Set(utils.TOR, storedCdr.TOR)
v.Set(utils.ACCID, storedCdr.AccId)
v.Set(utils.CDRHOST, storedCdr.CdrHost)
v.Set(utils.CDRSOURCE, storedCdr.CdrSource)
v.Set(utils.REQTYPE, storedCdr.ReqType)
v.Set(utils.DIRECTION, storedCdr.Direction)
v.Set(utils.TENANT, storedCdr.Tenant)
v.Set(utils.CATEGORY, storedCdr.Category)
v.Set(utils.ACCOUNT, storedCdr.Account)
v.Set(utils.SUBJECT, storedCdr.Subject)
v.Set(utils.DESTINATION, storedCdr.Destination)
v.Set(utils.SETUP_TIME, storedCdr.SetupTime.Format(time.RFC3339))
v.Set(utils.ANSWER_TIME, storedCdr.AnswerTime.Format(time.RFC3339))
v.Set(utils.USAGE, storedCdr.FormatUsage(utils.SECONDS))
return v
}
// Used in mediation, primaryMandatory marks whether missing field out of request represents error or can be ignored
func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tenantFld, categFld, accountFld, subjectFld, destFld, setupTimeFld, answerTimeFld, durationFld *utils.RSRField,
extraFlds []*utils.RSRField, primaryMandatory bool) (*StoredCdr, error) {
if reqTypeFld == nil {
reqTypeFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if reqTypeFld.Id == utils.META_DEFAULT {
reqTypeFld.Id = utils.REQTYPE
}
if directionFld == nil {
directionFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if directionFld.Id == utils.META_DEFAULT {
directionFld.Id = utils.DIRECTION
}
if tenantFld == nil {
tenantFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if tenantFld.Id == utils.META_DEFAULT {
tenantFld.Id = utils.TENANT
}
if categFld == nil {
categFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if categFld.Id == utils.META_DEFAULT {
categFld.Id = utils.CATEGORY
}
if accountFld == nil {
accountFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if accountFld.Id == utils.META_DEFAULT {
accountFld.Id = utils.ACCOUNT
}
if subjectFld == nil {
subjectFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if subjectFld.Id == utils.META_DEFAULT {
subjectFld.Id = utils.SUBJECT
}
if destFld == nil {
destFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if destFld.Id == utils.META_DEFAULT {
destFld.Id = utils.DESTINATION
}
if setupTimeFld == nil {
setupTimeFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if setupTimeFld.Id == utils.META_DEFAULT {
setupTimeFld.Id = utils.SETUP_TIME
}
if answerTimeFld == nil {
answerTimeFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if answerTimeFld.Id == utils.META_DEFAULT {
answerTimeFld.Id = utils.ANSWER_TIME
}
if durationFld == nil {
durationFld, _ = utils.NewRSRField(utils.META_DEFAULT)
}
if durationFld.Id == utils.META_DEFAULT {
durationFld.Id = utils.USAGE
}
var err error
frkStorCdr := new(StoredCdr)
frkStorCdr.CgrId = storedCdr.CgrId
frkStorCdr.TOR = storedCdr.TOR
frkStorCdr.MediationRunId = runId
frkStorCdr.Cost = -1.0 // Default for non-rated CDR
frkStorCdr.AccId = storedCdr.AccId
frkStorCdr.CdrHost = storedCdr.CdrHost
frkStorCdr.CdrSource = storedCdr.CdrSource
frkStorCdr.ReqType = storedCdr.FieldAsString(reqTypeFld)
if primaryMandatory && len(frkStorCdr.ReqType) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.REQTYPE, reqTypeFld.Id))
}
frkStorCdr.Direction = storedCdr.FieldAsString(directionFld)
if primaryMandatory && len(frkStorCdr.Direction) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.DIRECTION, directionFld.Id))
}
frkStorCdr.Tenant = storedCdr.FieldAsString(tenantFld)
if primaryMandatory && len(frkStorCdr.Tenant) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.TENANT, tenantFld.Id))
}
frkStorCdr.Category = storedCdr.FieldAsString(categFld)
if primaryMandatory && len(frkStorCdr.Category) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.CATEGORY, categFld.Id))
}
frkStorCdr.Account = storedCdr.FieldAsString(accountFld)
if primaryMandatory && len(frkStorCdr.Account) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.ACCOUNT, accountFld.Id))
}
frkStorCdr.Subject = storedCdr.FieldAsString(subjectFld)
if primaryMandatory && len(frkStorCdr.Subject) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.SUBJECT, subjectFld.Id))
}
frkStorCdr.Destination = storedCdr.FieldAsString(destFld)
if primaryMandatory && len(frkStorCdr.Destination) == 0 && frkStorCdr.TOR == utils.VOICE {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.DESTINATION, destFld.Id))
}
sTimeStr := storedCdr.FieldAsString(setupTimeFld)
if primaryMandatory && len(sTimeStr) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.SETUP_TIME, setupTimeFld.Id))
} else if frkStorCdr.SetupTime, err = utils.ParseTimeDetectLayout(sTimeStr); err != nil {
return nil, err
}
aTimeStr := storedCdr.FieldAsString(answerTimeFld)
if primaryMandatory && len(aTimeStr) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.ANSWER_TIME, answerTimeFld.Id))
} else if frkStorCdr.AnswerTime, err = utils.ParseTimeDetectLayout(aTimeStr); err != nil {
return nil, err
}
durStr := storedCdr.FieldAsString(durationFld)
if primaryMandatory && len(durStr) == 0 {
return nil, errors.New(fmt.Sprintf("%s:%s:%s", utils.ERR_MANDATORY_IE_MISSING, utils.USAGE, durationFld.Id))
} else if frkStorCdr.Usage, err = utils.ParseDurationWithSecs(durStr); err != nil {
return nil, err
}
frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds))
for _, fld := range extraFlds {
frkStorCdr.ExtraFields[fld.Id] = storedCdr.FieldAsString(fld)
}
return frkStorCdr, nil
}
func (storedCdr *StoredCdr) AsCgrExtCdr() *CgrExtCdr {
return &CgrExtCdr{CgrId: storedCdr.CgrId,
OrderId: storedCdr.OrderId,
TOR: storedCdr.TOR,
AccId: storedCdr.AccId,
CdrHost: storedCdr.CdrHost,
CdrSource: storedCdr.CdrSource,
ReqType: storedCdr.ReqType,
Direction: storedCdr.Direction,
Tenant: storedCdr.Tenant,
Category: storedCdr.Category,
Account: storedCdr.Account,
Subject: storedCdr.Subject,
Destination: storedCdr.Destination,
SetupTime: storedCdr.SetupTime.Format(time.RFC3339),
AnswerTime: storedCdr.AnswerTime.Format(time.RFC3339),
Usage: storedCdr.FormatUsage(utils.SECONDS),
ExtraFields: storedCdr.ExtraFields,
MediationRunId: storedCdr.MediationRunId,
RatedAccount: storedCdr.RatedAccount,
RatedSubject: storedCdr.RatedSubject,
Cost: storedCdr.Cost,
}
}
// Implementation of Event interface, used in tests
func (storedCdr *StoredCdr) AsEvent(ignored string) Event {
return Event(storedCdr)
}
func (storedCdr *StoredCdr) GetName() string {
return storedCdr.CdrSource
}
func (storedCdr *StoredCdr) GetCgrId() string {
return storedCdr.CgrId
}
func (storedCdr *StoredCdr) GetUUID() string {
return storedCdr.AccId
}
func (storedCdr *StoredCdr) GetSessionIds() []string {
return []string{storedCdr.GetUUID()}
}
func (storedCdr *StoredCdr) GetDirection(fieldName string) string {
if utils.IsSliceMember([]string{utils.DIRECTION, utils.META_DEFAULT}, fieldName) {
return storedCdr.Direction
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetSubject(fieldName string) string {
if utils.IsSliceMember([]string{utils.SUBJECT, utils.META_DEFAULT}, fieldName) {
return storedCdr.Subject
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetAccount(fieldName string) string {
if utils.IsSliceMember([]string{utils.ACCOUNT, utils.META_DEFAULT}, fieldName) {
return storedCdr.Account
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetDestination(fieldName string) string {
if utils.IsSliceMember([]string{utils.DESTINATION, utils.META_DEFAULT}, fieldName) {
return storedCdr.Destination
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetCallDestNr(fieldName string) string {
if utils.IsSliceMember([]string{utils.DESTINATION, utils.META_DEFAULT}, fieldName) {
return storedCdr.Destination
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetCategory(fieldName string) string {
if utils.IsSliceMember([]string{utils.CATEGORY, utils.META_DEFAULT}, fieldName) {
return storedCdr.Category
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetTenant(fieldName string) string {
if utils.IsSliceMember([]string{utils.TENANT, utils.META_DEFAULT}, fieldName) {
return storedCdr.Tenant
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetReqType(fieldName string) string {
if utils.IsSliceMember([]string{utils.REQTYPE, utils.META_DEFAULT}, fieldName) {
return storedCdr.ReqType
}
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
return fieldName[len(utils.STATIC_VALUE_PREFIX):]
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetSetupTime(fieldName string) (time.Time, error) {
if utils.IsSliceMember([]string{utils.SETUP_TIME, utils.META_DEFAULT}, fieldName) {
return storedCdr.SetupTime, nil
}
var sTimeVal string
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
sTimeVal = fieldName[len(utils.STATIC_VALUE_PREFIX):]
} else {
sTimeVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
return utils.ParseTimeDetectLayout(sTimeVal)
}
func (storedCdr *StoredCdr) GetAnswerTime(fieldName string) (time.Time, error) {
if utils.IsSliceMember([]string{utils.ANSWER_TIME, utils.META_DEFAULT}, fieldName) {
return storedCdr.AnswerTime, nil
}
var aTimeVal string
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
aTimeVal = fieldName[len(utils.STATIC_VALUE_PREFIX):]
} else {
aTimeVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
return utils.ParseTimeDetectLayout(aTimeVal)
}
func (storedCdr *StoredCdr) GetEndTime() (time.Time, error) {
return storedCdr.AnswerTime.Add(storedCdr.Usage), nil
}
func (storedCdr *StoredCdr) GetDuration(fieldName string) (time.Duration, error) {
if utils.IsSliceMember([]string{utils.USAGE, utils.META_DEFAULT}, fieldName) {
return storedCdr.Usage, nil
}
var durVal string
if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value
durVal = fieldName[len(utils.STATIC_VALUE_PREFIX):]
} else {
durVal = storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
return utils.ParseDurationWithSecs(durVal)
}
func (storedCdr *StoredCdr) GetOriginatorIP(fieldName string) string {
if utils.IsSliceMember([]string{utils.CDRHOST, utils.META_DEFAULT}, fieldName) {
return storedCdr.CdrHost
}
return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName})
}
func (storedCdr *StoredCdr) GetExtraFields() map[string]string {
return storedCdr.ExtraFields
}
func (storedCdr *StoredCdr) MissingParameter() bool {
return len(storedCdr.AccId) == 0 ||
len(storedCdr.Category) == 0 ||
len(storedCdr.Tenant) == 0 ||
len(storedCdr.Account) == 0 ||
len(storedCdr.Destination) == 0
}
func (storedCdr *StoredCdr) ParseEventValue(rsrFld *utils.RSRField) string {
return storedCdr.FieldAsString(rsrFld)
}
func (storedCdr *StoredCdr) String() string {
mrsh, _ := json.Marshal(storedCdr)
return string(mrsh)
}
type CgrExtCdr struct {
CgrId string
OrderId int64
TOR string
AccId string
CdrHost string
CdrSource string
ReqType string
Direction string
Tenant string
Category string
Account string
Subject string
Destination string
SetupTime string
AnswerTime string
Usage string
ExtraFields map[string]string
MediationRunId string
RatedAccount string
RatedSubject string
Cost float64
}

View File

@@ -0,0 +1,48 @@
/*
Real-time Charging System for Telecom & ISP environments
Copyright (C) 2012-2015 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 <http://www.gnu.org/licenses/>
*/
package engine
import (
"flag"
"github.com/cgrates/cgrates/utils"
"testing"
"time"
)
// Arguments received via test command
var testLocal = flag.Bool("local", false, "Perform the tests only on local test environment, not by default.") // This flag will be passed here via "go test -local" args
var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
// Sample HttpJsonPost, more for usage purposes
func TestHttpJsonPost(t *testing.T) {
if !*testLocal {
return
}
cdrOut := &CgrExtCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1",
CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
Category: "call", Account: "account1", Subject: "tgooiscs0014", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String(), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String(),
MediationRunId: utils.DEFAULT_RUNID,
Usage: "0.00000001", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
if _, err := utils.HttpJsonPost("http://localhost:8000", false, cdrOut); err == nil || err.Error() != "Post http://localhost:8000: dial tcp 127.0.0.1:8000: connection refused" {
t.Error(err)
}
}

478
engine/storedcdr_test.go Normal file
View File

@@ -0,0 +1,478 @@
/*
Real-time Charging System for Telecom & ISP environments
Copyright (C) 2012-2015 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 <http://www.gnu.org/licenses/>
*/
package engine
import (
"github.com/cgrates/cgrates/utils"
"reflect"
"testing"
"time"
)
func TestStoredCdrInterfaces(t *testing.T) {
storedCdr := new(StoredCdr)
var _ RawCdr = storedCdr
var _ Event = storedCdr
}
func TestFieldAsString(t *testing.T) {
cdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans",
}
if cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CgrId ||
cdr.FieldAsString(&utils.RSRField{Id: utils.ORDERID}) != "123" ||
cdr.FieldAsString(&utils.RSRField{Id: utils.TOR}) != utils.VOICE ||
cdr.FieldAsString(&utils.RSRField{Id: utils.ACCID}) != cdr.AccId ||
cdr.FieldAsString(&utils.RSRField{Id: utils.CDRHOST}) != cdr.CdrHost ||
cdr.FieldAsString(&utils.RSRField{Id: utils.CDRSOURCE}) != cdr.CdrSource ||
cdr.FieldAsString(&utils.RSRField{Id: utils.REQTYPE}) != cdr.ReqType ||
cdr.FieldAsString(&utils.RSRField{Id: utils.DIRECTION}) != cdr.Direction ||
cdr.FieldAsString(&utils.RSRField{Id: utils.CATEGORY}) != cdr.Category ||
cdr.FieldAsString(&utils.RSRField{Id: utils.ACCOUNT}) != cdr.Account ||
cdr.FieldAsString(&utils.RSRField{Id: utils.SUBJECT}) != cdr.Subject ||
cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}) != cdr.Destination ||
cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339) ||
cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339) ||
cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10" ||
cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.MediationRunId ||
cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01" ||
cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_ACCOUNT}) != "dan" ||
cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_SUBJECT}) != "dans" ||
cdr.FieldAsString(&utils.RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"] ||
cdr.FieldAsString(&utils.RSRField{Id: "fieldextr2"}) != cdr.ExtraFields["fieldextr2"] ||
cdr.FieldAsString(&utils.RSRField{Id: "dummy_field"}) != "" {
t.Error("Unexpected filed value received",
cdr.FieldAsString(&utils.RSRField{Id: utils.CGRID}) != cdr.CgrId,
cdr.FieldAsString(&utils.RSRField{Id: utils.ORDERID}) != "123",
cdr.FieldAsString(&utils.RSRField{Id: utils.TOR}) != utils.VOICE,
cdr.FieldAsString(&utils.RSRField{Id: utils.ACCID}) != cdr.AccId,
cdr.FieldAsString(&utils.RSRField{Id: utils.CDRHOST}) != cdr.CdrHost,
cdr.FieldAsString(&utils.RSRField{Id: utils.CDRSOURCE}) != cdr.CdrSource,
cdr.FieldAsString(&utils.RSRField{Id: utils.REQTYPE}) != cdr.ReqType,
cdr.FieldAsString(&utils.RSRField{Id: utils.DIRECTION}) != cdr.Direction,
cdr.FieldAsString(&utils.RSRField{Id: utils.CATEGORY}) != cdr.Category,
cdr.FieldAsString(&utils.RSRField{Id: utils.ACCOUNT}) != cdr.Account,
cdr.FieldAsString(&utils.RSRField{Id: utils.SUBJECT}) != cdr.Subject,
cdr.FieldAsString(&utils.RSRField{Id: utils.DESTINATION}) != cdr.Destination,
cdr.FieldAsString(&utils.RSRField{Id: utils.SETUP_TIME}) != cdr.SetupTime.Format(time.RFC3339),
cdr.FieldAsString(&utils.RSRField{Id: utils.ANSWER_TIME}) != cdr.AnswerTime.Format(time.RFC3339),
cdr.FieldAsString(&utils.RSRField{Id: utils.USAGE}) != "10",
cdr.FieldAsString(&utils.RSRField{Id: utils.MEDI_RUNID}) != cdr.MediationRunId,
cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_ACCOUNT}) != "dan",
cdr.FieldAsString(&utils.RSRField{Id: utils.RATED_SUBJECT}) != "dans",
cdr.FieldAsString(&utils.RSRField{Id: utils.COST}) != "1.01",
cdr.FieldAsString(&utils.RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"],
cdr.FieldAsString(&utils.RSRField{Id: "fieldextr2"}) != cdr.ExtraFields["fieldextr2"],
cdr.FieldAsString(&utils.RSRField{Id: "dummy_field"}) != "")
}
}
func TestPassesFieldFilter(t *testing.T) {
cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
if pass, _ := cdr.PassesFieldFilter(nil); !pass {
t.Error("Not passing filter")
}
acntPrefxFltr, _ := utils.NewRSRField(`~account:s/(.+)/1001/`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass {
t.Error("Not passing filter")
}
acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^(10)\d\d$/10/`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass {
t.Error("Not passing valid filter")
}
acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^\d(10)\d$/10/`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass {
t.Error("Passing filter")
}
acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^(10)\d\d$/010/`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass {
t.Error("Passing filter")
}
acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^1010$/1010/`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass {
t.Error("Passing filter")
}
torFltr, _ := utils.NewRSRField(`^tor::*voice/`)
if pass, _ := cdr.PassesFieldFilter(torFltr); !pass {
t.Error("Not passing filter")
}
torFltr, _ = utils.NewRSRField(`^tor/*data/`)
if pass, _ := cdr.PassesFieldFilter(torFltr); pass {
t.Error("Passing filter")
}
inexistentFieldFltr, _ := utils.NewRSRField(`^fakefield/fakevalue/`)
if pass, _ := cdr.PassesFieldFilter(inexistentFieldFltr); pass {
t.Error("Passing filter")
}
}
func TestPassesFieldFilterDn1(t *testing.T) {
cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem0005",
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
acntPrefxFltr, _ := utils.NewRSRField(`~account:s/^\w+[shmp]\d{4}$//`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass {
t.Error("Not passing valid filter")
}
cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "futurem00005",
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass {
t.Error("Should not pass filter")
}
cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0402129281",
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^0\d{9}$//`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass {
t.Error("Not passing valid filter")
}
acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^0(\d{9})$/placeholder/`)
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass {
t.Error("Should not pass filter")
}
cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "04021292812",
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass {
t.Error("Should not pass filter")
}
cdr = &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), Account: "0162447222",
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
if acntPrefxFltr, err := utils.NewRSRField(`~account:s/^0\d{9}$//`); err != nil {
t.Error("Unexpected parse error", err)
} else if acntPrefxFltr == nil {
t.Error("Failed parsing rule")
} else if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); !pass {
t.Error("Not passing valid filter")
}
if acntPrefxFltr, err := utils.NewRSRField(`~account:s/^\w+[shmp]\d{4}$//`); err != nil {
t.Error("Unexpected parse error", err)
} else if acntPrefxFltr == nil {
t.Error("Failed parsing rule")
} else if pass, _ := cdr.PassesFieldFilter(acntPrefxFltr); pass {
t.Error("Should not pass filter")
}
}
func TestUsageMultiply(t *testing.T) {
cdr := StoredCdr{Usage: time.Duration(10) * time.Second}
if cdr.UsageMultiply(1024.0, 0); cdr.Usage != time.Duration(10240)*time.Second {
t.Errorf("Unexpected usage after multiply: %v", cdr.Usage.Nanoseconds())
}
cdr = StoredCdr{Usage: time.Duration(10240) * time.Second} // Simulate conversion back, gives out a bit odd result but this can be rounded on export
expectDuration, _ := time.ParseDuration("10.000005120s")
if cdr.UsageMultiply(0.000976563, 0); cdr.Usage != expectDuration {
t.Errorf("Unexpected usage after multiply: %v", cdr.Usage.Nanoseconds())
}
}
func TestCostMultiply(t *testing.T) {
cdr := StoredCdr{Cost: 1.01}
if cdr.CostMultiply(1.19, 4); cdr.Cost != 1.2019 {
t.Errorf("Unexpected cost after multiply: %v", cdr.Cost)
}
cdr = StoredCdr{Cost: 1.01}
if cdr.CostMultiply(1000, 0); cdr.Cost != 1010 {
t.Errorf("Unexpected cost after multiply: %v", cdr.Cost)
}
}
func TestFormatCost(t *testing.T) {
cdr := StoredCdr{Cost: 1.01}
if cdr.FormatCost(0, 4) != "1.0100" {
t.Error("Unexpected format of the cost: ", cdr.FormatCost(0, 4))
}
cdr = StoredCdr{Cost: 1.01001}
if cdr.FormatCost(0, 4) != "1.0100" {
t.Error("Unexpected format of the cost: ", cdr.FormatCost(0, 4))
}
if cdr.FormatCost(2, 0) != "101" {
t.Error("Unexpected format of the cost: ", cdr.FormatCost(2, 0))
}
if cdr.FormatCost(1, 0) != "10" {
t.Error("Unexpected format of the cost: ", cdr.FormatCost(1, 0))
}
if cdr.FormatCost(2, 3) != "101.001" {
t.Error("Unexpected format of the cost: ", cdr.FormatCost(2, 3))
}
}
func TestFormatUsage(t *testing.T) {
cdr := StoredCdr{Usage: time.Duration(10) * time.Second}
if cdr.FormatUsage(utils.SECONDS) != "10" {
t.Error("Wrong usage format: ", cdr.FormatUsage(utils.SECONDS))
}
if cdr.FormatUsage("default") != "10" {
t.Error("Wrong usage format: ", cdr.FormatUsage("default"))
}
cdr = StoredCdr{TOR: DATA, Usage: time.Duration(1640113000000000)}
if cdr.FormatUsage("default") != "1640113" {
t.Error("Wrong usage format: ", cdr.FormatUsage("default"))
}
cdr = StoredCdr{Usage: time.Duration(2) * time.Millisecond}
if cdr.FormatUsage("default") != "0.002" {
t.Error("Wrong usage format: ", cdr.FormatUsage("default"))
}
cdr = StoredCdr{Usage: time.Duration(1002) * time.Millisecond}
if cdr.FormatUsage("default") != "1.002" {
t.Error("Wrong usage format: ", cdr.FormatUsage("default"))
}
}
func TestStoredCdrAsHttpForm(t *testing.T) {
storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RatedSubject: "dans", Cost: 1.01,
}
cdrForm := storCdr.AsHttpForm()
if cdrForm.Get(utils.TOR) != utils.VOICE {
t.Errorf("Expected: %s, received: %s", utils.VOICE, cdrForm.Get(utils.TOR))
}
if cdrForm.Get(utils.ACCID) != "dsafdsaf" {
t.Errorf("Expected: %s, received: %s", "dsafdsaf", cdrForm.Get(utils.ACCID))
}
if cdrForm.Get(utils.CDRHOST) != "192.168.1.1" {
t.Errorf("Expected: %s, received: %s", "192.168.1.1", cdrForm.Get(utils.CDRHOST))
}
if cdrForm.Get(utils.CDRSOURCE) != utils.UNIT_TEST {
t.Errorf("Expected: %s, received: %s", utils.UNIT_TEST, cdrForm.Get(utils.CDRSOURCE))
}
if cdrForm.Get(utils.REQTYPE) != utils.META_RATED {
t.Errorf("Expected: %s, received: %s", utils.META_RATED, cdrForm.Get(utils.REQTYPE))
}
if cdrForm.Get(utils.DIRECTION) != "*out" {
t.Errorf("Expected: %s, received: %s", "*out", cdrForm.Get(utils.DIRECTION))
}
if cdrForm.Get(utils.TENANT) != "cgrates.org" {
t.Errorf("Expected: %s, received: %s", "cgrates.org", cdrForm.Get(utils.TENANT))
}
if cdrForm.Get(utils.CATEGORY) != "call" {
t.Errorf("Expected: %s, received: %s", "call", cdrForm.Get(utils.CATEGORY))
}
if cdrForm.Get(utils.ACCOUNT) != "1001" {
t.Errorf("Expected: %s, received: %s", "1001", cdrForm.Get(utils.ACCOUNT))
}
if cdrForm.Get(utils.SUBJECT) != "1001" {
t.Errorf("Expected: %s, received: %s", "1001", cdrForm.Get(utils.SUBJECT))
}
if cdrForm.Get(utils.DESTINATION) != "1002" {
t.Errorf("Expected: %s, received: %s", "1002", cdrForm.Get(utils.DESTINATION))
}
if cdrForm.Get(utils.SETUP_TIME) != "2013-11-07T08:42:20Z" {
t.Errorf("Expected: %s, received: %s", "2013-11-07T08:42:20Z", cdrForm.Get(utils.SETUP_TIME))
}
if cdrForm.Get(utils.ANSWER_TIME) != "2013-11-07T08:42:26Z" {
t.Errorf("Expected: %s, received: %s", "2013-11-07T08:42:26Z", cdrForm.Get(utils.ANSWER_TIME))
}
if cdrForm.Get(utils.USAGE) != "10" {
t.Errorf("Expected: %s, received: %s", "10", cdrForm.Get(utils.USAGE))
}
if cdrForm.Get("field_extr1") != "val_extr1" {
t.Errorf("Expected: %s, received: %s", "val_extr1", cdrForm.Get("field_extr1"))
}
if cdrForm.Get("fieldextr2") != "valextr2" {
t.Errorf("Expected: %s, received: %s", "valextr2", cdrForm.Get("fieldextr2"))
}
}
func TestStoredCdrForkCdr(t *testing.T) {
storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE,
AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "field_extr2": "valextr2"}, Cost: 1.01, RatedSubject: "dans",
}
rtSampleCdrOut, err := storCdr.ForkCdr("sample_run1", &utils.RSRField{Id: utils.REQTYPE}, &utils.RSRField{Id: utils.DIRECTION}, &utils.RSRField{Id: utils.TENANT},
&utils.RSRField{Id: utils.CATEGORY}, &utils.RSRField{Id: utils.ACCOUNT}, &utils.RSRField{Id: utils.SUBJECT}, &utils.RSRField{Id: utils.DESTINATION},
&utils.RSRField{Id: utils.SETUP_TIME}, &utils.RSRField{Id: utils.ANSWER_TIME}, &utils.RSRField{Id: utils.USAGE},
[]*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "field_extr2"}}, true)
if err != nil {
t.Error("Unexpected error received", err)
}
expctSplRatedCdr := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "field_extr2": "valextr2"}, MediationRunId: "sample_run1", Cost: -1}
if !reflect.DeepEqual(expctSplRatedCdr, rtSampleCdrOut) {
t.Errorf("Expected: %v, received: %v", expctSplRatedCdr, rtSampleCdrOut)
}
}
func TestStoredCdrForkCdrStaticVals(t *testing.T) {
storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
rsrStPostpaid, _ := utils.NewRSRField("^" + utils.META_POSTPAID)
rsrStIn, _ := utils.NewRSRField("^*in")
rsrStCgr, _ := utils.NewRSRField("^cgrates.com")
rsrStPC, _ := utils.NewRSRField("^premium_call")
rsrStFA, _ := utils.NewRSRField("^first_account")
rsrStFS, _ := utils.NewRSRField("^first_subject")
rsrStST, _ := utils.NewRSRField("^2013-12-07T08:42:24Z")
rsrStAT, _ := utils.NewRSRField("^2013-12-07T08:42:26Z")
rsrStDur, _ := utils.NewRSRField("^12s")
rtCdrOut2, err := storCdr.ForkCdr("wholesale_run", rsrStPostpaid, rsrStIn, rsrStCgr, rsrStPC, rsrStFA, rsrStFS, &utils.RSRField{Id: "destination"}, rsrStST, rsrStAT, rsrStDur,
[]*utils.RSRField{}, true)
if err != nil {
t.Error("Unexpected error received", err)
}
expctRatedCdr2 := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_POSTPAID,
Direction: "*in", Tenant: "cgrates.com", Category: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "1002",
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(12) * time.Second,
ExtraFields: map[string]string{}, MediationRunId: "wholesale_run", Cost: -1}
if !reflect.DeepEqual(rtCdrOut2, expctRatedCdr2) {
t.Errorf("Received: %v, expected: %v", rtCdrOut2, expctRatedCdr2)
}
_, err = storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: "dummy_header"}, &utils.RSRField{Id: "direction"}, &utils.RSRField{Id: "tenant"}, &utils.RSRField{Id: "tor"}, &utils.RSRField{Id: "account"},
&utils.RSRField{Id: "subject"}, &utils.RSRField{Id: "destination"}, &utils.RSRField{Id: "setup_time"}, &utils.RSRField{Id: "answer_time"}, &utils.RSRField{Id: "duration"},
[]*utils.RSRField{}, true)
if err == nil {
t.Error("Failed to detect missing header")
}
}
func TestStoredCdrForkCdrFromMetaDefaults(t *testing.T) {
storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
}
expctCdr := &StoredCdr{CgrId: storCdr.CgrId, TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED,
Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
Usage: time.Duration(10) * time.Second,
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: "wholesale_run", Cost: -1}
cdrOut, err := storCdr.ForkCdr("wholesale_run", &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT},
&utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT},
&utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, &utils.RSRField{Id: utils.META_DEFAULT}, []*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "fieldextr2"}}, true)
if err != nil {
t.Fatal("Unexpected error received", err)
}
if !reflect.DeepEqual(expctCdr, cdrOut) {
t.Errorf("Expected: %v, received: %v", expctCdr, cdrOut)
}
// Should also accept nil as defaults
if cdrOut, err := storCdr.ForkCdr("wholesale_run", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
[]*utils.RSRField{&utils.RSRField{Id: "field_extr1"}, &utils.RSRField{Id: "fieldextr2"}}, true); err != nil {
t.Fatal("Unexpected error received", err)
} else if !reflect.DeepEqual(expctCdr, cdrOut) {
t.Errorf("Expected: %v, received: %v", expctCdr, cdrOut)
}
}
func TestStoredCdrAsCgrExtCdr(t *testing.T) {
storCdr := StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE,
AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), MediationRunId: utils.DEFAULT_RUNID,
Usage: time.Duration(10), ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans",
}
expectOutCdr := &CgrExtCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE,
AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: utils.UNIT_TEST, ReqType: utils.META_RATED, Direction: "*out",
Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002",
SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", MediationRunId: utils.DEFAULT_RUNID,
Usage: "0.00000001", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01, RatedAccount: "dan", RatedSubject: "dans",
}
if cdrOut := storCdr.AsCgrExtCdr(); !reflect.DeepEqual(expectOutCdr, cdrOut) {
t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut)
}
}
func TestStoredCdrEventFields(t *testing.T) {
cdr := &StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "dan", Subject: "dans",
Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 27, 0, time.UTC),
MediationRunId: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan"}
if ev := cdr.AsEvent(""); ev != Event(cdr) {
t.Error("Received: ", ev)
}
if res := cdr.GetName(); res != "test" {
t.Error("Received: ", res)
}
if res := cdr.GetCgrId(); res != utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()) {
t.Error("Received: ", res)
}
if res := cdr.GetUUID(); res != "dsafdsaf" {
t.Error("Received: ", res)
}
if res := cdr.GetDirection(utils.META_DEFAULT); res != "*out" {
t.Error("Received: ", res)
}
if res := cdr.GetSubject(utils.META_DEFAULT); res != "dans" {
t.Error("Received: ", res)
}
if res := cdr.GetAccount(utils.META_DEFAULT); res != "dan" {
t.Error("Received: ", res)
}
if res := cdr.GetDestination(utils.META_DEFAULT); res != "1002" {
t.Error("Received: ", res)
}
if res := cdr.GetCallDestNr(utils.META_DEFAULT); res != "1002" {
t.Error("Received: ", res)
}
if res := cdr.GetCategory(utils.META_DEFAULT); res != "call" {
t.Error("Received: ", res)
}
if res := cdr.GetTenant(utils.META_DEFAULT); res != "cgrates.org" {
t.Error("Received: ", res)
}
if res := cdr.GetReqType(utils.META_DEFAULT); res != utils.META_RATED {
t.Error("Received: ", res)
}
if st, _ := cdr.GetSetupTime(utils.META_DEFAULT); st != time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC) {
t.Error("Received: ", st)
}
if at, _ := cdr.GetAnswerTime(utils.META_DEFAULT); at != time.Date(2013, 11, 7, 8, 42, 27, 0, time.UTC) {
t.Error("Received: ", at)
}
if et, _ := cdr.GetEndTime(); et != time.Date(2013, 11, 7, 8, 42, 37, 0, time.UTC) {
t.Error("Received: ", et)
}
if dur, _ := cdr.GetDuration(utils.META_DEFAULT); dur != cdr.Usage {
t.Error("Received: ", dur)
}
if res := cdr.GetOriginatorIP(utils.META_DEFAULT); res != cdr.CdrHost {
t.Error("Received: ", res)
}
if extraFlds := cdr.GetExtraFields(); !reflect.DeepEqual(cdr.ExtraFields, extraFlds) {
t.Error("Received: ", extraFlds)
}
}