From 5af9e7385f49a6ad166802a8872cc4edecdae1b2 Mon Sep 17 00:00:00 2001 From: Tripon Alexandru-Ionut Date: Thu, 13 Jun 2019 14:35:40 +0300 Subject: [PATCH] Updated IfaceAsString and MapEvent tests --- agents/agentreq.go | 14 +---- agents/fsagent.go | 2 +- agents/kamagent.go | 10 +-- agents/libdiam.go | 10 +-- agents/libdns.go | 26 ++------ agents/libhttpagent.go | 6 +- agents/librad.go | 3 +- cdrc/csv.go | 3 +- cdrc/fwv.go | 3 +- cdrc/xml.go | 3 +- config/navigablemap.go | 11 +--- config/rsrparser.go | 5 +- dispatchers/dispatchers.go | 3 +- engine/action.go | 9 +-- engine/attributes.go | 8 +-- engine/filterhelpers.go | 9 +-- engine/mapevent.go | 81 ++++++------------------ engine/mapevent_test.go | 122 +++++++++++++++++++++++++++++++++++++ engine/safevent.go | 6 +- engine/safevent_test.go | 58 ++++++++++++++++++ loaders/libloader.go | 3 +- utils/cgrevent.go | 2 +- utils/dataconverter.go | 6 +- utils/reflect.go | 42 ++++++------- utils/reflect_test.go | 36 +++-------- utils/rsrfield.go | 5 +- utils/struct.go | 6 +- 27 files changed, 263 insertions(+), 229 deletions(-) diff --git a/agents/agentreq.go b/agents/agentreq.go index cc6298079..4cbf15a2b 100644 --- a/agents/agentreq.go +++ b/agents/agentreq.go @@ -119,7 +119,7 @@ func (ar *AgentRequest) FieldAsString(fldPath []string) (val string, err error) if iface, err = ar.FieldAsInterface(fldPath); err != nil { return } - return utils.IfaceAsString(iface) + return utils.IfaceAsString(iface), nil } // AsNavigableMap implements engine.DataProvider @@ -156,16 +156,8 @@ func (ar *AgentRequest) AsNavigableMap(tplFlds []*config.FCTemplate) ( valSet = nMFields.([]*config.NMItem) // start from previous stored fields if tplFld.Type == utils.META_COMPOSED { prevNMItem := valSet[len(valSet)-1] // could be we need nil protection here - prevDataStr, err := utils.IfaceAsString(prevNMItem.Data) - if err != nil { - return nil, err - } - outStr, err := utils.IfaceAsString(out) - if err != nil { - return nil, err - } - *nMItm = *prevNMItem // inherit the particularities, ie AttributeName - nMItm.Data = prevDataStr + outStr + *nMItm = *prevNMItem // inherit the particularities, ie AttributeName + nMItm.Data = utils.IfaceAsString(prevNMItem.Data) + utils.IfaceAsString(out) } valSet = valSet[:len(valSet)-1] // discard the last item } diff --git a/agents/fsagent.go b/agents/fsagent.go index b05d269d0..63771880c 100644 --- a/agents/fsagent.go +++ b/agents/fsagent.go @@ -385,7 +385,7 @@ func (sm *FSsessions) Call(serviceMethod string, args interface{}, reply interfa func (fsa *FSsessions) V1DisconnectSession(args utils.AttrDisconnectSession, reply *string) (err error) { ev := engine.NewMapEvent(args.EventStart) channelID := ev.GetStringIgnoreErrors(utils.OriginID) - connIdx, err := ev.GetInt64(FsConnID) + connIdx, err := ev.GetTInt64(FsConnID) if err != nil { utils.Logger.Err( fmt.Sprintf("<%s> error: <%s:%s> when attempting to disconnect channelID: <%s>", diff --git a/agents/kamagent.go b/agents/kamagent.go index 010250d13..feb07f82d 100644 --- a/agents/kamagent.go +++ b/agents/kamagent.go @@ -313,14 +313,8 @@ func (self *KamailioAgent) disconnectSession(connIdx int, dscEv *KamSessionDisco // Internal method to disconnect session in Kamailio func (ka *KamailioAgent) V1DisconnectSession(args utils.AttrDisconnectSession, reply *string) (err error) { - hEntry, err := utils.IfaceAsString(args.EventStart[KamHashEntry]) - if err != nil { - return err - } - hID, err := utils.IfaceAsString(args.EventStart[KamHashID]) - if err != nil { - return err - } + hEntry := utils.IfaceAsString(args.EventStart[KamHashEntry]) + hID := utils.IfaceAsString(args.EventStart[KamHashID]) connIdxIface, has := args.EventStart[EvapiConnID] if !has { utils.Logger.Err( diff --git a/agents/libdiam.go b/agents/libdiam.go index 8de332a8f..491a582e6 100644 --- a/agents/libdiam.go +++ b/agents/libdiam.go @@ -116,7 +116,7 @@ func diamAVPAsString(dAVP *diam.AVP) (s string, err error) { if iface, err = diamAVPAsIface(dAVP); err != nil { return } - return utils.IfaceAsString(iface) + return utils.IfaceAsString(iface), nil } // newDiamDataType constructs dataType from valStr @@ -320,7 +320,7 @@ func (dP *diameterDP) FieldAsString(fldPath []string) (data string, err error) { if err != nil { return } - return utils.IfaceAsString(valIface) + return utils.IfaceAsString(valIface), nil } // RemoteHost is part of engine.DataProvider interface @@ -447,16 +447,12 @@ func updateDiamMsgFromNavMap(m *diam.Message, navMp *config.NavigableMap, tmz st if itm == nil { continue // all attributes, not writable to diameter packet } - itmStr, err := utils.IfaceAsString(itm.Data) - if err != nil { - return fmt.Errorf("cannot convert data: %+v to string, err: %s", itm.Data, err) - } var newBranch bool if itm.Config != nil && itm.Config.NewBranch { newBranch = true } if err = messageSetAVPsWithPath(m, itm.Path, - itmStr, newBranch, tmz); err != nil { + utils.IfaceAsString(itm.Data), newBranch, tmz); err != nil { return fmt.Errorf("setting item with path: %+v got err: %s", itm.Path, err.Error()) } } diff --git a/agents/libdns.go b/agents/libdns.go index e4def101d..5bc1d5cbe 100644 --- a/agents/libdns.go +++ b/agents/libdns.go @@ -79,7 +79,7 @@ func (dP *dnsDP) FieldAsString(fldPath []string) (data string, err error) { if err != nil { return } - return utils.IfaceAsString(valIface) + return utils.IfaceAsString(valIface), nil } // RemoteHost is part of engine.DataProvider interface @@ -193,38 +193,22 @@ func updateDNSMsgFromNM(msg *dns.Msg, nm *config.NavigableMap) (err error) { if msg.Question[0].Qtype != dns.TypeNAPTR { return fmt.Errorf("field <%s> only works with NAPTR", utils.Flags) } - var itm string - if itm, err = utils.IfaceAsString(cfgItm.Data); err != nil { - return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error()) - } - msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Flags = itm + msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Flags = utils.IfaceAsString(cfgItm.Data) case utils.Service: if msg.Question[0].Qtype != dns.TypeNAPTR { return fmt.Errorf("field <%s> only works with NAPTR", utils.Service) } - var itm string - if itm, err = utils.IfaceAsString(cfgItm.Data); err != nil { - return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error()) - } - msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Service = itm + msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Service = utils.IfaceAsString(cfgItm.Data) case utils.Regexp: if msg.Question[0].Qtype != dns.TypeNAPTR { return fmt.Errorf("field <%s> only works with NAPTR", utils.Regexp) } - var itm string - if itm, err = utils.IfaceAsString(cfgItm.Data); err != nil { - return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error()) - } - msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Regexp = itm + msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Regexp = utils.IfaceAsString(cfgItm.Data) case utils.Replacement: if msg.Question[0].Qtype != dns.TypeNAPTR { return fmt.Errorf("field <%s> only works with NAPTR", utils.Replacement) } - var rplc string - if rplc, err = utils.IfaceAsString(cfgItm.Data); err != nil { - return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error()) - } - msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Replacement = rplc + msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Replacement = utils.IfaceAsString(cfgItm.Data) } } diff --git a/agents/libhttpagent.go b/agents/libhttpagent.go index 11d9077bc..98ead2fc1 100644 --- a/agents/libhttpagent.go +++ b/agents/libhttpagent.go @@ -91,8 +91,7 @@ func (hU *httpUrlDP) FieldAsString(fldPath []string) (data string, err error) { if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface @@ -186,8 +185,7 @@ func (hU *httpXmlDP) FieldAsString(fldPath []string) (data string, err error) { if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface diff --git a/agents/librad.go b/agents/librad.go index 925a21873..bf1093361 100644 --- a/agents/librad.go +++ b/agents/librad.go @@ -163,8 +163,7 @@ func (pk *radiusDP) FieldAsString(fldPath []string) (data string, err error) { if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface diff --git a/cdrc/csv.go b/cdrc/csv.go index e50799c07..0bb9f1a9e 100644 --- a/cdrc/csv.go +++ b/cdrc/csv.go @@ -274,8 +274,7 @@ func (cP *csvProvider) FieldAsString(fldPath []string) (data string, err error) if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface diff --git a/cdrc/fwv.go b/cdrc/fwv.go index 5bd8cf98f..9480a0f98 100644 --- a/cdrc/fwv.go +++ b/cdrc/fwv.go @@ -307,8 +307,7 @@ func (fP *fwvProvider) FieldAsString(fldPath []string) (data string, err error) if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface diff --git a/cdrc/xml.go b/cdrc/xml.go index e8b41c54b..0a0678df4 100644 --- a/cdrc/xml.go +++ b/cdrc/xml.go @@ -267,8 +267,7 @@ func (xP *xmlProvider) FieldAsString(fldPath []string) (data string, err error) if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface diff --git a/config/navigablemap.go b/config/navigablemap.go index b0132d9b9..1b0562bfc 100644 --- a/config/navigablemap.go +++ b/config/navigablemap.go @@ -229,10 +229,7 @@ func (nM *NavigableMap) FieldAsString(fldPath []string) (fldVal string, err erro if err != nil { return } - if fldVal, err = utils.IfaceAsString(valIface); err != nil { - return "", fmt.Errorf("cannot cast field: %s to string", utils.ToJSON(valIface)) - } - return + return utils.IfaceAsString(valIface), nil } // String is part of engine.DataProvider interface @@ -371,11 +368,7 @@ func (nM *NavigableMap) AsXMLElements() (ents []*XMLElement, err error) { if nmItm.Config != nil && nmItm.Config.NewBranch { pathIdx = make(map[string]*XMLElement) // reset cache so we can start having other elements with same path } - val, err := utils.IfaceAsString(nmItm.Data) - if err != nil { - return nil, - fmt.Errorf("cannot cast value: <%s> to string", utils.ToJSON(nmItm.Data)) - } + val := utils.IfaceAsString(nmItm.Data) var pathCached bool for i := len(nmItm.Path); i > 0; i-- { var cachedElm *XMLElement diff --git a/config/rsrparser.go b/config/rsrparser.go index 769c5df1e..5ea3294ea 100644 --- a/config/rsrparser.go +++ b/config/rsrparser.go @@ -250,10 +250,7 @@ func (prsr *RSRParser) parseValue(value string) string { // ParseValue will parse the value out considering converters and filters func (prsr *RSRParser) ParseValue(value interface{}) (out string, err error) { - if out, err = utils.IfaceAsString(value); err != nil { - return - } - out = prsr.parseValue(out) + out = prsr.parseValue(utils.IfaceAsString(value)) if out, err = prsr.converters.ConvertString(out); err != nil { return } diff --git a/dispatchers/dispatchers.go b/dispatchers/dispatchers.go index 401f1bf4e..52db1600a 100755 --- a/dispatchers/dispatchers.go +++ b/dispatchers/dispatchers.go @@ -222,8 +222,7 @@ func (dS *DispatcherService) V1Apier(apier interface{}, args *utils.MethodParame } } - tenant, _ := utils.IfaceAsString(parameters[utils.Tenant]) - tenant = utils.FirstNonEmpty(tenant, config.CgrConfig().GeneralCfg().DefaultTenant) + tenant := utils.FirstNonEmpty(utils.IfaceAsString(parameters[utils.Tenant]), config.CgrConfig().GeneralCfg().DefaultTenant) if dS.attrS != nil { if argD == nil { return utils.NewErrMandatoryIeMissing(utils.ArgDispatcherField) diff --git a/engine/action.go b/engine/action.go index 7428b30b8..bcc477e45 100644 --- a/engine/action.go +++ b/engine/action.go @@ -176,12 +176,8 @@ func cdrLogAction(acc *Account, a *Action, acs Actions, extraData interface{}) ( } //In case that we have extra data we populate default templates mapExtraData, _ := extraData.(map[string]interface{}) - var strVal string for key, val := range mapExtraData { - if strVal, err = utils.IfaceAsString(val); err != nil { - return - } - if defaultTemplate[key], err = config.NewRSRParsers(strVal, + if defaultTemplate[key], err = config.NewRSRParsers(utils.IfaceAsString(val), true, config.CgrConfig().GeneralCfg().RsrSepatarot); err != nil { return } @@ -965,8 +961,7 @@ func (cdrP *cdrLogProvider) FieldAsString(fldPath []string) (data string, err er if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface diff --git a/engine/attributes.go b/engine/attributes.go index cfc2da9c1..a12a33973 100644 --- a/engine/attributes.go +++ b/engine/attributes.go @@ -213,7 +213,7 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) ( if err != nil { return nil, err } - substitute, err = utils.IfaceAsString(ifaceSum) + substitute = utils.IfaceAsString(ifaceSum) case utils.MetaValueExponent: if len(attribute.Value) != 2 { return nil, fmt.Errorf("invalid arguments <%s> to %s", @@ -254,11 +254,7 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) ( continue } if attribute.Type == utils.META_COMPOSED { - evStrVal, err := utils.IfaceAsString(rply.CGREvent.Event[attribute.FieldName]) - if err != nil { - return nil, err - } - substitute = evStrVal + substitute + substitute = utils.IfaceAsString(rply.CGREvent.Event[attribute.FieldName]) + substitute } rply.CGREvent.Event[attribute.FieldName] = substitute diff --git a/engine/filterhelpers.go b/engine/filterhelpers.go index 5ef4c6a87..5e146344e 100644 --- a/engine/filterhelpers.go +++ b/engine/filterhelpers.go @@ -19,7 +19,6 @@ along with this program. If not, see package engine import ( - "fmt" "strings" "github.com/cgrates/cgrates/config" @@ -71,13 +70,7 @@ func MatchingItemIDsForEvent(ev map[string]interface{}, stringFldIDs, prefixFldI continue } if _, cached := stringFieldVals[fldName]; !cached { - strVal, err := utils.IfaceAsString(fieldValIf) - if err != nil { - utils.Logger.Warning( - fmt.Sprintf("<%s> cannot cast field: %s into string", utils.FilterS, fldName)) - continue - } - stringFieldVals[fldName] = strVal + stringFieldVals[fldName] = utils.IfaceAsString(fieldValIf) } fldVal := stringFieldVals[fldName] fldVals := []string{fldVal} diff --git a/engine/mapevent.go b/engine/mapevent.go index c329a880b..424fcb60d 100644 --- a/engine/mapevent.go +++ b/engine/mapevent.go @@ -78,10 +78,10 @@ func (me MapEvent) GetString(fldName string) (out string, err error) { if !has { return "", utils.ErrNotFound } - return utils.IfaceAsString(fldIface) + return utils.IfaceAsString(fldIface), nil } -func (me MapEvent) GetInt64(fldName string) (out int64, err error) { +func (me MapEvent) GetTInt64(fldName string) (out int64, err error) { fldIface, has := me[fldName] if !has { return 0, utils.ErrNotFound @@ -160,25 +160,13 @@ func (me MapEvent) AsMapString(ignoredFlds utils.StringMap) (mp map[string]strin if ignoredFlds.HasKey(k) { continue } - var out string - if out, err = utils.IfaceAsString(v); err != nil { - return nil, err - } - mp[k] = out + mp[k] = utils.IfaceAsString(v) } return } func (me MapEvent) AsMapStringIgnoreErrors(ignoredFlds utils.StringMap) (mp map[string]string) { - mp = make(map[string]string) - for k, v := range me { - if ignoredFlds.HasKey(k) { - continue - } - if out, err := utils.IfaceAsString(v); err == nil { - mp[k] = out - } - } + mp, _ = me.AsMapString(ignoredFlds) return } @@ -187,62 +175,37 @@ func (me MapEvent) AsCDR(cfg *config.CGRConfig, tnt, tmz string) (cdr *CDR, err cdr = &CDR{Tenant: tnt, Cost: -1.0, ExtraFields: make(map[string]string)} for k, v := range me { if _, has := utils.MainCDRFieldsMap[k]; !has { // not primary field, populate extra ones - if cdr.ExtraFields[k], err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.ExtraFields[k] = utils.IfaceAsString(v) continue } switch k { default: + // for the momment this return can not be reached because we implemented a case for every MainCDRField return nil, fmt.Errorf("unimplemented CDR field: <%s>", k) case utils.CGRID: - if cdr.CGRID, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.CGRID = utils.IfaceAsString(v) case utils.RunID: - if cdr.RunID, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.RunID = utils.IfaceAsString(v) case utils.OriginHost: - if cdr.OriginHost, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.OriginHost = utils.IfaceAsString(v) case utils.Source: - if cdr.Source, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.Source = utils.IfaceAsString(v) case utils.OriginID: - if cdr.OriginID, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.OriginID = utils.IfaceAsString(v) case utils.ToR: - if cdr.ToR, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.ToR = utils.IfaceAsString(v) case utils.RequestType: - if cdr.RequestType, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.RequestType = utils.IfaceAsString(v) case utils.Tenant: - if cdr.Tenant, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.Tenant = utils.IfaceAsString(v) case utils.Category: - if cdr.Category, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.Category = utils.IfaceAsString(v) case utils.Account: - if cdr.Account, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.Account = utils.IfaceAsString(v) case utils.Subject: - if cdr.Subject, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.Subject = utils.IfaceAsString(v) case utils.Destination: - if cdr.Destination, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.Destination = utils.IfaceAsString(v) case utils.SetupTime: if cdr.SetupTime, err = utils.IfaceAsTime(v, tmz); err != nil { return nil, err @@ -264,9 +227,7 @@ func (me MapEvent) AsCDR(cfg *config.CGRConfig, tnt, tmz string) (cdr *CDR, err return nil, err } case utils.CostSource: - if cdr.CostSource, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.CostSource = utils.IfaceAsString(v) case utils.Cost: if cdr.Cost, err = utils.IfaceAsFloat64(v); err != nil { return nil, err @@ -276,9 +237,7 @@ func (me MapEvent) AsCDR(cfg *config.CGRConfig, tnt, tmz string) (cdr *CDR, err return nil, err } case utils.ExtraInfo: - if cdr.ExtraInfo, err = utils.IfaceAsString(v); err != nil { - return nil, err - } + cdr.ExtraInfo = utils.IfaceAsString(v) case utils.OrderID: if cdr.OrderID, err = utils.IfaceAsTInt64(v); err != nil { return nil, err diff --git a/engine/mapevent_test.go b/engine/mapevent_test.go index 5b5dc27ee..557a88144 100644 --- a/engine/mapevent_test.go +++ b/engine/mapevent_test.go @@ -362,6 +362,15 @@ func TestMapEventAsCDR(t *testing.T) { if _, err := me.AsCDR(nil, utils.EmptyString, utils.EmptyString); err == nil { t.Errorf("Expecting not null error, received: null error") } + me = MapEvent{"CostDetails": "clearly not CostDetails string"} + if _, err := me.AsCDR(nil, utils.EmptyString, utils.EmptyString); err == nil { + t.Errorf("Expecting not null error, received: null error") + } + me = MapEvent{"OrderID": "clearly not int64 string"} + if _, err := me.AsCDR(nil, utils.EmptyString, utils.EmptyString); err == nil { + t.Errorf("Expecting not null error, received: null error") + } + me = MapEvent{"ExtraField1": 5, "ExtraField2": "extra"} expected = &CDR{ Cost: -1.0, @@ -402,6 +411,50 @@ func TestMapEventAsCDR(t *testing.T) { } else if !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } + me = MapEvent{ + utils.CGRID: "da39a3ee5e6b4b0d3255bfef95601890afd80709", + utils.RunID: utils.MetaDefault, + utils.OriginHost: utils.FreeSWITCHAgent, + utils.OriginID: "127.0.0.1", + utils.ToR: utils.VOICE, + utils.RequestType: utils.META_PREPAID, + utils.Tenant: "cgrates.org", + utils.Category: utils.CALL, + utils.Account: "10010", + utils.Subject: "10010", + utils.Destination: "10012", + "ExtraField1": 5, + "Source": 1001, + "CostSource": "1002", + "ExtraField2": "extra", + "ExtraInfo": "ACCOUNT_NOT_FOUND", + } + expected = &CDR{ + CGRID: "da39a3ee5e6b4b0d3255bfef95601890afd80709", + RunID: utils.MetaDefault, + OriginHost: utils.FreeSWITCHAgent, + OriginID: "127.0.0.1", + ToR: utils.VOICE, + RequestType: utils.META_PREPAID, + Tenant: "cgrates.org", + Category: utils.CALL, + Account: "10010", + Subject: "10010", + Destination: "10012", + Cost: -1.0, + Source: "1001", + CostSource: "1002", + ExtraFields: map[string]string{ + "ExtraField1": "5", + "ExtraField2": "extra", + }, + ExtraInfo: "ACCOUNT_NOT_FOUND", + } + if rply, err := me.AsCDR(cfg, utils.EmptyString, utils.EmptyString); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rply) { + t.Errorf("Expecting %+v, received: %+v", expected, rply) + } ec1 := &EventCost{ CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41", RunID: utils.META_DEFAULT, @@ -614,3 +667,72 @@ func TestMapEventAsCDR(t *testing.T) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } } + +func TestMapEventGetTInt64(t *testing.T) { + if rply, err := mapEv.GetTInt64("test2"); err != nil { + t.Error(err) + } else if rply != int64(42) { + t.Errorf("Expecting %+v, received: %+v", int64(42), rply) + } + + if rply, err := mapEv.GetTInt64("test3"); err != nil { + t.Error(err) + } else if rply != int64(42) { + t.Errorf("Expecting %+v, received: %+v", int64(42), rply) + } + + if rply, err := mapEv.GetTInt64("test4"); err == nil { + t.Errorf("Expecting error, received: %+v with error %v", rply, err) + } + + if rply, err := mapEv.GetTInt64("0test"); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Errorf("Expecting error: %v, received: %+v with error %v", utils.ErrNotFound, rply, err) + } +} + +func TestMapEventGetDurationPtr(t *testing.T) { + if rply, err := mapEv.GetDurationPtr("test4"); err == nil { + t.Errorf("Expecting error, received: %+v with error %v", rply, err) + } + if rply, err := mapEv.GetDurationPtr("test"); err != utils.ErrNotFound { + t.Errorf("Expected: %+v, received: %+v", utils.ErrNotFound, err) + } else if rply != nil { + t.Errorf("Expected: %+v , received duration: %+v", nil, rply) + } + expected := utils.DurationPointer(time.Duration(10 * time.Second)) + if rply, err := mapEv.GetDurationPtr("test6"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rply) { + t.Errorf("Expecting %+v, received: %+v", expected, rply) + } + expected = utils.DurationPointer(time.Duration(42 * time.Second)) + if rply, err := mapEv.GetDurationPtr("test7"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rply) { + t.Errorf("Expecting %+v, received: %+v", expected, rply) + } + expected = utils.DurationPointer(time.Duration(42)) + if rply, err := mapEv.GetDurationPtr("test2"); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rply) { + t.Errorf("Expecting %+v, received: %+v", expected, rply) + } +} + +func TestMapEventGetDurationPtrIgnoreErrors(t *testing.T) { + if rply := mapEv.GetDurationPtrIgnoreErrors("test"); rply != nil { + t.Errorf("Expected: %+v, received: %+v", nil, rply) + } + expected := utils.DurationPointer(time.Duration(10 * time.Second)) + if rply := mapEv.GetDurationPtrIgnoreErrors("test6"); *rply != *expected { + t.Errorf("Expected: %+v, received: %+v", expected, rply) + } + expected = utils.DurationPointer(time.Duration(42 * time.Second)) + if rply := mapEv.GetDurationPtrIgnoreErrors("test7"); *rply != *expected { + t.Errorf("Expected: %+v, received: %+v", expected, rply) + } + expected = utils.DurationPointer(time.Duration(42)) + if rply := mapEv.GetDurationPtrIgnoreErrors("test2"); *rply != *expected { + t.Errorf("Expected: %+v, received: %+v", expected, rply) + } +} diff --git a/engine/safevent.go b/engine/safevent.go index 7214cd0bb..6b1544cbc 100644 --- a/engine/safevent.go +++ b/engine/safevent.go @@ -126,9 +126,9 @@ func (se *SafEvent) GetString(fldName string) (out string, err error) { return } -func (se SafEvent) GetInt64(fldName string) (out int64, err error) { +func (se SafEvent) GetTInt64(fldName string) (out int64, err error) { se.RLock() - out, err = se.Me.GetInt64(fldName) + out, err = se.Me.GetTInt64(fldName) se.RUnlock() return } @@ -219,7 +219,7 @@ func (se *SafEvent) GetSetString(fldName string, setVal string) (out string, err return } // should be present, return it as string - return utils.IfaceAsString(outIface) + return utils.IfaceAsString(outIface), nil } // GetMapInterface returns the map stored internally without cloning it diff --git a/engine/safevent_test.go b/engine/safevent_test.go index 589bac8ba..466ea68f1 100644 --- a/engine/safevent_test.go +++ b/engine/safevent_test.go @@ -790,3 +790,61 @@ func TestSafEventAsCDR(t *testing.T) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } } + +func TestSafEventGetTInt64(t *testing.T) { + if rply, err := safEv.GetTInt64("test2"); err != nil { + t.Error(err) + } else if rply != int64(42) { + t.Errorf("Expecting %+v, received: %+v", int64(42), rply) + } + + if rply, err := safEv.GetTInt64("test3"); err != nil { + t.Error(err) + } else if rply != int64(42) { + t.Errorf("Expecting %+v, received: %+v", int64(42), rply) + } + + if rply, err := safEv.GetTInt64("test4"); err == nil { + t.Errorf("Expecting error, received: %+v with error %v", rply, err) + } + + if rply, err := safEv.GetTInt64("0test"); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Errorf("Expecting error: %v, received: %+v with error %v", utils.ErrNotFound, rply, err) + } +} + +func TestSafEventGetDurationPtrIgnoreErrors(t *testing.T) { + if rply := safEv.GetDurationPtrIgnoreErrors("test"); rply != nil { + t.Errorf("Expected: %+v, received: %+v", nil, rply) + } + expected := utils.DurationPointer(time.Duration(10 * time.Second)) + if rply := safEv.GetDurationPtrIgnoreErrors("test6"); *rply != *expected { + t.Errorf("Expected: %+v, received: %+v", expected, rply) + } + expected = utils.DurationPointer(time.Duration(42 * time.Second)) + if rply := safEv.GetDurationPtrIgnoreErrors("test7"); *rply != *expected { + t.Errorf("Expected: %+v, received: %+v", expected, rply) + } + expected = utils.DurationPointer(time.Duration(42)) + if rply := safEv.GetDurationPtrIgnoreErrors("test2"); *rply != *expected { + t.Errorf("Expected: %+v, received: %+v", expected, rply) + } +} + +func TestSafEventGetDurationOrDefault(t *testing.T) { + safEv.Remove("test7") + expected := time.Duration(10 * time.Second) + if rply, err := safEv.GetDurationOrDefault("test7", time.Duration(10*time.Second)); err != nil { + t.Error(err) + } else if rply != expected { + t.Errorf("Expecting %+v, received: %+v", expected, rply) + } + safEv.Set("test7", "42s") + expected = time.Duration(42 * time.Second) + if rply, err := safEv.GetDurationOrDefault("test7", time.Second); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rply) { + t.Errorf("Expecting %+v, received: %+v", expected, rply) + } + +} diff --git a/loaders/libloader.go b/loaders/libloader.go index f2823df90..9f4f3b101 100644 --- a/loaders/libloader.go +++ b/loaders/libloader.go @@ -127,8 +127,7 @@ func (cP *csvProvider) FieldAsString(fldPath []string) (data string, err error) if err != nil { return } - data, err = utils.IfaceAsString(valIface) - return + return utils.IfaceAsString(valIface), nil } // AsNavigableMap is part of engine.DataProvider interface diff --git a/utils/cgrevent.go b/utils/cgrevent.go index ad34e9bc2..b221e44c1 100644 --- a/utils/cgrevent.go +++ b/utils/cgrevent.go @@ -52,7 +52,7 @@ func (ev *CGREvent) FieldAsString(fldName string) (val string, err error) { if !has { return "", ErrNotFound } - return IfaceAsString(iface) + return IfaceAsString(iface), nil } // FieldAsTime returns a field as Time instance diff --git a/utils/dataconverter.go b/utils/dataconverter.go index dce15fad1..2bd716896 100644 --- a/utils/dataconverter.go +++ b/utils/dataconverter.go @@ -37,11 +37,7 @@ func (dcs DataConverters) ConvertString(in string) (out string, err error) { return } } - out, err = IfaceAsString(outIface) - if err != nil { - return "", NewErrStringCast(outIface) - } - return + return IfaceAsString(outIface), nil } // DataConverter represents functions which should convert input into output diff --git a/utils/reflect.go b/utils/reflect.go index 5700b62eb..a5f9e09bf 100644 --- a/utils/reflect.go +++ b/utils/reflect.go @@ -106,11 +106,7 @@ func ReflectFieldAsString(intf interface{}, fldName, extraFieldsLabel string) (s case reflect.Float64: return strconv.FormatFloat(vOf.Float(), 'f', -1, 64), nil case reflect.Interface: - strVal, err := IfaceAsString(field) - if err != nil { - return "", fmt.Errorf("Cannot convert to string field type: %s", vOf.Kind().String()) - } - return strVal, nil + return IfaceAsString(field), nil default: return "", fmt.Errorf("Cannot convert to string field type: %s", vOf.Kind().String()) } @@ -223,42 +219,38 @@ func IfaceAsBool(itm interface{}) (b bool, err error) { return } -func IfaceAsString(fld interface{}) (out string, err error) { - switch fld.(type) { +func IfaceAsString(fld interface{}) (out string) { + switch value := fld.(type) { case nil: return case int: - return strconv.Itoa(fld.(int)), nil + return strconv.Itoa(value) case int32: - return strconv.FormatInt(int64(fld.(int32)), 10), nil + return strconv.FormatInt(int64(value), 10) case int64: - return strconv.FormatInt(fld.(int64), 10), nil + return strconv.FormatInt(value, 10) case uint32: - return strconv.FormatUint(uint64(fld.(uint32)), 10), nil + return strconv.FormatUint(uint64(value), 10) case uint64: - return strconv.FormatUint(fld.(uint64), 10), nil + return strconv.FormatUint(value, 10) case bool: - return strconv.FormatBool(fld.(bool)), nil + return strconv.FormatBool(value) case float32: - return strconv.FormatFloat(float64(fld.(float32)), 'f', -1, 64), nil + return strconv.FormatFloat(float64(value), 'f', -1, 64) case float64: - return strconv.FormatFloat(fld.(float64), 'f', -1, 64), nil + return strconv.FormatFloat(value, 'f', -1, 64) case []uint8: - if byteVal, canCast := fld.([]byte); !canCast { - return "", ErrNotConvertibleNoCaps - } else { - return string(byteVal), nil - } + return string(value) // byte is an alias for uint8 conversions implicit case time.Duration: - return fld.(time.Duration).String(), nil + return value.String() case time.Time: - return fld.(time.Time).Format(time.RFC3339), nil + return value.Format(time.RFC3339) case net.IP: - return fld.(net.IP).String(), nil + return value.String() case string: - return fld.(string), nil + return value default: // Maybe we are lucky and the value converts to string - return ToJSON(fld), nil + return ToJSON(fld) } } diff --git a/utils/reflect_test.go b/utils/reflect_test.go index ee3f84003..1e05458bf 100644 --- a/utils/reflect_test.go +++ b/utils/reflect_test.go @@ -252,55 +252,37 @@ func TestStringToInterface(t *testing.T) { func TestIfaceAsString(t *testing.T) { val := interface{}("string1") - if rply, err := IfaceAsString(val); err != nil { - t.Error(err) - } else if rply != "string1" { + if rply := IfaceAsString(val); rply != "string1" { t.Errorf("Expeced string1 ,recived %+v", rply) } val = interface{}(123) - if rply, err := IfaceAsString(val); err != nil { - t.Error(err) - } else if rply != "123" { + if rply := IfaceAsString(val); rply != "123" { t.Errorf("Expeced 123 ,recived %+v", rply) } val = interface{}([]byte("byte_val")) - if rply, err := IfaceAsString(val); err != nil { - t.Error(err) - } else if rply != "byte_val" { + if rply := IfaceAsString(val); rply != "byte_val" { t.Errorf("Expeced byte_val ,recived %+v", rply) } val = interface{}(true) - if rply, err := IfaceAsString(val); err != nil { - t.Error(err) - } else if rply != "true" { + if rply := IfaceAsString(val); rply != "true" { t.Errorf("Expeced true ,recived %+v", rply) } - if rply, err := IfaceAsString(time.Duration(1 * time.Second)); err != nil { - t.Error(err) - } else if rply != "1s" { + if rply := IfaceAsString(time.Duration(1 * time.Second)); rply != "1s" { t.Errorf("Expeced 1s ,recived %+v", rply) } - if rply, err := IfaceAsString(nil); err != nil { - t.Error(err) - } else if rply != "" { + if rply := IfaceAsString(nil); rply != "" { t.Errorf("Expeced ,recived %+v", rply) } val = interface{}(net.ParseIP("127.0.0.1")) - if rply, err := IfaceAsString(val); err != nil { - t.Error(err) - } else if rply != "127.0.0.1" { + if rply := IfaceAsString(val); rply != "127.0.0.1" { t.Errorf("Expeced ,recived %+v", rply) } val = interface{}(10.23) - if rply, err := IfaceAsString(val); err != nil { - t.Error(err) - } else if rply != "10.23" { + if rply := IfaceAsString(val); rply != "10.23" { t.Errorf("Expeced ,recived %+v", rply) } val = interface{}(time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)) - if rply, err := IfaceAsString(val); err != nil { - t.Error(err) - } else if rply != "2009-11-10T23:00:00Z" { + if rply := IfaceAsString(val); rply != "2009-11-10T23:00:00Z" { t.Errorf("Expeced ,recived %+v", rply) } } diff --git a/utils/rsrfield.go b/utils/rsrfield.go index 117677519..c34b815ce 100644 --- a/utils/rsrfield.go +++ b/utils/rsrfield.go @@ -186,10 +186,7 @@ func (rsrf *RSRField) filtersPassing(value string) bool { // Parse will parse the value out considering converters and filters func (rsrf *RSRField) Parse(value interface{}) (out string, err error) { - if out, err = IfaceAsString(value); err != nil { - return - } - out = rsrf.parseValue(out) + out = rsrf.parseValue(IfaceAsString(value)) if out, err = rsrf.converters.ConvertString(out); err != nil { return } diff --git a/utils/struct.go b/utils/struct.go index 12579d799..dccd01fed 100644 --- a/utils/struct.go +++ b/utils/struct.go @@ -288,11 +288,7 @@ func UpdateStructWithIfaceMap(s interface{}, mp map[string]interface{}) (err err fld.SetFloat(valFlt) } case reflect.String: - if valStr, err := IfaceAsString(val); err != nil { - return fmt.Errorf("cannot convert field: %+v to string", val) - } else { - fld.SetString(valStr) - } + fld.SetString(IfaceAsString(val)) default: // improper use of function return fmt.Errorf("cannot update unsupported struct field: %+v", fld) }