conditional topup tests and improvements

fixes #275
This commit is contained in:
Radu Ioan Fericean
2016-01-19 21:24:13 +02:00
parent 178c291d6a
commit 4e784b6ef5
4 changed files with 240 additions and 6 deletions

View File

@@ -699,7 +699,9 @@ func (acc *Account) DebitConnectionFee(cc *CallCost, usefulMoneyBalances Balance
func (acc *Account) matchConditions(condition string) (bool, error) {
cl := &utils.CondLoader{}
cl.Parse(condition)
if err := cl.Parse(condition); err != nil {
return false, err
}
for balanceType, balanceChain := range acc.BalanceMap {
for _, b := range balanceChain {
check, err := cl.Check(&struct {

View File

@@ -1568,6 +1568,197 @@ func TestActionTransferMonetaryDefaultFilter(t *testing.T) {
}
}
func TestActionConditionalTopup(t *testing.T) {
err := accountingStorage.SetAccount(
&Account{
Id: "cgrates.org:cond",
BalanceMap: map[string]BalanceChain{
utils.MONETARY: BalanceChain{
&Balance{
Uuid: utils.GenUUID(),
Id: utils.META_DEFAULT,
Value: 10,
Weight: 20,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 3,
Weight: 20,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 1,
Weight: 10,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 6,
Weight: 20,
},
},
},
})
if err != nil {
t.Errorf("error setting account: %v", err)
}
a := &Action{
ActionType: CONDITIONAL_TOPUP,
BalanceType: utils.MONETARY,
ExtraParameters: `{"Type":"*monetary","Value":1,"Weight":10}`,
Balance: &Balance{
Value: 11,
Weight: 30,
},
}
at := &ActionTiming{
accountIDs: map[string]struct{}{"cgrates.org:cond": struct{}{}},
actions: Actions{a},
}
at.Execute()
afterUb, err := accountingStorage.GetAccount("cgrates.org:cond")
if err != nil {
t.Error("account not found: ", err, afterUb)
}
if len(afterUb.BalanceMap[utils.MONETARY]) != 5 ||
afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 31 ||
afterUb.BalanceMap[utils.MONETARY][4].Value != 11 {
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
t.Logf("B: %+v", b)
}
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
}
}
func TestActionConditionalTopupNoMatch(t *testing.T) {
err := accountingStorage.SetAccount(
&Account{
Id: "cgrates.org:cond",
BalanceMap: map[string]BalanceChain{
utils.MONETARY: BalanceChain{
&Balance{
Uuid: utils.GenUUID(),
Id: utils.META_DEFAULT,
Value: 10,
Weight: 20,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 3,
Weight: 20,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 1,
Weight: 10,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 6,
Weight: 20,
},
},
},
})
if err != nil {
t.Errorf("error setting account: %v", err)
}
a := &Action{
ActionType: CONDITIONAL_TOPUP,
BalanceType: utils.MONETARY,
ExtraParameters: `{"Type":"*monetary","Value":2,"Weight":10}`,
Balance: &Balance{
Value: 11,
Weight: 30,
},
}
at := &ActionTiming{
accountIDs: map[string]struct{}{"cgrates.org:cond": struct{}{}},
actions: Actions{a},
}
at.Execute()
afterUb, err := accountingStorage.GetAccount("cgrates.org:cond")
if err != nil {
t.Error("account not found: ", err, afterUb)
}
if len(afterUb.BalanceMap[utils.MONETARY]) != 4 ||
afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 20 {
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
t.Logf("B: %+v", b)
}
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
}
}
func TestActionConditionalTopupExistingBalance(t *testing.T) {
err := accountingStorage.SetAccount(
&Account{
Id: "cgrates.org:cond",
BalanceMap: map[string]BalanceChain{
utils.MONETARY: BalanceChain{
&Balance{
Uuid: utils.GenUUID(),
Value: 1,
Weight: 10,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 6,
Weight: 20,
},
},
utils.VOICE: BalanceChain{
&Balance{
Uuid: utils.GenUUID(),
Value: 10,
Weight: 10,
},
&Balance{
Uuid: utils.GenUUID(),
Value: 100,
Weight: 20,
},
},
},
})
if err != nil {
t.Errorf("error setting account: %v", err)
}
a := &Action{
ActionType: CONDITIONAL_TOPUP,
BalanceType: utils.MONETARY,
ExtraParameters: `{"Type":"*voice","Value":{"*gte":100}}`,
Balance: &Balance{
Value: 11,
Weight: 10,
},
}
at := &ActionTiming{
accountIDs: map[string]struct{}{"cgrates.org:cond": struct{}{}},
actions: Actions{a},
}
at.Execute()
afterUb, err := accountingStorage.GetAccount("cgrates.org:cond")
if err != nil {
t.Error("account not found: ", err, afterUb)
}
if len(afterUb.BalanceMap[utils.MONETARY]) != 2 ||
afterUb.BalanceMap[utils.MONETARY].GetTotalValue() != 18 {
for _, b := range afterUb.BalanceMap[utils.MONETARY] {
t.Logf("B: %+v", b)
}
t.Error("ransfer balance value: ", afterUb.BalanceMap[utils.MONETARY].GetTotalValue())
}
}
/**************** Benchmarks ********************************/
func BenchmarkUUID(b *testing.B) {

View File

@@ -148,6 +148,13 @@ func (kv *keyValue) checkStruct(o interface{}) (bool, error) {
return value.Interface() == kv.value, nil
}
type trueElement struct{}
func (te *trueElement) addChild(condElement) error { return ErrNotImplemented }
func (te *trueElement) checkStruct(o interface{}) (bool, error) {
return true, nil
}
func isOperator(s string) bool {
return strings.HasPrefix(s, "*")
}
@@ -186,18 +193,27 @@ func (cp *CondLoader) load(a map[string]interface{}, parentElement condElement)
if parentElement != nil {
parentElement.addChild(currentElement)
} else {
return currentElement, nil
if len(a) > 1 {
parentElement = &operatorSlice{operator: CondAND}
parentElement.addChild(currentElement)
} else {
return currentElement, nil
}
}
}
return nil, nil
return parentElement, nil
}
func (cp *CondLoader) Parse(s string) (err error) {
a := make(map[string]interface{})
if err := json.Unmarshal([]byte([]byte(s)), &a); err != nil {
return err
if len(s) != 0 {
if err := json.Unmarshal([]byte([]byte(s)), &a); err != nil {
return err
}
cp.rootElement, err = cp.load(a, nil)
} else {
cp.rootElement = &trueElement{}
}
cp.rootElement, err = cp.load(a, nil)
return
}

View File

@@ -20,6 +20,10 @@ func TestCondLoader(t *testing.T) {
if err != nil {
t.Errorf("Error loading structure: %+v (%v)", ToIJSON(cl.rootElement), err)
}
err = cl.Parse(``)
if err != nil {
t.Errorf("Error loading structure: %+v (%v)", ToIJSON(cl.rootElement), err)
}
}
func TestCondKeyValue(t *testing.T) {
@@ -68,6 +72,27 @@ func TestCondKeyValue(t *testing.T) {
if check, err := cl.Check(o); check || err != nil {
t.Errorf("Error checking struct: %v %v (%v)", check, err, ToIJSON(cl.rootElement))
}
err = cl.Parse(`{"Field":6, "Other":false}`)
if err != nil {
t.Errorf("Error loading structure: %+v (%v)", ToIJSON(cl.rootElement), err)
}
if check, err := cl.Check(o); check || err != nil {
t.Errorf("Error checking struct: %v %v (%v)", check, err, ToIJSON(cl.rootElement))
}
err = cl.Parse(`{"Other":true, "Field":{"*gt":5}}`)
if err != nil {
t.Errorf("Error loading structure: %+v (%v)", ToIJSON(cl.rootElement), err)
}
if check, err := cl.Check(o); !check || err != nil {
t.Errorf("Error checking struct: %v %v (%v)", check, err, ToIJSON(cl.rootElement))
}
err = cl.Parse(``)
if err != nil {
t.Errorf("Error loading structure: %+v (%v)", ToIJSON(cl.rootElement), err)
}
if check, err := cl.Check(o); !check || err != nil {
t.Errorf("Error checking struct: %v %v (%v)", check, err, ToIJSON(cl.rootElement))
}
}
func TestCondKeyValuePointer(t *testing.T) {