From ff60061a84d9bff14f25ed8a719976b378c284c1 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 22 Dec 2014 18:47:12 +0100 Subject: [PATCH] Event interface containing AsEvent instead of New, for better readability outside of sessionmanager package, storedCdr supporting event interface for testing purposes, Responder.GetDerivedMaxSessionTime tests --- engine/responder.go | 2 +- engine/responder_test.go | 49 ++++++++- engine/storage_redis_local_test.go | 2 +- general_tests/fsevcorelate_test.go | 2 +- sessionmanager/fsevent.go | 2 +- sessionmanager/fsevent_test.go | 24 ++--- sessionmanager/fssessionmanager.go | 8 +- sessionmanager/kamailiosm.go | 2 +- sessionmanager/kamevent.go | 5 +- sessionmanager/osipsevent.go | 2 +- utils/consts.go | 1 + utils/storedcdr.go | 157 ++++++++++++++++++++++++++++- utils/storedcdr_test.go | 63 ++++++++++++ 13 files changed, 291 insertions(+), 28 deletions(-) diff --git a/engine/responder.go b/engine/responder.go index bcb7eb803..5089c741d 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -123,7 +123,7 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev utils.Event, reply *float64) er if rs.Bal != nil { return errors.New("Unsupported method on the balancer") } - maxCallDuration := -1.0 // This will be the maximum duration this channel will be allowed to last, -1 represents no limits + maxCallDuration := -1.0 attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} var dcs utils.DerivedChargers diff --git a/engine/responder_test.go b/engine/responder_test.go index 3fbde39bc..3ff59093a 100644 --- a/engine/responder_test.go +++ b/engine/responder_test.go @@ -21,11 +21,14 @@ package engine import ( "reflect" "testing" + "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" ) +var rsponder *Responder + // Test internal abilites of GetDerivedChargers func TestResponderGetDerivedChargers(t *testing.T) { cfg, _ := config.NewDefaultCGRConfig() @@ -33,12 +36,54 @@ func TestResponderGetDerivedChargers(t *testing.T) { CategoryField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", UsageField: "test"}} cfg.DerivedChargers = cfgedDC config.SetCgrConfig(cfg) - r := Responder{} + rsponder = &Responder{} attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "responder_test", Subject: "responder_test"} var dcs utils.DerivedChargers - if err := r.GetDerivedChargers(attrs, &dcs); err != nil { + if err := rsponder.GetDerivedChargers(attrs, &dcs); err != nil { t.Error("Unexpected error", err.Error()) } else if !reflect.DeepEqual(dcs, cfgedDC) { t.Errorf("Expecting: %v, received: %v ", cfgedDC, dcs) } } + +func TestGetDerivedMaxSessionTime(t *testing.T) { + config.CgrConfig().CombinedDerivedChargers = false + 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", + CdrHost: "192.168.1.1", CdrSource: "test", ReqType: "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"}, + Cost: 1.01, RatedAccount: "dan", RatedSubject: "dan"} + var maxSessionTime float64 + if err := rsponder.GetDerivedMaxSessionTime(cdr.AsEvent(""), &maxSessionTime); err != nil { + t.Error(err) + } else if maxSessionTime != -1 { + t.Error("Unexpected maxSessionTime received: ", maxSessionTime) + } + keyCharger1 := utils.ConcatenatedKey("*out", testTenant, "call", "dan", "dan") + charger1 := utils.DerivedChargers{ + &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "^0", + AccountField: "^minitsboy", SubjectField: "^rif", DestinationField: "^0256", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, + &utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", + AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, + &utils.DerivedCharger{RunId: "extra3", ReqTypeField: "^pseudoprepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "^0", + AccountField: "^minu", SubjectField: "^rif", DestinationField: "^0256", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, + } + if err := accountingStorage.SetDerivedChargers(keyCharger1, charger1); err != nil { + t.Error("Error on setting DerivedChargers", err.Error()) + } + accountingStorage.CacheAccounting(nil, nil, nil, nil) + var dcs utils.DerivedChargers + attrs := utils.AttrDerivedChargers{Tenant: testTenant, Category: "call", Direction: "*out", Account: "dan", Subject: "dan"} + if err := rsponder.GetDerivedChargers(attrs, &dcs); err != nil { + t.Error("Unexpected error", err.Error()) + } else if !reflect.DeepEqual(dcs, charger1) { + t.Errorf("Expecting: %+v, received: %+v ", charger1, dcs) + } + if err := rsponder.GetDerivedMaxSessionTime(cdr.AsEvent(""), &maxSessionTime); err != nil { + t.Error(err) + } else if maxSessionTime != 9.9e+10 { // Smallest one + t.Error("Unexpected maxSessionTime received: ", maxSessionTime) + } + +} diff --git a/engine/storage_redis_local_test.go b/engine/storage_redis_local_test.go index 65037b260..e89855b9d 100644 --- a/engine/storage_redis_local_test.go +++ b/engine/storage_redis_local_test.go @@ -55,7 +55,7 @@ func TestSetGetDerivedCharges(t *testing.T) { if !*testLocal { return } - keyCharger1 := utils.ConcatenatedKey("cgrates.org", "call", "*out", "dan", "dan") + keyCharger1 := utils.ConcatenatedKey("*out", "cgrates.org", "call", "dan", "dan") charger1 := utils.DerivedChargers{ &utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default", AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"}, diff --git a/general_tests/fsevcorelate_test.go b/general_tests/fsevcorelate_test.go index 394080910..ab8832208 100644 --- a/general_tests/fsevcorelate_test.go +++ b/general_tests/fsevcorelate_test.go @@ -216,7 +216,7 @@ var jsonCdr = []byte(`{"core-uuid":"feef0b51-7fdf-4c4a-878e-aff233752de2","chann func TestEvCorelate(t *testing.T) { cfg, _ := config.NewDefaultCGRConfig() engine.NewCdrS(nil, nil, nil, cfg) // So we can set the package cfg - answerEv := new(sessionmanager.FSEvent).New(answerEvent) + answerEv := new(sessionmanager.FSEvent).AsEvent(answerEvent) if answerEv.GetName() != "CHANNEL_ANSWER" { t.Error("Event not parsed correctly: ", answerEv) } diff --git a/sessionmanager/fsevent.go b/sessionmanager/fsevent.go index 8dd673817..752a2f4e9 100644 --- a/sessionmanager/fsevent.go +++ b/sessionmanager/fsevent.go @@ -76,7 +76,7 @@ func (fsev FSEvent) String() (result string) { // Loads the new event data from a body of text containing the key value proprieties. // It stores the parsed proprieties in the internal map. -func (fsev FSEvent) New(body string) utils.Event { +func (fsev FSEvent) AsEvent(body string) utils.Event { fsev = fsock.FSEventStrToMap(body, nil) return fsev } diff --git a/sessionmanager/fsevent_test.go b/sessionmanager/fsevent_test.go index 1cba09845..c52201b10 100644 --- a/sessionmanager/fsevent_test.go +++ b/sessionmanager/fsevent_test.go @@ -358,7 +358,7 @@ Task-ID: 2 Task-Desc: heartbeat Task-Group: core Task-Runtime: 1349437318` - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) if ev.GetName() != "RE_SCHEDULE" { t.Error("Event not parsed correctly: ", ev) } @@ -370,7 +370,7 @@ Task-Runtime: 1349437318` // Detects if any of the parsers do not return static values func TestEventParseStatic(t *testing.T) { - ev := new(FSEvent).New("") + ev := new(FSEvent).AsEvent("") setupTime, _ := ev.GetSetupTime("^2013-12-07 08:42:24") answerTime, _ := ev.GetAnswerTime("^2013-12-07 08:42:24") dur, _ := ev.GetDuration("^60s") @@ -419,7 +419,7 @@ Task-Group: core Task-Runtime: 1349437318` cfg, _ = config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) setupTime, _ := ev.GetSetupTime("Event-Date-Local") answerTime, _ := ev.GetAnswerTime("Event-Date-Local") dur, _ := ev.GetDuration("Event-Calling-Line-Number") @@ -457,7 +457,7 @@ Caller-Channel-Created-Time: 0 Caller-Channel-Answered-Time Task-Runtime: 1349437318` var nilTime time.Time - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) if setupTime, err := ev.GetSetupTime(""); err != nil { t.Error("Error when parsing empty setupTime") } else if setupTime != nilTime { @@ -473,7 +473,7 @@ Task-Runtime: 1349437318` func TestParseFsHangup(t *testing.T) { cfg, _ = config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) - ev := new(FSEvent).New(hangupEv) + ev := new(FSEvent).AsEvent(hangupEv) setupTime, _ := ev.GetSetupTime(utils.META_DEFAULT) answerTime, _ := ev.GetAnswerTime(utils.META_DEFAULT) dur, _ := ev.GetDuration(utils.META_DEFAULT) @@ -504,7 +504,7 @@ func TestParseFsHangup(t *testing.T) { func TestParseEventValue(t *testing.T) { cfg, _ = config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) - ev := new(FSEvent).New(hangupEv) + ev := new(FSEvent).AsEvent(hangupEv) if cgrid := ev.ParseEventValue(&utils.RSRField{Id: utils.CGRID}); cgrid != "873e5bf7903978f305f7d8fed3f92f968cf82873" { t.Error("Unexpected cgrid parsed", cgrid) } @@ -570,7 +570,7 @@ FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: futurem0005` - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) acntPrefxFltr, _ := utils.NewRSRField(`~account:s/^\w+[shmp]\d{4}$//`) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") @@ -581,7 +581,7 @@ FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: futurem00005` - ev = new(FSEvent).New(body) + ev = new(FSEvent).AsEvent(body) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } @@ -591,7 +591,7 @@ FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: 0402129281` - ev = new(FSEvent).New(body) + ev = new(FSEvent).AsEvent(body) acntPrefxFltr, _ = utils.NewRSRField(`~account:s/^0\d{9}$//`) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); !pass { t.Error("Not passing valid filter") @@ -606,7 +606,7 @@ FreeSWITCH-Hostname: h1.ip-switch.net FreeSWITCH-Switchname: h1.ip-switch.net FreeSWITCH-IPv4: 88.198.12.156 Caller-Username: 04021292812` - ev = new(FSEvent).New(body) + ev = new(FSEvent).AsEvent(body) if pass, _ := ev.PassesFieldFilter(acntPrefxFltr); pass { t.Error("Should not pass filter") } @@ -615,7 +615,7 @@ Caller-Username: 04021292812` func TestFsEvAsStoredCdr(t *testing.T) { cfg, _ = config.NewDefaultCGRConfig() config.SetCgrConfig(cfg) - ev := new(FSEvent).New(hangupEv) + ev := new(FSEvent).AsEvent(hangupEv) setupTime, _ := utils.ParseTimeDetectLayout("1398442107") aTime, _ := utils.ParseTimeDetectLayout("1398442120") eStoredCdr := &utils.StoredCdr{CgrId: utils.Sha1("37e9b766-5256-4e4b-b1ed-3767b930fec8", setupTime.UTC().String()), @@ -632,7 +632,7 @@ func TestFsEvGetExtraFields(t *testing.T) { cfg, _ = config.NewDefaultCGRConfig() cfg.FSCdrExtraFields = []*utils.RSRField{&utils.RSRField{Id: "Channel-Read-Codec-Name"}, &utils.RSRField{Id: "Channel-Write-Codec-Name"}, &utils.RSRField{Id: "NonExistingHeader"}} config.SetCgrConfig(cfg) - ev := new(FSEvent).New(hangupEv) + ev := new(FSEvent).AsEvent(hangupEv) expectedExtraFields := map[string]string{"Channel-Read-Codec-Name": "G722", "Channel-Write-Codec-Name": "G722", "NonExistingHeader": ""} if extraFields := ev.GetExtraFields(); !reflect.DeepEqual(expectedExtraFields, extraFields) { t.Errorf("Expecting: %+v, received: %+v", expectedExtraFields, extraFields) diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index 2f5c1dde4..9ca84ad0c 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -68,19 +68,19 @@ func (sm *FSSessionManager) Connect() (err error) { func (sm *FSSessionManager) createHandlers() (handlers map[string][]func(string)) { hb := func(body string) { - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) sm.OnHeartBeat(ev) } cp := func(body string) { - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) sm.OnChannelPark(ev) } ca := func(body string) { - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) sm.OnChannelAnswer(ev) } ch := func(body string) { - ev := new(FSEvent).New(body) + ev := new(FSEvent).AsEvent(body) sm.OnChannelHangupComplete(ev) } return map[string][]func(string){ diff --git a/sessionmanager/kamailiosm.go b/sessionmanager/kamailiosm.go index cd922eb71..97031b6d0 100644 --- a/sessionmanager/kamailiosm.go +++ b/sessionmanager/kamailiosm.go @@ -47,7 +47,7 @@ func (self *KamailioSessionManager) onCgrAuth(evData []byte) { engine.Logger.Info(fmt.Sprintf(" ERROR unmarshalling event: %s, error: %s", evData, err.Error())) } var remainingDuration float64 - if err = self.rater.GetDerivedMaxSessionTime(kev.New(""), &remainingDuration); err != nil { + if err = self.rater.GetDerivedMaxSessionTime(kev.AsEvent(""), &remainingDuration); err != nil { engine.Logger.Err(fmt.Sprintf("Could not get max session time for %s: %v", kev.GetUUID(), err)) } if remainingDuration == -1.0 { // Unlimited diff --git a/sessionmanager/kamevent.go b/sessionmanager/kamevent.go index 9a7286424..81231d9c9 100644 --- a/sessionmanager/kamevent.go +++ b/sessionmanager/kamevent.go @@ -29,7 +29,6 @@ import ( ) const ( - CGR_AUTHORIZE = "CGR_AUTHORIZE" EVENT = "event" CGR_SETUPTIME = "cgr_setuptime" CGR_ANSWERTIME = "cgr_answertime" @@ -54,7 +53,7 @@ func NewKamEvent(kamEvData []byte) (KamEvent, error) { type KamEvent map[string]string // Backwards compatibility, should be AsEvent -func (kev KamEvent) New(ignored string) utils.Event { +func (kev KamEvent) AsEvent(ignored string) utils.Event { return utils.Event(kev) } @@ -153,7 +152,7 @@ func (kev KamEvent) GetCdrSource() string { } func (kev KamEvent) MissingParameter(eventName string) bool { switch eventName { - case CGR_AUTHORIZE: + case utils.CGR_AUTHORIZE: return len(kev.GetUUID()) == 0 || len(kev.GetCategory(utils.META_DEFAULT)) == 0 || len(kev.GetTenant(utils.META_DEFAULT)) == 0 || diff --git a/sessionmanager/osipsevent.go b/sessionmanager/osipsevent.go index 5e30043f6..404d3955c 100644 --- a/sessionmanager/osipsevent.go +++ b/sessionmanager/osipsevent.go @@ -57,7 +57,7 @@ type OsipsEvent struct { osipsEvent *osipsdagram.OsipsEvent } -func (osipsev *OsipsEvent) New(evStr string) utils.Event { +func (osipsev *OsipsEvent) AsEvent(evStr string) utils.Event { return osipsev } diff --git a/utils/consts.go b/utils/consts.go index 63c2c08c1..f3f7baacf 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -166,6 +166,7 @@ const ( METATAG = "metatag" HTTP_POST = "http_post" NANO_MULTIPLIER = 1000000000 + CGR_AUTHORIZE = "CGR_AUTHORIZE" ) var ( diff --git a/utils/storedcdr.go b/utils/storedcdr.go index 6b9e43844..3655a81ad 100644 --- a/utils/storedcdr.go +++ b/utils/storedcdr.go @@ -4,7 +4,7 @@ Copyright (C) 2012-2014 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 +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, @@ -19,11 +19,13 @@ along with this program. If not, see package utils import ( + "encoding/json" "errors" "fmt" "math" "net/url" "strconv" + "strings" "time" ) @@ -327,6 +329,159 @@ func (storedCdr *StoredCdr) AsCgrCdrOut() *CgrCdrOut { } } +// 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) GetDirection(fieldName string) string { + if IsSliceMember([]string{DIRECTION, META_DEFAULT}, fieldName) { + return storedCdr.Direction + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetSubject(fieldName string) string { + if IsSliceMember([]string{SUBJECT, META_DEFAULT}, fieldName) { + return storedCdr.Subject + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetAccount(fieldName string) string { + if IsSliceMember([]string{ACCOUNT, META_DEFAULT}, fieldName) { + return storedCdr.Account + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetDestination(fieldName string) string { + if IsSliceMember([]string{DESTINATION, META_DEFAULT}, fieldName) { + return storedCdr.Destination + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetCallDestNr(fieldName string) string { + if IsSliceMember([]string{DESTINATION, META_DEFAULT}, fieldName) { + return storedCdr.Destination + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetCategory(fieldName string) string { + if IsSliceMember([]string{CATEGORY, META_DEFAULT}, fieldName) { + return storedCdr.Category + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetTenant(fieldName string) string { + if IsSliceMember([]string{TENANT, META_DEFAULT}, fieldName) { + return storedCdr.Tenant + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetReqType(fieldName string) string { + if IsSliceMember([]string{REQTYPE, META_DEFAULT}, fieldName) { + return storedCdr.ReqType + } + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + return fieldName[len(STATIC_VALUE_PREFIX):] + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetSetupTime(fieldName string) (time.Time, error) { + if IsSliceMember([]string{SETUP_TIME, META_DEFAULT}, fieldName) { + return storedCdr.SetupTime, nil + } + var sTimeVal string + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + sTimeVal = fieldName[len(STATIC_VALUE_PREFIX):] + } else { + sTimeVal = storedCdr.FieldAsString(&RSRField{Id: fieldName}) + } + return ParseTimeDetectLayout(sTimeVal) +} +func (storedCdr *StoredCdr) GetAnswerTime(fieldName string) (time.Time, error) { + if IsSliceMember([]string{ANSWER_TIME, META_DEFAULT}, fieldName) { + return storedCdr.AnswerTime, nil + } + var aTimeVal string + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + aTimeVal = fieldName[len(STATIC_VALUE_PREFIX):] + } else { + aTimeVal = storedCdr.FieldAsString(&RSRField{Id: fieldName}) + } + return 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 IsSliceMember([]string{USAGE, META_DEFAULT}, fieldName) { + return storedCdr.Usage, nil + } + var durVal string + if strings.HasPrefix(fieldName, STATIC_VALUE_PREFIX) { // Static value + durVal = fieldName[len(STATIC_VALUE_PREFIX):] + } else { + durVal = storedCdr.FieldAsString(&RSRField{Id: fieldName}) + } + return ParseDurationWithSecs(durVal) +} +func (storedCdr *StoredCdr) GetOriginatorIP(fieldName string) string { + if IsSliceMember([]string{CDRHOST, META_DEFAULT}, fieldName) { + return storedCdr.CdrHost + } + return storedCdr.FieldAsString(&RSRField{Id: fieldName}) +} +func (storedCdr *StoredCdr) GetExtraFields() map[string]string { + return storedCdr.ExtraFields +} +func (storedCdr *StoredCdr) MissingParameter(eventName string) bool { + switch eventName { + case CGR_AUTHORIZE: + return len(storedCdr.AccId) == 0 || + len(storedCdr.Category) == 0 || + len(storedCdr.Tenant) == 0 || + len(storedCdr.Account) == 0 || + len(storedCdr.Destination) == 0 + default: + return true + } +} +func (storedCdr *StoredCdr) ParseEventValue(rsrFld *RSRField) string { + return storedCdr.FieldAsString(rsrFld) +} +func (storedCdr *StoredCdr) String() string { + mrsh, _ := json.Marshal(storedCdr) + return string(mrsh) +} + type CgrCdrOut struct { CgrId string OrderId int64 diff --git a/utils/storedcdr_test.go b/utils/storedcdr_test.go index 8bda93ea1..31c37ce64 100644 --- a/utils/storedcdr_test.go +++ b/utils/storedcdr_test.go @@ -27,6 +27,7 @@ import ( func TestStoredCdrInterfaces(t *testing.T) { storedCdr := new(StoredCdr) var _ RawCdr = storedCdr + var _ Event = storedCdr } func TestFieldAsString(t *testing.T) { @@ -402,3 +403,65 @@ func TestStoredCdrAsCgrCdrOut(t *testing.T) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) } } + +func TestStoredCdrEventFields(t *testing.T) { + cdr := &StoredCdr{CgrId: Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: VOICE, AccId: "dsafdsaf", + CdrHost: "192.168.1.1", CdrSource: "test", ReqType: "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: 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 != 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(META_DEFAULT); res != "*out" { + t.Error("Received: ", res) + } + if res := cdr.GetSubject(META_DEFAULT); res != "dans" { + t.Error("Received: ", res) + } + if res := cdr.GetAccount(META_DEFAULT); res != "dan" { + t.Error("Received: ", res) + } + if res := cdr.GetDestination(META_DEFAULT); res != "1002" { + t.Error("Received: ", res) + } + if res := cdr.GetCallDestNr(META_DEFAULT); res != "1002" { + t.Error("Received: ", res) + } + if res := cdr.GetCategory(META_DEFAULT); res != "call" { + t.Error("Received: ", res) + } + if res := cdr.GetTenant(META_DEFAULT); res != "cgrates.org" { + t.Error("Received: ", res) + } + if res := cdr.GetReqType(META_DEFAULT); res != "rated" { + t.Error("Received: ", res) + } + if st, _ := cdr.GetSetupTime(META_DEFAULT); st != time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC) { + t.Error("Received: ", st) + } + if at, _ := cdr.GetAnswerTime(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(META_DEFAULT); dur != cdr.Usage { + t.Error("Received: ", dur) + } + if res := cdr.GetOriginatorIP(META_DEFAULT); res != cdr.CdrHost { + t.Error("Received: ", res) + } + if extraFlds := cdr.GetExtraFields(); !reflect.DeepEqual(cdr.ExtraFields, extraFlds) { + t.Error("Received: ", extraFlds) + } +}