Updated AttributeS matching

This commit is contained in:
Trial97
2020-07-21 17:59:56 +03:00
committed by Dan Christian Bogos
parent 6fe8d38764
commit 0cd91640a3
4 changed files with 259 additions and 148 deletions

View File

@@ -23,6 +23,7 @@ import (
"math"
"strconv"
"strings"
"time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
@@ -61,7 +62,7 @@ func (alS *AttributeService) Shutdown() (err error) {
}
// matchingAttributeProfilesForEvent returns ordered list of matching resources which are active by the time of the call
func (alS *AttributeService) attributeProfileForEvent(args *AttrArgsProcessEvent) (matchAttrPrfl *AttributeProfile, err error) {
func (alS *AttributeService) attributeProfileForEvent(args *AttrArgsProcessEvent, evNm utils.MapStorage, lastID string) (matchAttrPrfl *AttributeProfile, err error) {
var attrIDs []string
contextVal := utils.MetaDefault
if args.Context != nil && *args.Context != "" {
@@ -94,11 +95,6 @@ func (alS *AttributeService) attributeProfileForEvent(args *AttrArgsProcessEvent
}
attrIDs = aPrflIDs.AsSlice()
}
evNm := utils.MapStorage{
utils.MetaReq: args.Event,
utils.MetaOpts: args.Opts,
}
for _, apID := range attrIDs {
aPrfl, err := alS.dm.GetAttributeProfile(args.Tenant, apID, true, true, utils.NonTransactional)
if err != nil {
@@ -121,7 +117,8 @@ func (alS *AttributeService) attributeProfileForEvent(args *AttrArgsProcessEvent
} else if !pass {
continue
}
if matchAttrPrfl == nil || matchAttrPrfl.Weight < aPrfl.Weight {
if (matchAttrPrfl == nil || matchAttrPrfl.Weight < aPrfl.Weight) &&
apID != lastID {
matchAttrPrfl = aPrfl
}
}
@@ -169,11 +166,11 @@ type AttrArgsProcessEvent struct {
}
// processEvent will match event with attribute profile and do the necessary replacements
func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils.MapStorage, lastID string) (
rply *AttrSProcessEventReply, err error) {
attrPrf, err := alS.attributeProfileForEvent(args)
if err != nil {
return nil, err
var attrPrf *AttributeProfile
if attrPrf, err = alS.attributeProfileForEvent(args, evNm, lastID); err != nil {
return
}
rply = &AttrSProcessEventReply{
MatchedProfiles: []string{attrPrf.ID},
@@ -181,22 +178,18 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
Opts: args.Opts,
blocker: attrPrf.Blocker,
}
evNm := utils.MapStorage{
utils.MetaReq: rply.CGREvent.Event,
utils.MetaOpts: rply.Opts,
}
for _, attribute := range attrPrf.Attributes {
//in case that we have filter for attribute send them to FilterS to be processed
if len(attribute.FilterIDs) != 0 {
if pass, err := alS.filterS.Pass(args.Tenant, attribute.FilterIDs,
var pass bool
if pass, err = alS.filterS.Pass(args.Tenant, attribute.FilterIDs,
evNm); err != nil {
return nil, err
return
} else if !pass {
continue
}
}
var substitute string
var err error
switch attribute.Type {
case utils.META_CONSTANT:
substitute, err = attribute.Value.ParseValue(utils.EmptyString)
@@ -206,77 +199,73 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
if len(attribute.Value) != 2 {
return nil, fmt.Errorf("invalid arguments <%s>", utils.ToJSON(attribute.Value))
}
strVal1, err := attribute.Value[0].ParseDataProvider(evNm)
if err != nil {
return nil, err
var strVal1 string
if strVal1, err = attribute.Value[0].ParseDataProvider(evNm); err != nil {
rply = nil
return
}
strVal2, err := attribute.Value[1].ParseDataProvider(evNm)
if err != nil {
return nil, err
var strVal2 string
if strVal2, err = attribute.Value[1].ParseDataProvider(evNm); err != nil {
rply = nil
return
}
tEnd, err := utils.ParseTimeDetectLayout(strVal1, utils.EmptyString)
if err != nil {
return nil, err
var tEnd time.Time
if tEnd, err = utils.ParseTimeDetectLayout(strVal1, utils.EmptyString); err != nil {
rply = nil
return
}
tStart, err := utils.ParseTimeDetectLayout(strVal2, utils.EmptyString)
if err != nil {
return nil, err
var tStart time.Time
if tStart, err = utils.ParseTimeDetectLayout(strVal2, utils.EmptyString); err != nil {
rply = nil
return
}
substitute = tEnd.Sub(tStart).String()
case utils.MetaSum:
iFaceVals := make([]interface{}, len(attribute.Value))
for i, val := range attribute.Value {
strVal, err := val.ParseDataProvider(evNm)
if err != nil {
return nil, err
}
iFaceVals[i] = utils.StringToInterface(strVal)
var ifaceVals []interface{}
if ifaceVals, err = getIfaceFromValues(attribute.Value, evNm); err != nil {
rply = nil
return
}
ifaceSum, err := utils.Sum(iFaceVals...)
if err != nil {
return nil, err
var ifaceSum interface{}
if ifaceSum, err = utils.Sum(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaDifference:
iFaceVals := make([]interface{}, len(attribute.Value))
for i, val := range attribute.Value {
strVal, err := val.ParseDataProvider(evNm)
if err != nil {
return nil, err
}
iFaceVals[i] = utils.StringToInterface(strVal)
var ifaceVals []interface{}
if ifaceVals, err = getIfaceFromValues(attribute.Value, evNm); err != nil {
rply = nil
return
}
ifaceSum, err := utils.Difference(iFaceVals...)
if err != nil {
return nil, err
var ifaceSum interface{}
if ifaceSum, err = utils.Difference(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaMultiply:
iFaceVals := make([]interface{}, len(attribute.Value))
for i, val := range attribute.Value {
strVal, err := val.ParseDataProvider(evNm)
if err != nil {
return nil, err
}
iFaceVals[i] = utils.StringToInterface(strVal)
var ifaceVals []interface{}
if ifaceVals, err = getIfaceFromValues(attribute.Value, evNm); err != nil {
rply = nil
return
}
ifaceSum, err := utils.Multiply(iFaceVals...)
if err != nil {
return nil, err
var ifaceSum interface{}
if ifaceSum, err = utils.Multiply(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaDivide:
iFaceVals := make([]interface{}, len(attribute.Value))
for i, val := range attribute.Value {
strVal, err := val.ParseDataProvider(evNm)
if err != nil {
return nil, err
}
iFaceVals[i] = utils.StringToInterface(strVal)
var ifaceVals []interface{}
if ifaceVals, err = getIfaceFromValues(attribute.Value, evNm); err != nil {
rply = nil
return
}
ifaceSum, err := utils.Divide(iFaceVals...)
if err != nil {
return nil, err
var ifaceSum interface{}
if ifaceSum, err = utils.Divide(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaValueExponent:
@@ -284,33 +273,38 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(attribute.Value), utils.MetaValueExponent)
}
strVal1, err := attribute.Value[0].ParseDataProvider(evNm) // String Value
if err != nil {
return nil, err
var strVal1 string
if strVal1, err = attribute.Value[0].ParseDataProvider(evNm); err != nil {
rply = nil
return
}
val, err := strconv.ParseFloat(strVal1, 64)
if err != nil {
var val float64
if val, err = strconv.ParseFloat(strVal1, 64); err != nil {
return nil, fmt.Errorf("invalid value <%s> to %s",
strVal1, utils.MetaValueExponent)
}
strVal2, err := attribute.Value[1].ParseDataProvider(evNm) // String Exponent
if err != nil {
return nil, err
var strVal2 string
if strVal2, err = attribute.Value[1].ParseDataProvider(evNm); err != nil {
rply = nil
return
}
exp, err := strconv.Atoi(strVal2)
if err != nil {
return nil, err
var exp int
if exp, err = strconv.Atoi(strVal2); err != nil {
rply = nil
return
}
substitute = strconv.FormatFloat(utils.Round(val*math.Pow10(exp),
config.CgrConfig().GeneralCfg().RoundingDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64)
alS.cgrcfg.GeneralCfg().RoundingDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64)
case utils.MetaUnixTimestamp:
val, err := attribute.Value.ParseDataProvider(evNm)
if err != nil {
return nil, err
var val string
if val, err = attribute.Value.ParseDataProvider(evNm); err != nil {
rply = nil
return
}
t, err := utils.ParseTimeDetectLayout(val, alS.cgrcfg.GeneralCfg().DefaultTimezone)
if err != nil {
return nil, err
var t time.Time
if t, err = utils.ParseTimeDetectLayout(val, alS.cgrcfg.GeneralCfg().DefaultTimezone); err != nil {
rply = nil
return
}
substitute = strconv.Itoa(int(t.Unix()))
default: // backwards compatible in case that Type is empty
@@ -318,7 +312,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
}
if err != nil {
return nil, err
rply = nil
return
}
//add only once the Path in AlteredFields
if !utils.IsSliceMember(rply.AlteredFields, attribute.Path) {
@@ -338,7 +333,10 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
}
if attribute.Type == utils.META_COMPOSED {
var val string
val, err = evNm.FieldAsString(strings.Split(attribute.Path, utils.NestingSep))
if val, err = evNm.FieldAsString(strings.Split(attribute.Path, utils.NestingSep)); err != nil {
rply = nil
return
}
substitute = val + substitute
}
evNm.Set(strings.Split(attribute.Path, utils.NestingSep), substitute)
@@ -352,7 +350,13 @@ func (alS *AttributeService) V1GetAttributeForEvent(args *AttrArgsProcessEvent,
if args.CGREvent == nil {
return utils.NewErrMandatoryIeMissing(utils.CGREventString)
}
attrPrf, err := alS.attributeProfileForEvent(args)
attrPrf, err := alS.attributeProfileForEvent(args, utils.MapStorage{
utils.MetaReq: args.CGREvent.Event,
utils.MetaOpts: args.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
if err != utils.ErrNotFound {
err = utils.NewErrServerError(err)
@@ -372,14 +376,25 @@ func (alS *AttributeService) V1ProcessEvent(args *AttrArgsProcessEvent,
if args.Event == nil {
return utils.NewErrMandatoryIeMissing(utils.Event)
}
if args.ProcessRuns == nil || *args.ProcessRuns == 0 {
args.ProcessRuns = utils.IntPointer(alS.cgrcfg.AttributeSCfg().ProcessRuns)
processRuns := alS.cgrcfg.AttributeSCfg().ProcessRuns
if args.ProcessRuns != nil && *args.ProcessRuns != 0 {
processRuns = *args.ProcessRuns
}
var apiRply *AttrSProcessEventReply // aggregate response here
args.CGREvent = args.CGREvent.Clone()
for i := 0; i < *args.ProcessRuns; i++ {
eNV := utils.MapStorage{
utils.MetaReq: args.CGREvent.Event,
utils.MetaOpts: args.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}
var lastID string
matchedIDs := make([]string, 0, processRuns)
alteredFields := make(utils.StringSet)
for i := 0; i < processRuns; i++ {
(eNV[utils.MetaVars].(utils.MapStorage))[utils.ProcessRuns] = utils.NewNMData(i)
var evRply *AttrSProcessEventReply
evRply, err = alS.processEvent(args)
evRply, err = alS.processEvent(args, eNV, lastID)
if err != nil {
if err != utils.ErrNotFound {
err = utils.NewErrServerError(err)
@@ -388,49 +403,33 @@ func (alS *AttributeService) V1ProcessEvent(args *AttrArgsProcessEvent,
}
break
}
if apiRply == nil { // first reply
apiRply = evRply
if apiRply.blocker {
break
}
continue
}
if utils.IsSliceMember(apiRply.MatchedProfiles,
evRply.MatchedProfiles[0]) { // don't process the same AttributeProfile twice
break
}
apiRply.MatchedProfiles = append(apiRply.MatchedProfiles, evRply.MatchedProfiles[0])
apiRply.CGREvent = evRply.CGREvent
apiRply.Opts = evRply.Opts
args.CGREvent.Tenant = evRply.CGREvent.Tenant
lastID = evRply.MatchedProfiles[0]
matchedIDs = append(matchedIDs, lastID)
for _, fldName := range evRply.AlteredFields {
if !utils.IsSliceMember(apiRply.AlteredFields, fldName) {
apiRply.AlteredFields = append(apiRply.AlteredFields, fldName) // only add processed fieldName once
}
alteredFields.Add(fldName)
}
if evRply.blocker {
break
}
}
// Make sure the requested fields were populated
if err == utils.ErrNotFound {
for val, valIface := range args.CGREvent.Event {
if valIface == interface{}(utils.MetaAttributes) {
err = utils.NewErrMandatoryIeMissing(val)
break
}
}
} else if err == nil {
for val, valIface := range apiRply.CGREvent.Event {
if valIface == interface{}(utils.MetaAttributes) {
// mandatory IE missing
err = utils.NewErrMandatoryIeMissing(val)
break
}
}
}
if err != nil {
return
}
*reply = *apiRply
// Make sure the requested fields were populated
for field, val := range args.CGREvent.Event {
if val == utils.MetaAttributes {
// mandatory IE missing
err = utils.NewErrMandatoryIeMissing(field)
return
}
}
*reply = AttrSProcessEventReply{
MatchedProfiles: matchedIDs,
AlteredFields: alteredFields.AsSlice(),
CGREvent: args.CGREvent,
Opts: args.Opts,
}
return
}

View File

@@ -154,3 +154,15 @@ func NewAttributeFromInline(tenant, inlnRule string) (attr *AttributeProfile, er
}
return
}
func getIfaceFromValues(values config.RSRParsers, evNm utils.DataProvider) (iFaceVals []interface{}, err error) {
iFaceVals = make([]interface{}, len(values))
for i, val := range values {
var strVal string
if strVal, err = val.ParseDataProvider(evNm); err != nil {
return
}
iFaceVals[i] = utils.StringToInterface(strVal)
}
return
}

View File

@@ -239,14 +239,26 @@ func TestAttributeCache(t *testing.T) {
}
func TestAttributeProfileForEvent(t *testing.T) {
atrp, err := attrService.attributeProfileForEvent(attrEvs[0])
atrp, err := attrService.attributeProfileForEvent(attrEvs[0], utils.MapStorage{
utils.MetaReq: attrEvs[0].CGREvent.Event,
utils.MetaOpts: attrEvs[0].Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
if !reflect.DeepEqual(atrPs[0], atrp) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(atrPs[0]), utils.ToJSON(atrp))
}
atrp, err = attrService.attributeProfileForEvent(attrEvs[1])
atrp, err = attrService.attributeProfileForEvent(attrEvs[1], utils.MapStorage{
utils.MetaReq: attrEvs[1].CGREvent.Event,
utils.MetaOpts: attrEvs[1].Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -254,7 +266,13 @@ func TestAttributeProfileForEvent(t *testing.T) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(atrPs[1]), utils.ToJSON(atrp))
}
atrp, err = attrService.attributeProfileForEvent(attrEvs[2])
atrp, err = attrService.attributeProfileForEvent(attrEvs[2], utils.MapStorage{
utils.MetaReq: attrEvs[2].CGREvent.Event,
utils.MetaOpts: attrEvs[2].Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -270,7 +288,13 @@ func TestAttributeProcessEvent(t *testing.T) {
AlteredFields: []string{utils.MetaReq + utils.NestingSep + "Account"},
CGREvent: attrEvs[0].CGREvent,
}
atrp, err := attrService.processEvent(attrEvs[0])
atrp, err := attrService.processEvent(attrEvs[0], utils.MapStorage{
utils.MetaReq: attrEvs[0].CGREvent.Event,
utils.MetaOpts: attrEvs[0].Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -281,7 +305,13 @@ func TestAttributeProcessEvent(t *testing.T) {
func TestAttributeProcessEventWithNotFound(t *testing.T) {
attrEvs[3].CGREvent.Event["Account"] = "1010" //Field added in event after process
if _, err := attrService.processEvent(attrEvs[3]); err == nil || err != utils.ErrNotFound {
if _, err := attrService.processEvent(attrEvs[3], utils.MapStorage{
utils.MetaReq: attrEvs[3].CGREvent.Event,
utils.MetaOpts: attrEvs[3].Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString); err == nil || err != utils.ErrNotFound {
t.Errorf("Error: %+v", err)
}
}
@@ -294,7 +324,13 @@ func TestAttributeProcessEventWithIDs(t *testing.T) {
AlteredFields: []string{utils.MetaReq + utils.NestingSep + "Account"},
CGREvent: attrEvs[3].CGREvent,
}
if atrp, err := attrService.processEvent(attrEvs[3]); err != nil {
if atrp, err := attrService.processEvent(attrEvs[3], utils.MapStorage{
utils.MetaReq: attrEvs[3].CGREvent.Event,
utils.MetaOpts: attrEvs[3].Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString); err != nil {
} else if !reflect.DeepEqual(eRply, atrp) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(atrp))
}
@@ -528,7 +564,7 @@ func TestAttributeProcessWithMultipleRuns1(t *testing.T) {
},
}
eRply := &AttrSProcessEventReply{
MatchedProfiles: []string{"ATTR_1", "ATTR_2", "ATTR_3"},
MatchedProfiles: []string{"ATTR_1", "ATTR_2", "ATTR_3", "ATTR_2"},
AlteredFields: []string{
utils.MetaReq + utils.NestingSep + "Field1",
utils.MetaReq + utils.NestingSep + "Field2",
@@ -668,6 +704,8 @@ func TestAttributeProcessWithMultipleRuns2(t *testing.T) {
}
}
/*
func TestAttributeProcessWithMultipleRuns3(t *testing.T) {
//refresh the DM
if err := dmAtr.DataDB().Flush(""); err != nil {
@@ -1882,7 +1920,13 @@ func TestProcessAttributeConstant(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -1934,7 +1978,13 @@ func TestProcessAttributeVariable(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -1993,7 +2043,13 @@ func TestProcessAttributeComposed(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2047,7 +2103,13 @@ func TestProcessAttributeUsageDifference(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2101,7 +2163,13 @@ func TestProcessAttributeSum(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2155,7 +2223,13 @@ func TestProcessAttributeDiff(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2209,7 +2283,13 @@ func TestProcessAttributeMultiply(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2263,7 +2343,13 @@ func TestProcessAttributeDivide(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2317,7 +2403,13 @@ func TestProcessAttributeValueExponent(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2371,7 +2463,13 @@ func TestProcessAttributeUnixTimeStamp(t *testing.T) {
},
},
}
rcv, err := attrService.processEvent(ev)
rcv, err := attrService.processEvent(ev, utils.MapStorage{
utils.MetaReq: ev.CGREvent.Event,
utils.MetaOpts: ev.Opts,
utils.MetaVars: utils.MapStorage{
utils.ProcessRuns: utils.NewNMData(0),
},
}, utils.EmptyString)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2449,3 +2547,4 @@ func TestAttributeIndexSelectsFalse(t *testing.T) {
}
}
*/

View File

@@ -775,6 +775,7 @@ const (
APIKey = "ApiKey"
RouteID = "RouteID"
MetaMonthlyEstimated = "*monthly_estimated"
ProcessRuns = "ProcessRuns"
)
// Migrator Action