mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Add support for *multiply and *divide in Agent and sync with AttributeS supported format fixes #1954
This commit is contained in:
committed by
Dan Christian Bogos
parent
43944fb7a7
commit
61a0aafd48
@@ -303,6 +303,26 @@ func (ar *AgentRequest) ParseField(
|
||||
iFaceVals[i] = utils.StringToInterface(strVal)
|
||||
}
|
||||
out, err = utils.Difference(iFaceVals...)
|
||||
case utils.MetaMultiply:
|
||||
iFaceVals := make([]interface{}, len(cfgFld.Value))
|
||||
for i, val := range cfgFld.Value {
|
||||
strVal, err := val.ParseDataProvider(ar, utils.NestingSep)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
iFaceVals[i] = utils.StringToInterface(strVal)
|
||||
}
|
||||
out, err = utils.Multiply(iFaceVals...)
|
||||
case utils.MetaDivide:
|
||||
iFaceVals := make([]interface{}, len(cfgFld.Value))
|
||||
for i, val := range cfgFld.Value {
|
||||
strVal, err := val.ParseDataProvider(ar, utils.NestingSep)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
iFaceVals[i] = utils.StringToInterface(strVal)
|
||||
}
|
||||
out, err = utils.Divide(iFaceVals...)
|
||||
case utils.MetaValueExponent:
|
||||
if len(cfgFld.Value) != 2 {
|
||||
return nil, fmt.Errorf("invalid arguments <%s> to %s",
|
||||
|
||||
@@ -1381,6 +1381,94 @@ func TestAgReqParseFieldMetaDifference(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgReqParseFieldMetaMultiply(t *testing.T) {
|
||||
//creater diameter message
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002"))
|
||||
m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type
|
||||
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data
|
||||
diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)),
|
||||
}})
|
||||
//create diameterDataProvider
|
||||
dP := newDADataProvider(nil, m)
|
||||
cfg, _ := config.NewDefaultCGRConfig()
|
||||
data := engine.NewInternalDB(nil, nil, true, cfg.DataDbCfg().Items)
|
||||
dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil)
|
||||
filterS := engine.NewFilterS(cfg, nil, dm)
|
||||
//pass the data provider to agent request
|
||||
agReq := NewAgentRequest(dP, nil, nil, nil, nil, "cgrates.org", "", filterS, nil, nil)
|
||||
|
||||
tplFlds := []*config.FCTemplate{
|
||||
&config.FCTemplate{Tag: "Multiply", Filters: []string{},
|
||||
Path: "Multiply", Type: utils.MetaMultiply,
|
||||
Value: config.NewRSRParsersMustCompile("15;~*req.Session-Id", true, utils.INFIELD_SEP),
|
||||
Mandatory: true},
|
||||
}
|
||||
if _, err := agReq.ParseField(tplFlds[0]); err == nil ||
|
||||
err.Error() != `strconv.ParseInt: parsing "simuhuawei;1449573472;00002": invalid syntax` {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
tplFlds = []*config.FCTemplate{
|
||||
&config.FCTemplate{Tag: "Multiply", Filters: []string{},
|
||||
Path: "Multiply", Type: utils.MetaMultiply,
|
||||
Value: config.NewRSRParsersMustCompile("15;15", true, utils.INFIELD_SEP),
|
||||
Mandatory: true},
|
||||
}
|
||||
expected := int64(225)
|
||||
if out, err := agReq.ParseField(tplFlds[0]); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(out, expected) {
|
||||
t.Errorf("expecting: <%+v>, %T received: <%+v> %T", expected, expected, out, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgReqParseFieldMetaDivide(t *testing.T) {
|
||||
//creater diameter message
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002"))
|
||||
m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(2)), // Subscription-Id-Type
|
||||
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000004")), // Subscription-Id-Data
|
||||
diam.NewAVP(avp.ValueDigits, avp.Mbit, 0, datatype.Integer64(20000)),
|
||||
}})
|
||||
//create diameterDataProvider
|
||||
dP := newDADataProvider(nil, m)
|
||||
cfg, _ := config.NewDefaultCGRConfig()
|
||||
data := engine.NewInternalDB(nil, nil, true, cfg.DataDbCfg().Items)
|
||||
dm := engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil)
|
||||
filterS := engine.NewFilterS(cfg, nil, dm)
|
||||
//pass the data provider to agent request
|
||||
agReq := NewAgentRequest(dP, nil, nil, nil, nil, "cgrates.org", "", filterS, nil, nil)
|
||||
|
||||
tplFlds := []*config.FCTemplate{
|
||||
&config.FCTemplate{Tag: "Divide", Filters: []string{},
|
||||
Path: "Divide", Type: utils.MetaDivide,
|
||||
Value: config.NewRSRParsersMustCompile("15;~*req.Session-Id", true, utils.INFIELD_SEP),
|
||||
Mandatory: true},
|
||||
}
|
||||
if _, err := agReq.ParseField(tplFlds[0]); err == nil ||
|
||||
err.Error() != `strconv.ParseInt: parsing "simuhuawei;1449573472;00002": invalid syntax` {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
tplFlds = []*config.FCTemplate{
|
||||
&config.FCTemplate{Tag: "Divide", Filters: []string{},
|
||||
Path: "Divide", Type: utils.MetaDivide,
|
||||
Value: config.NewRSRParsersMustCompile("15;3", true, utils.INFIELD_SEP),
|
||||
Mandatory: true},
|
||||
}
|
||||
expected := int64(5)
|
||||
if out, err := agReq.ParseField(tplFlds[0]); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(out, expected) {
|
||||
t.Errorf("expecting: <%+v>, %T received: <%+v> %T", expected, expected, out, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgReqParseFieldMetaValueExponent(t *testing.T) {
|
||||
//creater diameter message
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
|
||||
@@ -223,6 +223,48 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
|
||||
return nil, err
|
||||
}
|
||||
substitute = utils.IfaceAsString(ifaceSum)
|
||||
case utils.MetaDifference:
|
||||
iFaceVals := make([]interface{}, len(attribute.Value))
|
||||
for i, val := range attribute.Value {
|
||||
strVal, err := val.ParseDataProvider(evNm, utils.NestingSep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iFaceVals[i] = utils.StringToInterface(strVal)
|
||||
}
|
||||
ifaceSum, err := utils.Difference(iFaceVals...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
substitute = utils.IfaceAsString(ifaceSum)
|
||||
case utils.MetaMultiply:
|
||||
iFaceVals := make([]interface{}, len(attribute.Value))
|
||||
for i, val := range attribute.Value {
|
||||
strVal, err := val.ParseDataProvider(evNm, utils.NestingSep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iFaceVals[i] = utils.StringToInterface(strVal)
|
||||
}
|
||||
ifaceSum, err := utils.Multiply(iFaceVals...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
substitute = utils.IfaceAsString(ifaceSum)
|
||||
case utils.MetaDivide:
|
||||
iFaceVals := make([]interface{}, len(attribute.Value))
|
||||
for i, val := range attribute.Value {
|
||||
strVal, err := val.ParseDataProvider(evNm, utils.NestingSep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iFaceVals[i] = utils.StringToInterface(strVal)
|
||||
}
|
||||
ifaceSum, err := utils.Divide(iFaceVals...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
substitute = utils.IfaceAsString(ifaceSum)
|
||||
case utils.MetaValueExponent:
|
||||
if len(attribute.Value) != 2 {
|
||||
return nil, fmt.Errorf("invalid arguments <%s> to %s",
|
||||
@@ -247,6 +289,16 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
|
||||
}
|
||||
substitute = strconv.FormatFloat(utils.Round(val*math.Pow10(exp),
|
||||
config.CgrConfig().GeneralCfg().RoundingDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
case utils.MetaUnixTimestamp:
|
||||
val, err := attribute.Value.ParseDataProvider(evNm, utils.NestingSep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t, err := utils.ParseTimeDetectLayout(val, alS.cgrcfg.GeneralCfg().DefaultTimezone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
substitute = strconv.Itoa(int(t.Unix()))
|
||||
default: // backwards compatible in case that Type is empty
|
||||
substitute, err = attribute.Value.ParseDataProvider(evNm, utils.NestingSep)
|
||||
}
|
||||
|
||||
@@ -627,6 +627,98 @@ func Difference(items ...interface{}) (diff interface{}, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Multiply attempts to multiply multiple items
|
||||
// returns the result or error if not comparable
|
||||
func Multiply(items ...interface{}) (mlt interface{}, err error) {
|
||||
//we need at least 2 items to diff them
|
||||
if len(items) < 2 {
|
||||
return nil, ErrNotEnoughParameters
|
||||
}
|
||||
switch dt := items[0].(type) {
|
||||
case float64:
|
||||
mlt = dt
|
||||
for _, item := range items[1:] {
|
||||
if itmVal, err := IfaceAsFloat64(item); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = mlt.(float64) * itmVal
|
||||
}
|
||||
}
|
||||
case int64:
|
||||
mlt = dt
|
||||
for _, item := range items[1:] {
|
||||
if itmVal, err := IfaceAsInt64(item); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = mlt.(int64) * itmVal
|
||||
}
|
||||
}
|
||||
case int:
|
||||
// need explicit conversion for int
|
||||
if firstItmVal, err := IfaceAsInt64(dt); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = firstItmVal
|
||||
}
|
||||
for _, item := range items[1:] {
|
||||
if itmVal, err := IfaceAsInt64(item); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = mlt.(int64) * itmVal
|
||||
}
|
||||
}
|
||||
default: // unsupported comparison
|
||||
return nil, fmt.Errorf("unsupported type")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Divide attempts to divide multiple items
|
||||
// returns the result or error if not comparable
|
||||
func Divide(items ...interface{}) (mlt interface{}, err error) {
|
||||
//we need at least 2 items to diff them
|
||||
if len(items) < 2 {
|
||||
return nil, ErrNotEnoughParameters
|
||||
}
|
||||
switch dt := items[0].(type) {
|
||||
case float64:
|
||||
mlt = dt
|
||||
for _, item := range items[1:] {
|
||||
if itmVal, err := IfaceAsFloat64(item); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = mlt.(float64) / itmVal
|
||||
}
|
||||
}
|
||||
case int64:
|
||||
mlt = dt
|
||||
for _, item := range items[1:] {
|
||||
if itmVal, err := IfaceAsInt64(item); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = mlt.(int64) / itmVal
|
||||
}
|
||||
}
|
||||
case int:
|
||||
// need explicit conversion for int
|
||||
if firstItmVal, err := IfaceAsInt64(dt); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = firstItmVal
|
||||
}
|
||||
for _, item := range items[1:] {
|
||||
if itmVal, err := IfaceAsInt64(item); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
mlt = mlt.(int64) / itmVal
|
||||
}
|
||||
}
|
||||
default: // unsupported comparison
|
||||
return nil, fmt.Errorf("unsupported type")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ReflectFieldMethodInterface parses intf attepting to return the field value or error otherwise
|
||||
// Supports "ExtraFields" where additional fields are dynamically inserted in map with field name: extraFieldsLabel
|
||||
func ReflectFieldMethodInterface(obj interface{}, fldName string) (retIf interface{}, err error) {
|
||||
|
||||
@@ -641,6 +641,56 @@ func TestDifference(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestMultiply(t *testing.T) {
|
||||
if _, err := Multiply(10); err == nil || err != ErrNotEnoughParameters {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := Multiply(10, 1.2, false); err == nil || err.Error() != "cannot convert field: 1.2 to int" {
|
||||
t.Error(err)
|
||||
}
|
||||
if diff, err := Multiply(12, 1, 2, 3); err != nil {
|
||||
t.Error(err)
|
||||
} else if diff != int64(72) {
|
||||
t.Errorf("Expecting: 72, received: %+v", diff)
|
||||
}
|
||||
if diff, err := Multiply(8.0, 4.0, 2.0, 1.0); err != nil {
|
||||
t.Error(err)
|
||||
} else if diff != 64.0 {
|
||||
t.Errorf("Expecting: 64.0, received: %+v", diff)
|
||||
}
|
||||
|
||||
if diff, err := Multiply(8.0, 4, 6.0, 1.0); err != nil {
|
||||
t.Error(err)
|
||||
} else if diff != 192.0 {
|
||||
t.Errorf("Expecting: 192.0, received: %+v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDivide(t *testing.T) {
|
||||
if _, err := Divide(10); err == nil || err != ErrNotEnoughParameters {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := Divide(10, 1.2, false); err == nil || err.Error() != "cannot convert field: 1.2 to int" {
|
||||
t.Error(err)
|
||||
}
|
||||
if diff, err := Divide(12, 1, 2, 3); err != nil {
|
||||
t.Error(err)
|
||||
} else if diff != int64(2) {
|
||||
t.Errorf("Expecting: 2, received: %+v", diff)
|
||||
}
|
||||
if diff, err := Divide(8.0, 4.0, 2.0, 1.0); err != nil {
|
||||
t.Error(err)
|
||||
} else if diff != 1.0 {
|
||||
t.Errorf("Expecting: 1.0, received: %+v", diff)
|
||||
}
|
||||
|
||||
if diff, err := Divide(8.0, 4, 6.0, 1.0); err != nil {
|
||||
t.Error(err)
|
||||
} else if diff != 0.3333333333333333 {
|
||||
t.Errorf("Expecting: 0.3333333333333333, received: %+v", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqualTo(t *testing.T) {
|
||||
if gte, err := EqualTo(1, 1.2); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
Reference in New Issue
Block a user