SMG event using CastFieldIfToString instead of deprecated ConvertIfaceToString, SMGClientV1.DisconnectSession with nanosecond units, more test fixes

This commit is contained in:
DanB
2017-11-06 12:52:46 +01:00
parent 774dc123c8
commit 48ad63baa3
9 changed files with 66 additions and 92 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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),

View File

@@ -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")
}

View File

@@ -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])

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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" {