diff --git a/agents/agentreq.go b/agents/agentreq.go index 717c875f0..7ffad2cfd 100644 --- a/agents/agentreq.go +++ b/agents/agentreq.go @@ -229,18 +229,15 @@ func (aReq *AgentRequest) ParseField( } return usedCCTime + time.Duration(debitItvl.Nanoseconds()*mltpl), nil case utils.MetaSum: - if len(cfgFld.Value) != 2 { - return nil, fmt.Errorf("invalid arguments <%s>", utils.ToJSON(cfgFld.Value)) + iFaceVals := make([]interface{}, len(cfgFld.Value)) + for i, val := range cfgFld.Value { + strVal, err := val.ParseDataProvider(aReq, utils.NestingSep) + if err != nil { + return "", err + } + iFaceVals[i] = utils.StringToInterface(strVal) } - strVal1, err := cfgFld.Value[0].ParseDataProvider(aReq, utils.NestingSep) - if err != nil { - return "", err - } - strVal2, err := cfgFld.Value[1].ParseDataProvider(aReq, utils.NestingSep) - if err != nil { - return "", err - } - out, err = utils.Sum(utils.StringToInterface(strVal1), utils.StringToInterface(strVal2)) + out, err = utils.MultipleSum(iFaceVals) } if err != nil { return diff --git a/utils/reflect.go b/utils/reflect.go index 32747c646..3e6c4c556 100644 --- a/utils/reflect.go +++ b/utils/reflect.go @@ -363,3 +363,70 @@ func Sum(item, oItem interface{}) (sum interface{}, err error) { } return } + +// MultipleSum attempts to sum multiple items +// returns the result or error if not comparable +func MultipleSum(items ...interface{}) (sum interface{}, err error) { + //we need at least 2 items to sum them + if len(items) < 2 { + return nil, errors.New("Not enought parameters") + } + + // convert the type for first item + valItm := reflect.ValueOf(items[0]) + switch valItm.Kind() { + case reflect.Float32: + items[0] = valItm.Float() + valItm = reflect.ValueOf(items[0]) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: + items[0] = valItm.Int() + valItm = reflect.ValueOf(items[0]) + } + typItem := reflect.TypeOf(items[0]) + + //populate sum with first item so we can add after + switch items[0].(type) { + case float64: + sum = valItm.Float() + case int64: + sum = valItm.Int() + case time.Duration: + tVal := items[0].(time.Duration) + sum = tVal + } + + for _, item := range items[1:] { + valOtItm := reflect.ValueOf(item) + // convert to wider type so we can be compatible with StringToInterface function + switch valOtItm.Kind() { + case reflect.Float32: + item = valOtItm.Float() + valOtItm = reflect.ValueOf(item) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: + item = valOtItm.Int() + valOtItm = reflect.ValueOf(item) + } + typOItem := reflect.TypeOf(item) + // check if the type for rest items is the same as first + if !typItem.Comparable() || + !typOItem.Comparable() || + typItem != typOItem { + return false, errors.New("incomparable") + } + + switch items[0].(type) { + case float64: + sum = reflect.ValueOf(sum).Float() + valOtItm.Float() + case int64: + sum = reflect.ValueOf(sum).Int() + valOtItm.Int() + case time.Duration: + tOVal := item.(time.Duration) + sum = sum.(time.Duration) + tOVal + default: // unsupported comparison + err = fmt.Errorf("unsupported comparison type: %v, kind: %v", typItem, typItem.Kind()) + break + } + } + return + +} diff --git a/utils/reflect_test.go b/utils/reflect_test.go index c66d64ba2..70a8fb8da 100644 --- a/utils/reflect_test.go +++ b/utils/reflect_test.go @@ -420,11 +420,11 @@ func TestIfaceAsBool(t *testing.T) { } func TestSum(t *testing.T) { - if _, err := GreaterThan(1, 1.2, false); err == nil || err.Error() != "incomparable" { + if _, err := Sum(1, 1.2); err == nil || err.Error() != "incomparable" { t.Error(err) } - if _, err := GreaterThan(struct{}{}, - map[string]interface{}{"a": "a"}, false); err == nil || err.Error() != "incomparable" { + if _, err := Sum(struct{}{}, + map[string]interface{}{"a": "a"}); err == nil || err.Error() != "incomparable" { t.Error(err) } if sum, err := Sum(1.2, 1.2); err != nil { @@ -455,3 +455,39 @@ func TestSum(t *testing.T) { t.Errorf("Expecting: 2s10ms, received: %+v", sum) } } + +func TestMultipleSum(t *testing.T) { + if _, err := MultipleSum(1); err == nil || err.Error() != "Not enought parameters" { + t.Error(err) + } + if _, err := MultipleSum(1, 1.2, false); err == nil || err.Error() != "incomparable" { + t.Error(err) + } + if sum, err := MultipleSum(1.2, 1.2, 1.2, 1.2); err != nil { + t.Error(err) + } else if sum != 4.8 { + t.Errorf("Expecting: 4.8, received: %+v", sum) + } + if sum, err := MultipleSum(2, 4, 6, 8); err != nil { + t.Error(err) + } else if sum != int64(20) { + t.Errorf("Expecting: 20, received: %+v", sum) + } + if sum, err := MultipleSum(0.5, 1.23, 1.456, 2.234, 11.2, 0.45); err != nil { + t.Error(err) + } else if sum != 17.069999999999997 { + t.Errorf("Expecting: 17.069999999999997, received: %+v", sum) + } + if sum, err := MultipleSum(2*time.Second, 1*time.Second, 2*time.Second, + 5*time.Second, 4*time.Millisecond); err != nil { + t.Error(err) + } else if sum != 10*time.Second+4*time.Millisecond { + t.Errorf("Expecting: 10.004s, received: %+v", sum) + } + if sum, err := MultipleSum(time.Duration(2*time.Second), + time.Duration(10*time.Millisecond)); err != nil { + t.Error(err) + } else if sum != time.Duration(2*time.Second+10*time.Millisecond) { + t.Errorf("Expecting: 2s10ms, received: %+v", sum) + } +}