integration test for *cgr_rpc

This commit is contained in:
Radu Ioan Fericean
2016-04-20 00:39:14 +03:00
parent c174605ab8
commit da1a9b344c
9 changed files with 82 additions and 14 deletions

View File

@@ -103,11 +103,12 @@ func (self *ApierV1) GetRatingPlan(rplnId string, reply *engine.RatingPlan) erro
}
func (self *ApierV1) ExecuteAction(attr *utils.AttrExecuteAction, reply *string) error {
accID := utils.AccountKey(attr.Tenant, attr.Account)
at := &engine.ActionTiming{
ActionsID: attr.ActionsId,
}
at.SetAccountIDs(utils.StringMap{accID: true})
if attr.Tenant != "" && attr.Account != "" {
at.SetAccountIDs(utils.StringMap{utils.AccountKey(attr.Tenant, attr.Account): true})
}
if err := at.Execute(); err != nil {
*reply = err.Error()
return err

View File

@@ -1297,7 +1297,7 @@ func TestApierResetDataAfterLoadFromFolder(t *testing.T) {
if rcvStats.Destinations != 5 ||
rcvStats.RatingPlans != 5 ||
rcvStats.RatingProfiles != 5 ||
rcvStats.Actions != 9 ||
rcvStats.Actions != 10 ||
rcvStats.DerivedChargers != 3 {
t.Errorf("Calling ApierV1.GetCacheStats received: %+v", rcvStats)
}

View File

@@ -9,3 +9,4 @@ TOPUP_DATA_r,*topup,,,,*monetary,*out,,DATA_DEST,,,*unlimited,,5000000,10,false,
TOPUP_DATA_r,*topup,,,,*data,*out,,DATA_DEST,datar,,*unlimited,,50000000000,10,false,false,10
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,""Param"":{""Account"":""rpc"",""Tenant"":""cgrates.org""}}",,,,,,,,,,,,,,,
1 #ActionsTag[0] Action[1] ActionExtraParameters[2] Filter[3] BalanceTag[4] BalanceType[5] Directions[6] Categories[7] DestinationIds[8] RatingSubject[9] SharedGroup[10] ExpiryTime[11] TimingTags[12] Units[13] BalanceWeight[14] BalanceBlocker[15] BalanceDisabled[16] Weight[17]
9 TOPUP_DATA_r *topup *data *out DATA_DEST datar *unlimited 50000000000 10 false false 10
10 TOPUP_VOICE *topup *voice *out GERMANY_MOBILE *unlimited 50000 10 false false 10
11 TOPUP_NEG *topup *voice *out GERMANY;!GERMANY_MOBILE *zero1m *unlimited 100 10 false false 10
12 RPC *cgr_rpc {"Address": "localhost:2013","Transport":"*gob","Method":"ApierV2.SetAccount","Attempts":1,"Async" :false,"Param":{"Account":"rpc","Tenant":"cgrates.org"}}

View File

@@ -657,7 +657,7 @@ type RPCRequest struct {
Method string
Attempts int
Async bool
Param string
Param map[string]interface{}
}
func cgrRPCAction(account *Account, sq *StatsQueueTriggered, a *Action, acs Actions) error {
@@ -677,13 +677,25 @@ func cgrRPCAction(account *Account, sq *StatsQueueTriggered, a *Action, acs Acti
} else {
client = params.Object
}
if client == nil {
return utils.ErrServerError
}
in, out := params.InParam, params.OutParam
x := in
if err := json.Unmarshal([]byte(req.Param), &x); err != nil {
p, err := utils.FromMapStringInterfaceValue(req.Param, in)
if err != nil {
return err
}
return client.Call(req.Method, in, out)
if !req.Async {
err = client.Call(req.Method, p, out)
utils.Logger.Info(fmt.Sprintf("<*cgr_rpc> result: %+v err: %v", out, err))
return err
}
go func() {
err := client.Call(req.Method, p, out)
utils.Logger.Info(fmt.Sprintf("<*cgr_rpc> result: %+v err: %v", out, err))
}()
return nil
}
// Structure to store actions according to weight

View File

@@ -2212,7 +2212,7 @@ func TestCgrRpcAction(t *testing.T) {
"Method": "TestRPCParameters.Hopa",
"Attempts":1,
"Async" :false,
"Param": "{\"Name\":\"n\", \"Surname\":\"s\", \"Age\":10.2}"}`,
"Param": {"Name":"n", "Surname":"s", "Age":10.2}}`,
}
if err := cgrRPCAction(nil, nil, a, nil); err != nil {
t.Error("error executing cgr action: ", err)

View File

@@ -214,7 +214,7 @@ func TestTpZeroNegativeCost(t *testing.T) {
} else if cc.GetDuration() != 20*time.Second {
t.Errorf("Calling Responder.MaxDebit got callcost: %v", utils.ToIJSON(cc))
}
var acnt *engine.Account
var acnt engine.Account
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1013"}
if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
@@ -222,3 +222,20 @@ func TestTpZeroNegativeCost(t *testing.T) {
t.Errorf("Calling ApierV2.GetAccount received: %s", utils.ToIJSON(acnt))
}
}
func TestTpExecuteActionCgrRpc(t *testing.T) {
if !*testIntegration {
return
}
var reply string
if err := tpRPC.Call("ApierV2.ExecuteAction", utils.AttrExecuteAction{ActionsId: "RPC"}, &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: "rpc"}
if err := tpRPC.Call("ApierV2.GetAccount", attrs, &acnt); err != nil {
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
}
}

View File

@@ -10,7 +10,7 @@ var rpcParamsMap map[string]*RpcParams
type RpcParams struct {
Object rpcclient.RpcClientConnection
InParam interface{}
InParam reflect.Value
OutParam interface{}
}
@@ -33,7 +33,7 @@ func RegisterRpcParams(name string, obj rpcclient.RpcClientConnection) {
if methodType.NumIn() == 3 { // if it has three parameters (one is self and two are rpc params)
rpcParamsMap[name+"."+method.Name] = &RpcParams{
Object: obj,
InParam: (reflect.New(methodType.In(1)).Elem()).Interface(),
InParam: reflect.New(methodType.In(1)),
OutParam: reflect.New(methodType.In(2).Elem()).Interface(),
}
}

View File

@@ -4,11 +4,17 @@ import "testing"
type RpcStruct struct{}
func (rpc *RpcStruct) Hopa(normal string, out *float64) error {
type Attr struct {
Name string
Surname string
Age float64
}
func (rpc *RpcStruct) Hopa(normal Attr, out *float64) error {
return nil
}
func (rpc *RpcStruct) Tropa(pointer *string, out *float64) error {
func (rpc *RpcStruct) Tropa(pointer *Attr, out *float64) error {
return nil
}
@@ -25,8 +31,18 @@ func TestRPCObjectPointer(t *testing.T) {
if !found {
t.Errorf("error getting rpcobject: %v (%+v)", rpcParamsMap, x)
}
x, found = rpcParamsMap["RpcStruct.Tropa"]
a := x.InParam
if v, err := FromMapStringInterfaceValue(map[string]interface{}{"Name": "a", "Surname": "b", "Age": 10.2}, a); err != nil || v.(Attr).Name != "a" || v.(Attr).Surname != "b" || v.(Attr).Age != 10.2 {
t.Errorf("error converting to struct: %+v (%v)", v, err)
}
//TODO: make pointer in arguments usable
/*x, found = rpcParamsMap["RpcStruct.Tropa"]
if !found {
t.Errorf("error getting rpcobject: %v (%+v)", rpcParamsMap, x)
}
b := x.InParam
log.Printf("T: %+v", b)
if v, err := FromMapStringInterfaceValue(map[string]interface{}{"Name": "a", "Surname": "b", "Age": 10.2}, b); err != nil || v.(Attr).Name != "a" || v.(Attr).Surname != "b" || v.(Attr).Age != 10.2 {
t.Errorf("error converting to struct: %+v (%v)", v, err)
}*/
}

View File

@@ -194,6 +194,27 @@ func FromMapStringInterface(m map[string]interface{}, in interface{}) error {
return nil
}
func FromMapStringInterfaceValue(m map[string]interface{}, v reflect.Value) (interface{}, error) {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
for fieldName, fieldValue := range m {
field := v.FieldByName(fieldName)
if field.IsValid() {
if !field.IsValid() || !field.CanSet() {
continue
}
structFieldType := field.Type()
val := reflect.ValueOf(fieldValue)
if structFieldType != val.Type() {
return nil, errors.New("Provided value type didn't match obj field type")
}
field.Set(val)
}
}
return v.Interface(), nil
}
// Update struct with map fields, returns not matching map keys, s is a struct to be updated
func UpdateStructWithStrMap(s interface{}, m map[string]string) []string {
notMatched := []string{}