diff --git a/apier/v1/apier.go b/apier/v1/apier.go
index cf3f86389..21d64d422 100644
--- a/apier/v1/apier.go
+++ b/apier/v1/apier.go
@@ -523,14 +523,14 @@ func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error
}
a := &engine.Action{
- Id: utils.GenUUID(),
+ Id: attrs.ActionsId,
ActionType: apiAct.Identifier,
Weight: apiAct.Weight,
ExpirationString: apiAct.ExpiryTime,
ExtraParameters: apiAct.ExtraParameters,
Filter: apiAct.Filter,
Balance: &engine.BalanceFilter{ // TODO: update this part
- Uuid: utils.StringPointer(utils.GenUUID()),
+ Uuid: utils.StringPointer(apiAct.BalanceUuid),
ID: utils.StringPointer(apiAct.BalanceId),
Type: utils.StringPointer(apiAct.BalanceType),
Value: vf,
@@ -562,7 +562,8 @@ func (self *ApierV1) GetActions(actsId string, reply *[]*utils.TPAction) error {
return utils.NewErrServerError(err)
}
for _, engAct := range engActs {
- act := &utils.TPAction{Identifier: engAct.ActionType,
+ act := &utils.TPAction{
+ Identifier: engAct.ActionType,
ExpiryTime: engAct.ExpirationString,
ExtraParameters: engAct.ExtraParameters,
Filter: engAct.Filter,
@@ -1063,3 +1064,63 @@ func (self *ApierV1) GetLoadHistory(attrs utils.Paginator, reply *[]*engine.Load
*reply = loadHist[offset:nrItems]
return nil
}
+
+type AttrRemActions struct {
+ ActionIDs []string
+}
+
+func (self *ApierV1) RemActions(attr AttrRemActions, reply *string) error {
+ if attr.ActionIDs == nil {
+ err := utils.ErrNotFound
+ *reply = err.Error()
+ return err
+ }
+ stringMap := utils.NewStringMap(attr.ActionIDs...)
+ keys, err := self.RatingDb.GetKeysForPrefix(utils.ACTION_TRIGGER_PREFIX, true)
+ if err != nil {
+ *reply = err.Error()
+ return err
+ }
+ for _, key := range keys {
+ getAttrs, err := self.RatingDb.GetActionTriggers(key[len(utils.ACTION_TRIGGER_PREFIX):])
+ if err != nil {
+ *reply = err.Error()
+ return err
+ }
+ for _, atr := range getAttrs {
+ if _, found := stringMap[atr.ActionsID]; found {
+ // found action trigger referencing action; abort
+ err := fmt.Errorf("action %s refenced by action trigger %s", atr.ActionsID, atr.ID)
+ *reply = err.Error()
+ return err
+ }
+ }
+ }
+ allAplsMap, err := self.RatingDb.GetAllActionPlans()
+ if err != nil && err != utils.ErrNotFound {
+ *reply = err.Error()
+ return err
+ }
+ for _, apl := range allAplsMap {
+ for _, atm := range apl.ActionTimings {
+ if _, found := stringMap[atm.ActionsID]; found {
+ err := fmt.Errorf("action %s refenced by action plan %s", atm.ActionsID, apl.Id)
+ *reply = err.Error()
+ return err
+ }
+ }
+
+ }
+ for _, aID := range attr.ActionIDs {
+ if err := self.RatingDb.RemoveActions(aID); err != nil {
+ *reply = err.Error()
+ return err
+ }
+ }
+ if err := self.RatingDb.CacheRatingPrefixes(utils.ACTION_PREFIX); err != nil {
+ *reply = err.Error()
+ return err
+ }
+ *reply = utils.OK
+ return nil
+}
diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go
index 124b6a984..0e1e7f09e 100644
--- a/apier/v1/apier_local_test.go
+++ b/apier/v1/apier_local_test.go
@@ -1297,7 +1297,7 @@ func TestApierResetDataAfterLoadFromFolder(t *testing.T) {
if rcvStats.Destinations != 5 ||
rcvStats.RatingPlans != 5 ||
rcvStats.RatingProfiles != 5 ||
- rcvStats.Actions != 10 ||
+ rcvStats.Actions != 11 ||
rcvStats.DerivedChargers != 3 {
t.Errorf("Calling ApierV1.GetCacheStats received: %+v", rcvStats)
}
diff --git a/apier/v2/accounts.go b/apier/v2/accounts.go
index 08f6832dd..83d3d56f2 100644
--- a/apier/v2/accounts.go
+++ b/apier/v2/accounts.go
@@ -33,7 +33,7 @@ func (self *ApierV2) GetAccounts(attr utils.AttrGetAccounts, reply *[]*engine.Ac
var accountKeys []string
var err error
if len(attr.AccountIds) == 0 {
- if accountKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACCOUNT_PREFIX+utils.ConcatenatedKey(attr.Tenant), true); err != nil {
+ if accountKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACCOUNT_PREFIX+attr.Tenant, true); err != nil {
return err
}
} else {
diff --git a/apier/v2/apier.go b/apier/v2/apier.go
index 9f5f4cc2a..e337400b0 100644
--- a/apier/v2/apier.go
+++ b/apier/v2/apier.go
@@ -21,6 +21,7 @@ package v2
import (
"errors"
"fmt"
+ "math"
"os"
"path"
"strings"
@@ -263,3 +264,58 @@ func (self *ApierV2) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder,
*reply = *li
return nil
}
+
+type AttrGetActions struct {
+ ActionIDs []string
+ Offset int // Set the item offset
+ Limit int // Limit number of items retrieved
+}
+
+// Retrieves actions attached to specific ActionsId within cache
+func (self *ApierV2) GetActions(attr AttrGetActions, reply *map[string]engine.Actions) error {
+ var actionKeys []string
+ var err error
+ if len(attr.ActionIDs) == 0 {
+ if actionKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACTION_PREFIX, false); err != nil {
+ return err
+ }
+ } else {
+ for _, accID := range attr.ActionIDs {
+ if len(accID) == 0 { // Source of error returned from redis (key not found)
+ continue
+ }
+ actionKeys = append(actionKeys, utils.ACCOUNT_PREFIX+accID)
+ }
+ }
+ if len(actionKeys) == 0 {
+ return nil
+ }
+ if attr.Offset > len(actionKeys) {
+ attr.Offset = len(actionKeys)
+ }
+ if attr.Offset < 0 {
+ attr.Offset = 0
+ }
+ var limitedActions []string
+ if attr.Limit != 0 {
+ max := math.Min(float64(attr.Offset+attr.Limit), float64(len(actionKeys)))
+ limitedActions = actionKeys[attr.Offset:int(max)]
+ } else {
+ limitedActions = actionKeys[attr.Offset:]
+ }
+ retActions := make(map[string]engine.Actions)
+ for _, accKey := range limitedActions {
+ key := accKey[len(utils.ACTION_PREFIX):]
+ acts, err := self.RatingDb.GetActions(key, false)
+ if err != nil {
+ return utils.NewErrServerError(err)
+ }
+ if len(acts) > 0 {
+ retActions[key] = acts
+
+ }
+ }
+
+ *reply = retActions
+ return nil
+}
diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go
index c342e56ba..ddf5b3b14 100644
--- a/cmd/cgr-engine/cgr-engine.go
+++ b/cmd/cgr-engine/cgr-engine.go
@@ -22,7 +22,7 @@ import (
"flag"
"fmt"
"log"
- _ "net/http/pprof"
+ // _ "net/http/pprof"
"os"
"runtime"
"runtime/pprof"
diff --git a/console/actions.go b/console/actions.go
index 25e9af0e5..1d2504029 100644
--- a/console/actions.go
+++ b/console/actions.go
@@ -18,7 +18,10 @@ along with this program. If not, see
package console
-import "github.com/cgrates/cgrates/utils"
+import (
+ "github.com/cgrates/cgrates/apier/v2"
+ "github.com/cgrates/cgrates/engine"
+)
func init() {
c := &CmdGetActions{
@@ -33,7 +36,7 @@ func init() {
type CmdGetActions struct {
name string
rpcMethod string
- rpcParams *StringWrapper
+ rpcParams *v2.AttrGetActions
*CommandExecuter
}
@@ -47,7 +50,7 @@ func (self *CmdGetActions) RpcMethod() string {
func (self *CmdGetActions) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
- self.rpcParams = &StringWrapper{}
+ self.rpcParams = &v2.AttrGetActions{}
}
return self.rpcParams
}
@@ -57,6 +60,6 @@ func (self *CmdGetActions) PostprocessRpcParams() error {
}
func (self *CmdGetActions) RpcResult() interface{} {
- a := make([]*utils.TPAction, 0)
+ a := make(map[string]engine.Actions, 0)
return &a
}
diff --git a/console/actions_remove.go b/console/actions_remove.go
new file mode 100644
index 000000000..c7d5f54db
--- /dev/null
+++ b/console/actions_remove.go
@@ -0,0 +1,62 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2015 ITsysCOM GmbH
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package console
+
+import "github.com/cgrates/cgrates/apier/v1"
+
+func init() {
+ c := &CmdRemoveActions{
+ name: "actions_remove",
+ rpcMethod: "ApierV1.RemActions",
+ }
+ commands[c.Name()] = c
+ c.CommandExecuter = &CommandExecuter{c}
+}
+
+// Commander implementation
+type CmdRemoveActions struct {
+ name string
+ rpcMethod string
+ rpcParams *v1.AttrRemActions
+ *CommandExecuter
+}
+
+func (self *CmdRemoveActions) Name() string {
+ return self.name
+}
+
+func (self *CmdRemoveActions) RpcMethod() string {
+ return self.rpcMethod
+}
+
+func (self *CmdRemoveActions) RpcParams(reset bool) interface{} {
+ if reset || self.rpcParams == nil {
+ self.rpcParams = &v1.AttrRemActions{}
+ }
+ return self.rpcParams
+}
+
+func (self *CmdRemoveActions) PostprocessRpcParams() error {
+ return nil
+}
+
+func (self *CmdRemoveActions) RpcResult() interface{} {
+ var s string
+ return &s
+}
diff --git a/data/tariffplans/testtp/AccountActions.csv b/data/tariffplans/testtp/AccountActions.csv
index 850d03f77..9fa3f8977 100644
--- a/data/tariffplans/testtp/AccountActions.csv
+++ b/data/tariffplans/testtp/AccountActions.csv
@@ -9,4 +9,5 @@ cgrates.org,1010,TEST_DATA_r,,true,
cgrates.org,1011,TEST_VOICE,,,
cgrates.org,1012,PREPAID_10,,,
cgrates.org,1013,TEST_NEG,,,
-cgrates.org,1014,TEST_RPC,,,
\ No newline at end of file
+cgrates.org,1014,TEST_RPC,,,
+cgrates.org,1015,,,,
diff --git a/data/tariffplans/testtp/Actions.csv b/data/tariffplans/testtp/Actions.csv
index 680866202..20d61a27d 100644
--- a/data/tariffplans/testtp/Actions.csv
+++ b/data/tariffplans/testtp/Actions.csv
@@ -10,3 +10,5 @@ TOPUP_DATA_r,*topup,,,,*data,*out,,DATA_DEST,datar,,*unlimited,,50000000000,10,f
TOPUP_VOICE,*topup,,,,*voice,*out,,GERMANY_MOBILE,,,*unlimited,,50000,10,false,false,10
TOPUP_NEG,*topup,,,,*voice,*out,,GERMANY;!GERMANY_MOBILE,*zero1m,,*unlimited,,100,10,false,false,10
RPC,*cgr_rpc,"{""Address"": ""localhost:2013"",""Transport"":""*gob"",""Method"":""ApierV2.SetAccount"",""Attempts"":1,""Async"" :false,""Params"":{""Account"":""rpc"",""Tenant"":""cgrates.org""}}",,,,,,,,,,,,,,,
+DID,*debit,,,,*monetary,*out,,*any,,,*unlimited,*any,"{""Method"":""*incremental"",""Params"":{""Units"":1, ""Interval"":""month"",""Increment"":""day""}}",10.0,,,10.0
+DID,*cdrlog,"{""action"":""^DID"",""prev_balance"":""BalanceValue""}",,,*monetary,*out,,*any,,,*unlimited,,,10.0,,,10.0
diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go
index f2fb1f898..fbcf9e8f2 100644
--- a/engine/loader_csv_test.go
+++ b/engine/loader_csv_test.go
@@ -833,7 +833,7 @@ func TestLoadActions(t *testing.T) {
as1 := csvr.actions["MINI"]
expected := []*Action{
&Action{
- Id: "MINI0",
+ Id: "MINI",
ActionType: TOPUP_RESET,
ExpirationString: UNLIMITED,
ExtraParameters: "",
@@ -853,7 +853,7 @@ func TestLoadActions(t *testing.T) {
},
},
&Action{
- Id: "MINI1",
+ Id: "MINI",
ActionType: TOPUP,
ExpirationString: UNLIMITED,
ExtraParameters: "",
@@ -880,7 +880,7 @@ func TestLoadActions(t *testing.T) {
as2 := csvr.actions["SHARED"]
expected = []*Action{
&Action{
- Id: "SHARED0",
+ Id: "SHARED",
ActionType: TOPUP,
ExpirationString: UNLIMITED,
Weight: 10,
@@ -905,7 +905,7 @@ func TestLoadActions(t *testing.T) {
as3 := csvr.actions["DEFEE"]
expected = []*Action{
&Action{
- Id: "DEFEE0",
+ Id: "DEFEE",
ActionType: CDRLOG,
ExtraParameters: `{"Category":"^ddi","MediationRunId":"^did_run"}`,
Weight: 10,
diff --git a/engine/storage_interface.go b/engine/storage_interface.go
index 96a4b32c6..327be197f 100644
--- a/engine/storage_interface.go
+++ b/engine/storage_interface.go
@@ -59,6 +59,7 @@ type RatingStorage interface {
SetDerivedChargers(string, *utils.DerivedChargers) error
GetActions(string, bool) (Actions, error)
SetActions(string, Actions) error
+ RemoveActions(string) error
GetSharedGroup(string, bool) (*SharedGroup, error)
SetSharedGroup(*SharedGroup) error
GetActionTriggers(string) (ActionTriggers, error)
@@ -204,6 +205,7 @@ func NewCodecMsgpackMarshaler() *CodecMsgpackMarshaler {
cmm := &CodecMsgpackMarshaler{new(codec.MsgpackHandle)}
mh := cmm.mh
mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
+ mh.RawToString = true
return cmm
}
diff --git a/engine/storage_map.go b/engine/storage_map.go
index afab1a06d..f9a747a5b 100644
--- a/engine/storage_map.go
+++ b/engine/storage_map.go
@@ -469,6 +469,13 @@ func (ms *MapStorage) SetActions(key string, as Actions) (err error) {
return
}
+func (ms *MapStorage) RemoveActions(key string) (err error) {
+ ms.mu.Lock()
+ defer ms.mu.Unlock()
+ delete(ms.dict, utils.ACTION_PREFIX+key)
+ return
+}
+
func (ms *MapStorage) GetSharedGroup(key string, skipCache bool) (sg *SharedGroup, err error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go
index 0e2e59113..70fc91dc4 100644
--- a/engine/storage_mongo_datadb.go
+++ b/engine/storage_mongo_datadb.go
@@ -916,6 +916,10 @@ func (ms *MongoStorage) SetActions(key string, as Actions) error {
return err
}
+func (ms *MongoStorage) RemoveActions(key string) error {
+ return ms.db.C(colAct).Remove(bson.M{"key": key})
+}
+
func (ms *MongoStorage) GetSharedGroup(key string, skipCache bool) (sg *SharedGroup, err error) {
if !skipCache {
if x, err := cache2go.Get(utils.SHARED_GROUP_PREFIX + key); err == nil {
diff --git a/engine/storage_redis.go b/engine/storage_redis.go
index 896181922..be591ff48 100644
--- a/engine/storage_redis.go
+++ b/engine/storage_redis.go
@@ -590,6 +590,11 @@ func (rs *RedisStorage) SetActions(key string, as Actions) (err error) {
return
}
+func (rs *RedisStorage) RemoveActions(key string) (err error) {
+ err = rs.db.Cmd("DEL", utils.ACTION_PREFIX+key).Err
+ return
+}
+
func (rs *RedisStorage) GetSharedGroup(key string, skipCache bool) (sg *SharedGroup, err error) {
key = utils.SHARED_GROUP_PREFIX + key
if !skipCache {
diff --git a/engine/tp_reader.go b/engine/tp_reader.go
index a2a71470b..4eaf2e81f 100644
--- a/engine/tp_reader.go
+++ b/engine/tp_reader.go
@@ -514,7 +514,7 @@ func (tpr *TpReader) LoadActions() (err error) {
}
}
acts[idx] = &Action{
- Id: tag + strconv.Itoa(idx),
+ Id: tag,
ActionType: tpact.Identifier,
//BalanceType: tpact.BalanceType,
Weight: tpact.Weight,
@@ -990,7 +990,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error
}
}
acts[idx] = &Action{
- Id: tag + strconv.Itoa(idx),
+ Id: tag,
ActionType: tpact.Identifier,
//BalanceType: tpact.BalanceType,
Weight: tpact.Weight,
@@ -1338,7 +1338,7 @@ func (tpr *TpReader) LoadCdrStatsFiltered(tag string, save bool) (err error) {
}
}
acts[idx] = &Action{
- Id: tag + strconv.Itoa(idx),
+ Id: tag,
ActionType: tpact.Identifier,
//BalanceType: tpact.BalanceType,
Weight: tpact.Weight,
diff --git a/general_tests/tp_it_test.go b/general_tests/tp_it_test.go
index 8165ed19c..a917c9961 100644
--- a/general_tests/tp_it_test.go
+++ b/general_tests/tp_it_test.go
@@ -8,6 +8,7 @@ import (
"time"
"github.com/cgrates/cgrates/apier/v1"
+ "github.com/cgrates/cgrates/apier/v2"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
@@ -239,3 +240,128 @@ func TestTpExecuteActionCgrRpc(t *testing.T) {
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
}
}
+
+func TestTpCreateExecuteActionMatch(t *testing.T) {
+ if !*testIntegration {
+ return
+ }
+ var reply string
+ if err := tpRPC.Call("ApierV2.SetActions", utils.AttrSetActions{
+ ActionsId: "PAYMENT_2056bd2fe137082970f97102b64e42fd",
+ Actions: []*utils.TPAction{
+ &utils.TPAction{
+ BalanceType: "*monetary",
+ Directions: "*out",
+ Identifier: "*topup",
+ RatingSubject: "",
+ Units: "10.500000",
+ Weight: 10,
+ },
+ },
+ }, &reply); err != nil {
+ t.Error("Got error on ApierV2.SetActions: ", err.Error())
+ } else if reply != utils.OK {
+ t.Errorf("Calling ApierV2.SetActions got reply: %s", reply)
+ }
+ if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{
+ Tenant: "cgrates.org",
+ Account: "1015",
+ ActionsId: "PAYMENT_2056bd2fe137082970f97102b64e42fd",
+ }, &reply); err != nil {
+ t.Error("Got error on ApierV2.ExecuteAction: ", err.Error())
+ } else if reply != utils.OK {
+ t.Errorf("Calling ExecuteAction got reply: %s", reply)
+ }
+ if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{
+ Tenant: "cgrates.org",
+ Account: "1015",
+ ActionsId: "PAYMENT_2056bd2fe137082970f97102b64e42fd",
+ }, &reply); err != nil {
+ t.Error("Got error on ApierV2.ExecuteAction: ", err.Error())
+ } else if reply != utils.OK {
+ t.Errorf("Calling ExecuteAction got reply: %s", reply)
+ }
+ var acnt engine.Account
+ attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1015"}
+ if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error("Got error on ApierV2.GetAccount: ", err.Error())
+ }
+ if len(acnt.BalanceMap) != 1 ||
+ len(acnt.BalanceMap[utils.MONETARY]) != 1 ||
+ acnt.BalanceMap[utils.MONETARY].GetTotalValue() != 21 {
+ t.Error("error matching previous created balance: ", utils.ToIJSON(acnt.BalanceMap))
+ }
+}
+
+func TestTpSetRemActions(t *testing.T) {
+ if !*testIntegration {
+ return
+ }
+ var reply string
+ if err := tpRPC.Call("ApierV2.SetActions", utils.AttrSetActions{
+ ActionsId: "TO_BE_DELETED",
+ Actions: []*utils.TPAction{
+ &utils.TPAction{
+ BalanceType: "*monetary",
+ Directions: "*out",
+ Identifier: "*topup",
+ RatingSubject: "",
+ Units: "10.500000",
+ Weight: 10,
+ },
+ },
+ }, &reply); err != nil {
+ t.Error("Got error on ApierV2.SetActions: ", err.Error())
+ } else if reply != utils.OK {
+ t.Errorf("Calling ApierV2.SetActions got reply: %s", reply)
+ }
+ actionsMap := make(map[string]engine.Actions)
+ if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{
+ ActionIDs: []string{"PAYMENT_2056bd2fe137082970f97102b64e42fd"},
+ }, &actionsMap); err != nil {
+ t.Error("Got error on ApierV2.GetActions: ", err.Error())
+ } else if len(actionsMap) != 1 {
+ t.Errorf("Calling ApierV2.GetActions got reply: %s", utils.ToIJSON(actionsMap))
+ }
+ if err := tpRPC.Call("ApierV2.RemActions", v1.AttrRemActions{
+ ActionIDs: []string{"PAYMENT_2056bd2fe137082970f97102b64e42fd"},
+ }, &reply); err != nil {
+ t.Error("Got error on ApierV2.RemActions: ", err.Error())
+ } else if reply != utils.OK {
+ t.Errorf("Calling ApierV2.RemActions got reply: %s", reply)
+ }
+ if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{
+ ActionIDs: []string{"PAYMENT_2056bd2fe137082970f97102b64e42fd"},
+ }, &actionsMap); err == nil {
+ t.Error("no error on ApierV2.GetActions: ", err)
+ }
+}
+
+func TestTpRemActionsRefenced(t *testing.T) {
+ if !*testIntegration {
+ return
+ }
+ actionsMap := make(map[string]engine.Actions)
+ if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{
+ ActionIDs: []string{"TOPUP_VOICE"},
+ }, &actionsMap); err != nil {
+ t.Error("Got error on ApierV2.GetActions: ", err.Error())
+ } else if len(actionsMap) != 1 {
+ t.Errorf("Calling ApierV2.GetActions got reply: %s", utils.ToIJSON(actionsMap))
+ }
+ var reply string
+ if err := tpRPC.Call("ApierV2.RemActions", v1.AttrRemActions{
+ ActionIDs: []string{"TOPUP_VOICE"},
+ }, &reply); err == nil {
+ t.Error("No error on ApierV2.RemActions: ", err.Error())
+ } else if reply == utils.OK {
+ t.Errorf("Calling ApierV2.RemActions got reply: %s", reply)
+ }
+ if err := tpRPC.Call("ApierV2.GetActions", v2.AttrGetActions{
+ ActionIDs: []string{"TOPUP_VOICE"},
+ }, &actionsMap); err != nil {
+ t.Error("Got error on ApierV2.GetActions: ", err.Error())
+ } else if len(actionsMap) != 1 {
+ t.Errorf("Calling ApierV2.GetActions got reply: %s", utils.ToIJSON(actionsMap))
+ }
+}
diff --git a/sessionmanager/data_it_test.go b/sessionmanager/data_it_test.go
index dd21c6c8c..726e6d5d4 100644
--- a/sessionmanager/data_it_test.go
+++ b/sessionmanager/data_it_test.go
@@ -212,6 +212,12 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
+ aSessions := make([]*ActiveSession, 0)
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
smgEv = SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT",
utils.TOR: utils.DATA,
@@ -238,6 +244,11 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1068576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
smgEv = SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT",
utils.TOR: utils.DATA,
@@ -264,7 +275,11 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
-
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1088576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
smgEv = SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT",
utils.TOR: utils.DATA,
@@ -291,6 +306,11 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1108576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
smgEv = SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT",
utils.TOR: utils.DATA,
@@ -317,7 +337,11 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
-
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1128576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
smgEv = SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT",
utils.TOR: utils.DATA,
@@ -341,6 +365,11 @@ func TestSMGDataLastUsedMultipleData(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 0 {
+ t.Errorf("wrong active sessions: %+v", aSessions)
+ }
}
func TestSMGDataDerivedChargingNoCredit(t *testing.T) {
@@ -474,6 +503,12 @@ func TestSMGDataTTLExpiredMultiUpdates(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
+ aSessions := make([]*ActiveSession, 0)
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
smgEv = SMGenericEvent{
utils.EVENT_NAME: "TEST_EVENT",
@@ -509,4 +544,410 @@ func TestSMGDataTTLExpiredMultiUpdates(t *testing.T) {
} else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
}
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 0 {
+ t.Errorf("wrong active sessions: %+v", aSessions)
+ }
+}
+
+func TestSMGDataMultipleDataNoUsage(t *testing.T) {
+ if !*testIntegration {
+ return
+ }
+ var acnt *engine.Account
+ attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"}
+ eAcntVal := 49997767680.000000
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ smgEv := SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.SETUP_TIME: "2016-01-05 18:30:49",
+ utils.ANSWER_TIME: "2016-01-05 18:31:05",
+ utils.USAGE: "1048576",
+ }
+ var maxUsage float64
+ if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 1054720
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ aSessions := make([]*ActiveSession, 0)
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "0",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "0",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "0",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "0",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.LastUsed: "0",
+ }
+ var rpl string
+ if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK {
+ t.Error(err)
+ }
+ eAcntVal = 49997767680.000000 // refunded
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 0 {
+ t.Errorf("wrong active sessions: %+v", aSessions)
+ }
+}
+
+func TestSMGDataMultipleDataConstantUsage(t *testing.T) {
+ if !*testIntegration {
+ return
+ }
+ var acnt *engine.Account
+ attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1010"}
+ eAcntVal := 49997767680.000000
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ smgEv := SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.SETUP_TIME: "2016-01-05 18:30:49",
+ utils.ANSWER_TIME: "2016-01-05 18:31:05",
+ utils.USAGE: "1048576",
+ }
+ var maxUsage float64
+ if err := smgRPC.Call("SMGenericV1.SessionStart", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 1054720
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ aSessions := make([]*ActiveSession, 0)
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1048576 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "600",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049176 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "600",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1049776 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "600",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050376 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.USAGE: "1048576",
+ utils.LastUsed: "600",
+ }
+ if err := smgRPC.Call("SMGenericV1.SessionUpdate", smgEv, &maxUsage); err != nil {
+ t.Error(err)
+ }
+ if maxUsage != 1.048576e+06 {
+ t.Error("Bad max usage: ", maxUsage)
+ }
+ eAcntVal = 49996712960.000000 // 0
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 1 || aSessions[0].Usage.Seconds() != 1050976 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
+ smgEv = SMGenericEvent{
+ utils.EVENT_NAME: "TEST_EVENT",
+ utils.TOR: utils.DATA,
+ utils.ACCID: "12349",
+ utils.DIRECTION: utils.OUT,
+ utils.ACCOUNT: "1010",
+ utils.SUBJECT: "1010",
+ utils.DESTINATION: "222",
+ utils.CATEGORY: "data",
+ utils.TENANT: "cgrates.org",
+ utils.REQTYPE: utils.META_PREPAID,
+ utils.LastUsed: "0",
+ }
+ var rpl string
+ if err = smgRPC.Call("SMGenericV1.SessionEnd", smgEv, &rpl); err != nil || rpl != utils.OK {
+ t.Error(err)
+ }
+ eAcntVal = 49997757440.000000 // 10240 (from the start)
+ if err := smgRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
+ t.Error(err)
+ } else if acnt.BalanceMap[utils.DATA].GetTotalValue() != eAcntVal {
+ t.Errorf("Expected: %f, received: %f", eAcntVal, acnt.BalanceMap[utils.DATA].GetTotalValue())
+ }
+ if err := smgRPC.Call("SMGenericV1.ActiveSessions", utils.AttrSMGGetActiveSessions{}, &aSessions); err != nil {
+ t.Error(err)
+ } else if len(aSessions) != 0 {
+ t.Errorf("wrong active sessions: %f", aSessions[0].Usage.Seconds())
+ }
}
diff --git a/sessionmanager/smg_session.go b/sessionmanager/smg_session.go
index d1701a905..df622953b 100644
--- a/sessionmanager/smg_session.go
+++ b/sessionmanager/smg_session.go
@@ -90,13 +90,15 @@ func (self *SMGSession) debit(dur time.Duration, lastUsed *time.Duration) (time.
// total usage correction
self.totalUsage -= self.lastUsage
self.totalUsage += *lastUsed
- //utils.Logger.Debug(fmt.Sprintf("Correction: %f", self.totalUsage.Seconds()))
+ //utils.Logger.Debug(fmt.Sprintf("TotalUsage Correction: %f", self.totalUsage.Seconds()))
}
}
// apply correction from previous run
if self.extraDuration < dur {
dur -= self.extraDuration
} else {
+ self.lastUsage = requestedDuration
+ self.totalUsage += self.lastUsage
ccDuration := self.extraDuration // fake ccDuration
self.extraDuration -= dur
return ccDuration, nil
@@ -111,6 +113,7 @@ func (self *SMGSession) debit(dur time.Duration, lastUsed *time.Duration) (time.
self.cd.DurationIndex += dur
cc := &engine.CallCost{}
if err := self.rater.Call("Responder.MaxDebit", self.cd, cc); err != nil {
+ self.lastUsage = 0
self.lastDebit = 0
return 0, err
}
diff --git a/utils/apitpdata.go b/utils/apitpdata.go
index 62f38434b..12bfc9173 100644
--- a/utils/apitpdata.go
+++ b/utils/apitpdata.go
@@ -275,6 +275,7 @@ type TPActions struct {
type TPAction struct {
Identifier string // Identifier mapped in the code
BalanceId string // Balance identification string (account scope)
+ BalanceUuid string // Balance identification string (global scope)
BalanceType string // Type of balance the action will operate on
Directions string // Balance direction
Units string // Number of units to add/deduct
diff --git a/utils/value_formula.go b/utils/value_formula.go
index 1ac113aa1..1e6221087 100644
--- a/utils/value_formula.go
+++ b/utils/value_formula.go
@@ -37,6 +37,10 @@ var ValueFormulas = map[string]valueFormula{
INCREMENTAL: incrementalFormula,
}
+func (vf *ValueFormula) String() string {
+ return ToJSON(vf)
+}
+
func incrementalFormula(params map[string]interface{}) float64 {
// check parameters
unitsInterface, unitsFound := params["Units"]