From 48ad63baa3cb5cb8c862d92b449e693913071105 Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 6 Nov 2017 12:52:46 +0100 Subject: [PATCH] SMG event using CastFieldIfToString instead of deprecated ConvertIfaceToString, SMGClientV1.DisconnectSession with nanosecond units, more test fixes --- engine/action.go | 5 +-- engine/cdr_test.go | 4 +-- sessionmanager/smg_event.go | 56 +++++++++++++++--------------- sessionmanager/smg_session.go | 3 +- sessionmanager/smgbirpc_it_test.go | 24 ++++++++----- utils/coreutils.go | 28 --------------- utils/coreutils_test.go | 19 ---------- utils/reflect.go | 3 -- utils/reflect_test.go | 16 +++++++++ 9 files changed, 66 insertions(+), 92 deletions(-) diff --git a/engine/action.go b/engine/action.go index 8ed9cdaaa..2aaddaa8d 100644 --- a/engine/action.go +++ b/engine/action.go @@ -213,14 +213,15 @@ func cdrLogAction(acc *Account, sq *CDRStatsQueueTriggered, a *Action, acs Actio // set stored cdr values var cdrs []*CDR for _, action := range acs { - if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET, TOPUP, TOPUP_RESET}, action.ActionType) || action.Balance == nil { + if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET, TOPUP, TOPUP_RESET}, action.ActionType) || + action.Balance == nil { continue // Only log specific actions } cdr := &CDR{RunID: action.ActionType, Source: CDRLOG, SetupTime: time.Now(), AnswerTime: time.Now(), OriginID: utils.GenUUID(), ExtraFields: make(map[string]string)} cdr.CGRID = utils.Sha1(cdr.OriginID, cdr.SetupTime.String()) - cdr.Usage = time.Duration(1) * time.Second + cdr.Usage = time.Duration(1) elem := reflect.ValueOf(cdr).Elem() for key, rsrFlds := range defaultTemplate { parsedValue := parseTemplateValue(rsrFlds, acc, action) diff --git a/engine/cdr_test.go b/engine/cdr_test.go index 4c8d6ccad..a94ee168b 100644 --- a/engine/cdr_test.go +++ b/engine/cdr_test.go @@ -395,7 +395,7 @@ func TestCDRAsExternalCDR(t *testing.T) { Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC), AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), - RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10), Cost: 1.01, + RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10 * time.Second), Cost: 1.01, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} expectOutCdr := &ExternalCDR{ CGRID: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()), @@ -403,7 +403,7 @@ func TestCDRAsExternalCDR(t *testing.T) { Source: utils.UNIT_TEST, RequestType: utils.META_RATED, Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: "2013-11-07T08:42:20Z", AnswerTime: "2013-11-07T08:42:26Z", RunID: utils.DEFAULT_RUNID, - Usage: "0.00000001", Cost: 1.01, CostDetails: "null", + Usage: "10s", Cost: 1.01, CostDetails: "null", ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} if cdrOut := storCdr.AsExternalCDR(); !reflect.DeepEqual(expectOutCdr, cdrOut) { t.Errorf("Expected: %+v, received: %+v", expectOutCdr, cdrOut) diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 8d3718d73..97e047956 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -43,7 +43,7 @@ func (ev SMGenericEvent) HasField(fieldName string) (hasField bool) { } func (self SMGenericEvent) GetName() string { - result, _ := utils.ConvertIfaceToString(self[utils.EVENT_NAME]) + result, _ := utils.CastFieldIfToString(self[utils.EVENT_NAME]) return result } @@ -51,7 +51,7 @@ func (self SMGenericEvent) GetTOR(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.TOR } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -65,7 +65,7 @@ func (self SMGenericEvent) GetOriginID(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.ACCID } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -77,7 +77,7 @@ func (self SMGenericEvent) GetDirection(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.DIRECTION } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -85,7 +85,7 @@ func (self SMGenericEvent) GetAccount(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.ACCOUNT } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -93,7 +93,7 @@ func (self SMGenericEvent) GetSubject(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.SUBJECT } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -101,7 +101,7 @@ func (self SMGenericEvent) GetDestination(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.DESTINATION } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -113,7 +113,7 @@ func (self SMGenericEvent) GetCategory(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.CATEGORY } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -121,7 +121,7 @@ func (self SMGenericEvent) GetTenant(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.TENANT } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -129,7 +129,7 @@ func (self SMGenericEvent) GetReqType(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.REQTYPE } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -137,7 +137,7 @@ func (self SMGenericEvent) GetSetupTime(fieldName, timezone string) (time.Time, if fieldName == utils.META_DEFAULT { fieldName = utils.SETUP_TIME } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return utils.ParseTimeDetectLayout(result, timezone) } @@ -145,7 +145,7 @@ func (self SMGenericEvent) GetAnswerTime(fieldName, timezone string) (time.Time, if fieldName == utils.META_DEFAULT { fieldName = utils.ANSWER_TIME } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return utils.ParseTimeDetectLayout(result, timezone) } @@ -170,7 +170,7 @@ func (self SMGenericEvent) GetUsage(fieldName string) (time.Duration, error) { if !hasVal { return nilDuration, utils.ErrNotFound } - result, _ := utils.ConvertIfaceToString(valIf) + result, _ := utils.CastFieldIfToString(valIf) return utils.ParseDurationWithNanosecs(result) } @@ -182,7 +182,7 @@ func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error) if !hasVal { return nilDuration, utils.ErrNotFound } - result, _ := utils.ConvertIfaceToString(valStr) + result, _ := utils.CastFieldIfToString(valStr) return utils.ParseDurationWithNanosecs(result) } @@ -190,7 +190,7 @@ func (self SMGenericEvent) GetLastUsed(fieldName string) (time.Duration, error) func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxDelay *time.Duration) time.Duration { valIf, hasVal := self[utils.SessionTTL] if hasVal { - ttlStr, converted := utils.ConvertIfaceToString(valIf) + ttlStr, converted := utils.CastFieldIfToString(valIf) if !converted { utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot convert SessionTTL, disabling functionality for event: <%s>", self.GetCGRID(utils.META_DEFAULT))) @@ -209,7 +209,7 @@ func (self SMGenericEvent) GetSessionTTL(sesTTL time.Duration, cfgSessionTTLMaxD sessionTTLMaxDelay = cfgSessionTTLMaxDelay.Nanoseconds() / 1000000 // Milliseconds precision } if sesTTLMaxDelayIf, hasVal := self[utils.SessionTTLMaxDelay]; hasVal { - maxTTLDelaxStr, converted := utils.ConvertIfaceToString(sesTTLMaxDelayIf) + maxTTLDelaxStr, converted := utils.CastFieldIfToString(sesTTLMaxDelayIf) if !converted { utils.Logger.Warning(fmt.Sprintf("SMGenericEvent, cannot convert SessionTTLMaxDelay, disabling functionality for event: <%s>", self.GetCGRID(utils.META_DEFAULT))) @@ -236,7 +236,7 @@ func (self SMGenericEvent) GetSessionTTLLastUsed() *time.Duration { if !hasVal { return nil } - ttlStr, converted := utils.ConvertIfaceToString(valIf) + ttlStr, converted := utils.CastFieldIfToString(valIf) if !converted { return nil } @@ -253,7 +253,7 @@ func (self SMGenericEvent) GetSessionTTLUsage() *time.Duration { if !hasVal { return nil } - ttlStr, converted := utils.ConvertIfaceToString(valIf) + ttlStr, converted := utils.CastFieldIfToString(valIf) if !converted { return nil } @@ -272,7 +272,7 @@ func (self SMGenericEvent) GetMaxUsage(fieldName string, cfgMaxUsage time.Durati if !hasIt { return cfgMaxUsage, nil } - result, _ := utils.ConvertIfaceToString(maxUsageStr) + result, _ := utils.CastFieldIfToString(maxUsageStr) return utils.ParseDurationWithNanosecs(result) } @@ -280,7 +280,7 @@ func (self SMGenericEvent) GetPdd(fieldName string) (time.Duration, error) { if fieldName == utils.META_DEFAULT { fieldName = utils.PDD } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return utils.ParseDurationWithNanosecs(result) } @@ -288,7 +288,7 @@ func (self SMGenericEvent) GetSupplier(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.SUPPLIER } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -296,7 +296,7 @@ func (self SMGenericEvent) GetDisconnectCause(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.DISCONNECT_CAUSE } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -304,7 +304,7 @@ func (self SMGenericEvent) GetOriginatorIP(fieldName string) string { if fieldName == utils.META_DEFAULT { fieldName = utils.CDRHOST } - result, _ := utils.ConvertIfaceToString(self[fieldName]) + result, _ := utils.CastFieldIfToString(self[fieldName]) return result } @@ -319,7 +319,7 @@ func (self SMGenericEvent) GetExtraFields() map[string]string { if utils.IsSliceMember(primaryFields, key) { continue } - result, _ := utils.ConvertIfaceToString(val) + result, _ := utils.CastFieldIfToString(val) extraFields[key] = result } return extraFields @@ -330,7 +330,7 @@ func (self SMGenericEvent) GetFieldAsString(fieldName string) (string, error) { if !hasVal { return "", utils.ErrNotFound } - result, converted := utils.ConvertIfaceToString(valIf) + result, converted := utils.CastFieldIfToString(valIf) if !converted { return "", utils.ErrNotConvertible } @@ -405,7 +405,7 @@ func (self SMGenericEvent) ParseEventValue(rsrFld *utils.RSRField, timezone stri case utils.COST: return rsrFld.ParseValue(strconv.FormatFloat(-1, 'f', -1, 64)) // Recommended to use FormatCost default: - strVal, _ := utils.ConvertIfaceToString(self[rsrFld.Id]) + strVal, _ := utils.CastFieldIfToString(self[rsrFld.Id]) val := rsrFld.ParseValue(strVal) return val } @@ -448,8 +448,8 @@ func (self SMGenericEvent) ComputeLcr() bool { } func (self SMGenericEvent) AsLcrRequest() *engine.LcrRequest { - setupTimeStr, _ := utils.ConvertIfaceToString(self[utils.SETUP_TIME]) - usageStr, _ := utils.ConvertIfaceToString(self[utils.USAGE]) + setupTimeStr, _ := utils.CastFieldIfToString(self[utils.SETUP_TIME]) + usageStr, _ := utils.CastFieldIfToString(self[utils.USAGE]) return &engine.LcrRequest{ Direction: self.GetDirection(utils.META_DEFAULT), Tenant: self.GetTenant(utils.META_DEFAULT), diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go index fae1689d0..b1f6ef79a 100644 --- a/sessionmanager/smg_session.go +++ b/sessionmanager/smg_session.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" "reflect" - "strconv" "sync" "time" @@ -153,7 +152,7 @@ func (self *SMGSession) debit(dur time.Duration, lastUsed *time.Duration) (time. // Send disconnect order to remote connection func (self *SMGSession) disconnectSession(reason string) error { - self.EventStart[utils.USAGE] = strconv.FormatFloat(self.TotalUsage.Seconds(), 'f', -1, 64) // Set the usage to total one debitted + self.EventStart[utils.USAGE] = self.TotalUsage.Nanoseconds() // Set the usage to total one debitted if self.clntConn == nil || reflect.ValueOf(self.clntConn).IsNil() { return errors.New("Calling SMGClientV1.DisconnectSession requires bidirectional JSON connection") } diff --git a/sessionmanager/smgbirpc_it_test.go b/sessionmanager/smgbirpc_it_test.go index 160edc254..0a96b5063 100644 --- a/sessionmanager/smgbirpc_it_test.go +++ b/sessionmanager/smgbirpc_it_test.go @@ -39,7 +39,8 @@ var ( disconnectEvChan = make(chan *utils.AttrDisconnectSession) ) -func handleDisconnectSession(clnt *rpc2.Client, args *utils.AttrDisconnectSession, reply *string) error { +func handleDisconnectSession(clnt *rpc2.Client, + args *utils.AttrDisconnectSession, reply *string) error { disconnectEvChan <- args *reply = utils.OK return nil @@ -79,11 +80,14 @@ func TestSMGBiRPCStartEngine(t *testing.T) { // Connect rpc client to rater func TestSMGBiRPCApierRpcConn(t *testing.T) { + time.Sleep(time.Duration(1 * time.Second)) clntHandlers := map[string]interface{}{"SMGClientV1.DisconnectSession": handleDisconnectSession} - if _, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, clntHandlers); err != nil { // First attempt is to make sure multiple clients are supported + if _, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, + clntHandlers); err != nil { // First attempt is to make sure multiple clients are supported t.Fatal(err) } - if smgBiRPC, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, clntHandlers); err != nil { + if smgBiRPC, err = utils.NewBiJSONrpcClient(smgBiRPCCfg.SmGenericConfig.ListenBijson, + clntHandlers); err != nil { t.Fatal(err) } if smgRPC, err = jsonrpc.Dial("tcp", smgBiRPCCfg.RPCJSONListen); err != nil { // Connect also simple RPC so we can check accounts and such @@ -103,8 +107,11 @@ func TestSMGBiRPCTPFromFolder(t *testing.T) { func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { // Create a balance with 1 second inside and rating increments of 1ms (to be compatible with debit interval) - attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", Account: "TestSMGBiRPCSessionAutomaticDisconnects", BalanceType: utils.VOICE, BalanceID: utils.StringPointer("TestSMGBiRPCSessionAutomaticDisconnects"), - Value: utils.Float64Pointer(0.01), RatingSubject: utils.StringPointer("*zero1ms")} + attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org", + Account: "TestSMGBiRPCSessionAutomaticDisconnects", BalanceType: utils.VOICE, + BalanceID: utils.StringPointer("TestSMGBiRPCSessionAutomaticDisconnects"), + Value: utils.Float64Pointer(0.01), + RatingSubject: utils.StringPointer("*zero1ms")} var reply string if err := smgRPC.Call("ApierV2.SetBalance", attrSetBalance, &reply); err != nil { t.Error(err) @@ -165,15 +172,16 @@ func TestSMGBiRPCSessionAutomaticDisconnects(t *testing.T) { } else if reply != utils.OK { t.Errorf("Received reply: %s", reply) } - time.Sleep(time.Duration(10) * time.Millisecond) + time.Sleep(time.Duration(20) * time.Millisecond) var cdrs []*engine.ExternalCDR - req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} + req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, + DestinationPrefixes: []string{smgEv.GetDestination(utils.META_DEFAULT)}} if err := smgRPC.Call("ApierV2.GetCdrs", req, &cdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Usage != "0.01" { + if cdrs[0].Usage != "10ms" { t.Errorf("Unexpected CDR Usage received, cdr: %v %+v ", cdrs[0].Usage, cdrs[0]) } else if cdrs[0].CostSource != utils.SESSION_MANAGER_SOURCE { t.Errorf("Unexpected CDR CostSource received, cdr: %v %+v ", cdrs[0].CostSource, cdrs[0]) diff --git a/utils/coreutils.go b/utils/coreutils.go index b957943e3..361cb2540 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -479,34 +479,6 @@ func LogFull(v interface{}) { log.Print(ToIJSON(v)) } -// Used to convert from generic interface type towards string value -func ConvertIfaceToString(fld interface{}) (string, bool) { - var strVal string - var converted bool - switch fld.(type) { - case string: - strVal = fld.(string) - converted = true - case int: - strVal = strconv.Itoa(fld.(int)) - converted = true - case int64: - strVal = strconv.FormatInt(fld.(int64), 10) - converted = true - case bool: - strVal = strconv.FormatBool(fld.(bool)) - converted = true - case []uint8: - var byteVal []byte - if byteVal, converted = fld.([]byte); converted { - strVal = string(byteVal) - } - default: // Maybe we are lucky and the value converts to string - strVal, converted = fld.(string) - } - return strVal, converted -} - // Simple object cloner, b should be a pointer towards a value into which we want to decode func Clone(a, b interface{}) error { buff := new(bytes.Buffer) diff --git a/utils/coreutils_test.go b/utils/coreutils_test.go index a9ea152d2..b1173425a 100644 --- a/utils/coreutils_test.go +++ b/utils/coreutils_test.go @@ -409,25 +409,6 @@ func TestConcatenatedKey(t *testing.T) { } } -func TestConvertIfaceToString(t *testing.T) { - val := interface{}("string1") - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "string1" { - t.Error(resVal, converted) - } - val = interface{}(123) - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "123" { - t.Error(resVal, converted) - } - val = interface{}([]byte("byte_val")) - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "byte_val" { - t.Error(resVal, converted) - } - val = interface{}(true) - if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "true" { - t.Error(resVal, converted) - } -} - func TestMandatory(t *testing.T) { _, err := FmtFieldWidth("", "", 0, "", "", true) if err == nil { diff --git a/utils/reflect.go b/utils/reflect.go index 8b14b3de3..5af166639 100644 --- a/utils/reflect.go +++ b/utils/reflect.go @@ -30,9 +30,6 @@ func CastFieldIfToString(fld interface{}) (string, bool) { var strVal string var converted bool switch fld.(type) { - case string: - strVal = fld.(string) - converted = true case int: strVal = strconv.Itoa(fld.(int)) converted = true diff --git a/utils/reflect_test.go b/utils/reflect_test.go index 3e9c990b1..f4beaf715 100644 --- a/utils/reflect_test.go +++ b/utils/reflect_test.go @@ -218,6 +218,22 @@ func TestStringToInterface(t *testing.T) { } func TestCastFieldIfToString(t *testing.T) { + val := interface{}("string1") + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "string1" { + t.Error(resVal, converted) + } + val = interface{}(123) + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "123" { + t.Error(resVal, converted) + } + val = interface{}([]byte("byte_val")) + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "byte_val" { + t.Error(resVal, converted) + } + val = interface{}(true) + if resVal, converted := CastFieldIfToString(val); !converted || resVal != "true" { + t.Error(resVal, converted) + } if strVal, cast := CastFieldIfToString(time.Duration(1 * time.Second)); !cast { t.Error("cannot cast time.Duration") } else if strVal != "1s" {