From 965e476c7c626949454e81de4aa3ac125d5b1f5a Mon Sep 17 00:00:00 2001 From: TeoV Date: Sun, 10 Sep 2017 16:54:38 +0300 Subject: [PATCH 1/2] Add test for TPUser and disable stats from tutmysql tutmongo and tutpostgres --- apier/v1/tpusers.go | 28 ++- apier/v1/tpusers_it_test.go | 241 +++++++++++++++++++++ data/conf/samples/tutmongo/cgrates.json | 2 +- data/conf/samples/tutmysql/cgrates.json | 2 +- data/conf/samples/tutpostgres/cgrates.json | 6 +- engine/storage_mongo_stordb.go | 20 +- engine/storage_sql.go | 1 - engine/tp_reader.go | 2 +- 8 files changed, 278 insertions(+), 24 deletions(-) create mode 100644 apier/v1/tpusers_it_test.go diff --git a/apier/v1/tpusers.go b/apier/v1/tpusers.go index 8093878a8..5258ac76d 100644 --- a/apier/v1/tpusers.go +++ b/apier/v1/tpusers.go @@ -23,7 +23,7 @@ import ( // Creates a new alias within a tariff plan func (self *ApierV1) SetTPUser(attrs utils.TPUsers, reply *string) error { - if missing := utils.MissingStructFields(&attrs, []string{"TPid", "Direction", "Tenant", "Category", "Account", "Subject", "Group"}); len(missing) != 0 { + if missing := utils.MissingStructFields(&attrs, []string{"TPid", "UserName", "Tenant"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } if err := self.StorDb.SetTPUsers([]*utils.TPUsers{&attrs}); err != nil { @@ -34,21 +34,22 @@ func (self *ApierV1) SetTPUser(attrs utils.TPUsers, reply *string) error { } type AttrGetTPUser struct { - TPid string // Tariff plan id - UserId string + TPid string // Tariff plan id + Tenant string + UserName string } // Queries specific User on Tariff plan func (self *ApierV1) GetTPUser(attr AttrGetTPUser, reply *utils.TPUsers) error { - if missing := utils.MissingStructFields(&attr, []string{"TPid"}); len(missing) != 0 { //Params missing + if missing := utils.MissingStructFields(&attr, []string{"TPid", "UserName", "Tenant"}); len(missing) != 0 { //Params missing return utils.NewErrMandatoryIeMissing(missing...) } - filter := &utils.TPUsers{TPid: attr.TPid} - filter.SetId(attr.UserId) + filter := &utils.TPUsers{TPid: attr.TPid, UserName: attr.UserName, Tenant: attr.Tenant} if tms, err := self.StorDb.GetTPUsers(filter); err != nil { - return utils.NewErrServerError(err) - } else if len(tms) == 0 { - return utils.ErrNotFound + if err.Error() != utils.ErrNotFound.Error() { + err = utils.NewErrServerError(err) + } + return err } else { *reply = *tms[0] } @@ -77,11 +78,14 @@ func (self *ApierV1) GetTPUserIds(attrs AttrGetTPUserIds, reply *[]string) error // Removes specific User on Tariff plan func (self *ApierV1) RemTPUser(attrs AttrGetTPUser, reply *string) error { - if missing := utils.MissingStructFields(&attrs, []string{"TPid", "UserId"}); len(missing) != 0 { //Params missing + if missing := utils.MissingStructFields(&attrs, []string{"TPid", "Tenant", "UserName"}); len(missing) != 0 { //Params missing return utils.NewErrMandatoryIeMissing(missing...) } - if err := self.StorDb.RemTpData(utils.TBLTPUsers, attrs.TPid, map[string]string{"tag": attrs.UserId}); err != nil { - return utils.NewErrServerError(err) + if err := self.StorDb.RemTpData(utils.TBLTPUsers, attrs.TPid, map[string]string{"tenant": attrs.Tenant, "user_name": attrs.UserName}); err != nil { + if err.Error() != utils.ErrNotFound.Error() { + err = utils.NewErrServerError(err) + } + return err } else { *reply = utils.OK } diff --git a/apier/v1/tpusers_it_test.go b/apier/v1/tpusers_it_test.go new file mode 100644 index 000000000..9f1c978bb --- /dev/null +++ b/apier/v1/tpusers_it_test.go @@ -0,0 +1,241 @@ +// +build integration + +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) 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 v1 + +import ( + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" + "net/rpc" + "net/rpc/jsonrpc" + "path" + "reflect" + "testing" +) + +var ( + tpUserCfgPath string + tpUserCfg *config.CGRConfig + tpUserRPC *rpc.Client + tpUserDataDir = "/usr/share/cgrates" + tpUser *utils.TPUsers + tpUserDelay int + tpUserConfigDIR string //run tests for specific configuration +) + +var sTestsTPUsers = []func(t *testing.T){ + testTPUsersInitCfg, + testTPUsersResetStorDb, + testTPUsersStartEngine, + testTPUsersRpcConn, + testTPUsersGetTPUserBeforeSet, + testTPUsersSetTPUser, + testTPUsersGetTPUserAfterSet, + testTPUsersGetTPUserID, + testTPUsersUpdateTPUser, + testTPUsersGetTPUserAfterUpdate, + testTPUsersRemTPUser, + testTPUsersGetTPUserAfterRemove, + testTPUsersKillEngine, +} + +//Test start here +func TestTPUserITMySql(t *testing.T) { + tpUserConfigDIR = "tutmysql" + for _, stest := range sTestsTPUsers { + t.Run(tpUserConfigDIR, stest) + } +} + +func TestTPUserITMongo(t *testing.T) { + tpUserConfigDIR = "tutmongo" + for _, stest := range sTestsTPUsers { + t.Run(tpUserConfigDIR, stest) + } +} + +func TestTPUserITPG(t *testing.T) { + tpUserConfigDIR = "tutpostgres" + for _, stest := range sTestsTPUsers { + t.Run(tpUserConfigDIR, stest) + } +} + +func testTPUsersInitCfg(t *testing.T) { + var err error + tpUserCfgPath = path.Join(tpUserDataDir, "conf", "samples", tpUserConfigDIR) + tpUserCfg, err = config.NewCGRConfigFromFolder(tpUserCfgPath) + if err != nil { + t.Error(err) + } + tpUserCfg.DataFolderPath = tpUserDataDir // Share DataFolderPath through config towards StoreDb for Flush() + config.SetCgrConfig(tpUserCfg) + switch tpUserConfigDIR { + case "tutmongo": // Mongo needs more time to reset db + tpUserDelay = 4000 + default: + tpUserDelay = 2000 + } +} + +// Wipe out the cdr database +func testTPUsersResetStorDb(t *testing.T) { + if err := engine.InitStorDb(tpUserCfg); err != nil { + t.Fatal(err) + } +} + +// Start CGR Engine +func testTPUsersStartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(tpUserCfgPath, tpUserDelay); err != nil { + t.Fatal(err) + } +} + +// Connect rpc client to rater +func testTPUsersRpcConn(t *testing.T) { + var err error + tpUserRPC, err = jsonrpc.Dial("tcp", tpUserCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal(err) + } +} + +func testTPUsersGetTPUserBeforeSet(t *testing.T) { + var reply *utils.TPUsers + if err := tpUserRPC.Call("ApierV1.GetTPUser", AttrGetTPUser{TPid: "TPU1", Tenant: "Tentant1", UserName: "User1"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testTPUsersSetTPUser(t *testing.T) { + tpUser = &utils.TPUsers{ + TPid: "TPU1", + UserName: "User1", + Tenant: "Tenant1", + Masked: true, + Weight: 20, + Profile: []*utils.TPUserProfile{ + &utils.TPUserProfile{ + AttrName: "UserProfile1", + AttrValue: "ValUP1", + }, + &utils.TPUserProfile{ + AttrName: "UserProfile2", + AttrValue: "ValUP2", + }, + }, + } + var result string + if err := tpUserRPC.Call("ApierV1.SetTPUser", tpUser, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Error("Unexpected reply returned", result) + } +} + +func testTPUsersGetTPUserAfterSet(t *testing.T) { + var respond *utils.TPUsers + if err := tpUserRPC.Call("ApierV1.GetTPUser", &AttrGetTPUser{TPid: tpUser.TPid, UserName: tpUser.UserName, Tenant: tpUser.Tenant}, &respond); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(tpUser.TPid, respond.TPid) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.TPid, respond.TPid) + } else if !reflect.DeepEqual(tpUser.UserName, respond.UserName) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.UserName, respond.UserName) + } else if !reflect.DeepEqual(tpUser.Tenant, respond.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.Tenant, respond.Tenant) + } else if !reflect.DeepEqual(tpUser.Weight, respond.Weight) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.Weight, respond.Weight) + } else if !reflect.DeepEqual(len(tpUser.Profile), len(respond.Profile)) { + t.Errorf("Expecting: %+v, received: %+v", len(tpUser.Profile), len(respond.Profile)) + } +} + +func testTPUsersGetTPUserID(t *testing.T) { + var result []string + expectedTPID := []string{"Tenant1:User1"} + if err := tpUserRPC.Call("ApierV1.GetTPUserIds", AttrGetTPUserIds{tpUser.TPid, utils.Paginator{}}, &result); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(result, expectedTPID) { + t.Errorf("Expecting: %+v, received: %+v", result, expectedTPID) + } +} + +func testTPUsersUpdateTPUser(t *testing.T) { + var result string + tpUser.Profile = []*utils.TPUserProfile{ + &utils.TPUserProfile{ + AttrName: "UserProfile1", + AttrValue: "ValUp1", + }, + &utils.TPUserProfile{ + AttrName: "UserProfile2", + AttrValue: "ValUP2", + }, + &utils.TPUserProfile{ + AttrName: "UserProfile3", + AttrValue: "ValUP3", + }, + } + if err := tpUserRPC.Call("ApierV1.SetTPUser", tpUser, &result); err != nil { + t.Error(err) + } else if result != utils.OK { + t.Error("Unexpected reply returned", result) + } +} + +func testTPUsersGetTPUserAfterUpdate(t *testing.T) { + var respond *utils.TPUsers + if err := tpUserRPC.Call("ApierV1.GetTPUser", &AttrGetTPUser{TPid: tpUser.TPid, Tenant: tpUser.Tenant, UserName: tpUser.UserName}, &respond); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(tpUser.TPid, respond.TPid) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.TPid, respond.TPid) + } else if !reflect.DeepEqual(tpUser.UserName, respond.UserName) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.UserName, respond.UserName) + } else if !reflect.DeepEqual(tpUser.Tenant, respond.Tenant) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.Tenant, respond.Tenant) + } else if !reflect.DeepEqual(tpUser.Weight, respond.Weight) { + t.Errorf("Expecting: %+v, received: %+v", tpUser.Weight, respond.Weight) + } else if !reflect.DeepEqual(len(tpUser.Profile), len(respond.Profile)) { + t.Errorf("Expecting: %+v, received: %+v", len(tpUser.Profile), len(respond.Profile)) + } +} + +func testTPUsersRemTPUser(t *testing.T) { + var resp string + if err := tpUserRPC.Call("ApierV1.RemTPUser", &AttrGetTPUser{TPid: tpUser.TPid, Tenant: tpUser.Tenant, UserName: tpUser.UserName}, &resp); err != nil { + t.Error(err) + } else if resp != utils.OK { + t.Error("Unexpected reply returned", resp) + } +} + +func testTPUsersGetTPUserAfterRemove(t *testing.T) { + var respond *utils.TPUsers + if err := tpUserRPC.Call("ApierV1.GetTPUser", &AttrGetTPUser{TPid: "TPU1", UserName: "User1", Tenant: "Tenant1"}, &respond); err == nil || err.Error() != utils.ErrNotFound.Error() { + t.Error(err) + } +} + +func testTPUsersKillEngine(t *testing.T) { + if err := engine.KillEngine(tpUserDelay); err != nil { + t.Error(err) + } +} diff --git a/data/conf/samples/tutmongo/cgrates.json b/data/conf/samples/tutmongo/cgrates.json index 5bb324d5c..dd8d774d6 100644 --- a/data/conf/samples/tutmongo/cgrates.json +++ b/data/conf/samples/tutmongo/cgrates.json @@ -84,7 +84,7 @@ "stats": { - "enabled": true, + "enabled": false, "store_interval": "0s", }, diff --git a/data/conf/samples/tutmysql/cgrates.json b/data/conf/samples/tutmysql/cgrates.json index db6a53cb1..ce0358ea1 100644 --- a/data/conf/samples/tutmysql/cgrates.json +++ b/data/conf/samples/tutmysql/cgrates.json @@ -112,7 +112,7 @@ "stats": { - "enabled": true, + "enabled": false, "store_interval": "0s", }, diff --git a/data/conf/samples/tutpostgres/cgrates.json b/data/conf/samples/tutpostgres/cgrates.json index 77b78db03..6ebb5d62b 100644 --- a/data/conf/samples/tutpostgres/cgrates.json +++ b/data/conf/samples/tutpostgres/cgrates.json @@ -60,8 +60,8 @@ "users": { - "enabled": true, // starts User service: . - "indexes": ["Uuid"], // user profile field indexes + "enabled": true, + "indexes": ["Uuid"], }, @@ -80,4 +80,4 @@ }, -} \ No newline at end of file +} diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 9a0088a4f..d965e7916 100755 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -19,13 +19,12 @@ package engine import ( "fmt" - "regexp" - "strings" - "time" - "github.com/cgrates/cgrates/utils" "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" + "regexp" + "strings" + "time" ) func (ms *MongoStorage) GetTpIds() ([]string, error) { @@ -63,7 +62,11 @@ func (ms *MongoStorage) GetTpTableIds(tpid, table string, distinct utils.TPDisti for k, v := range filter { findMap[k] = v } - + for k, v := range distinct { //fix for MongoStorage on TPUsers + if v == "user_name" { + distinct[k] = "username" + } + } if pag != nil && pag.SearchTerm != "" { var searchItems []bson.M for _, d := range distinct { @@ -521,6 +524,13 @@ func (ms *MongoStorage) RemTpData(table, tpid string, args map[string]string) er if args == nil { args = make(map[string]string) } + for arg, val := range args { //fix for Mongo TPUsers tables + if arg == "user_name" { + delete(args, arg) + args["username"] = val + } + } + if _, has := args["tag"]; has { // API uses tag to be compatible with SQL models, fix it here args["id"] = args["tag"] delete(args, "tag") diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 2db238d8c..e7613b9a7 100755 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -199,7 +199,6 @@ func (self *SQLStorage) RemTpData(table, tpid string, args map[string]string) er tx.Commit() return nil } - utils.Logger.Debug(fmt.Sprintf("#Rem sterge %s", tpid)) // Remove from a single table tx = tx.Table(table).Where("tpid = ?", tpid) // Compose filters diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 6b08b1419..9dcf27cd4 100755 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -1945,7 +1945,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err } } if verbose { - log.Print("StatQueueProfile:") + log.Print("StatQueueProfiles:") } for _, tpST := range tpr.stats { st, err := APItoStats(tpST, tpr.timezone) From 468610af92406d8a19009a8808f5ccb0a5c65a9e Mon Sep 17 00:00:00 2001 From: TeoV Date: Sun, 10 Sep 2017 23:49:18 +0300 Subject: [PATCH 2/2] Set on tutmysql historys on false --- data/conf/samples/tutmysql/cgrates.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/conf/samples/tutmysql/cgrates.json b/data/conf/samples/tutmysql/cgrates.json index ce0358ea1..bb2983bd3 100644 --- a/data/conf/samples/tutmysql/cgrates.json +++ b/data/conf/samples/tutmysql/cgrates.json @@ -118,7 +118,7 @@ "historys": { - "enabled": true, + "enabled": false, },