mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-22 23:58:44 +05:00
Add TPStats and test for it
This commit is contained in:
85
apier/v1/tpstats.go
Normal file
85
apier/v1/tpstats.go
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func (self *ApierV1) SetTPStat(attr utils.TPStats, reply *string) error {
|
||||
if missing := utils.MissingStructFields(&attr, []string{"TPid", "ID"}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
if err := self.StorDb.SetTPStats([]*utils.TPStats{&attr}); err != nil {
|
||||
return utils.APIErrorHandler(err)
|
||||
}
|
||||
*reply = utils.OK
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrGetTPStat struct {
|
||||
TPid string // Tariff plan id
|
||||
ID string
|
||||
}
|
||||
|
||||
func (self *ApierV1) GetTPStat(attr AttrGetTPStat, reply *utils.TPStats) error {
|
||||
if missing := utils.MissingStructFields(&attr, []string{"TPid", "ID"}); len(missing) != 0 { //Params missing
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
if rls, err := self.StorDb.GetTPStats(attr.TPid, attr.ID); err != nil {
|
||||
if err.Error() != utils.ErrNotFound.Error() {
|
||||
err = utils.NewErrServerError(err)
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
*reply = *rls[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrGetTPStatIds struct {
|
||||
TPid string // Tariff plan id
|
||||
utils.Paginator
|
||||
}
|
||||
|
||||
func (self *ApierV1) GetTPStatIDs(attrs AttrGetTPStatIds, reply *[]string) error {
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"TPid"}); len(missing) != 0 { //Params missing
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
if ids, err := self.StorDb.GetTpTableIds(attrs.TPid, utils.TBLTPStats, utils.TPDistinctIds{"tag"}, nil, &attrs.Paginator); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
} else if ids == nil {
|
||||
return utils.ErrNotFound
|
||||
} else {
|
||||
*reply = ids
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ApierV1) RemTPStat(attrs AttrGetTPStat, reply *string) error {
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"TPid", "ID"}); len(missing) != 0 { //Params missing
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
if err := self.StorDb.RemTpData(utils.TBLTPStats, attrs.TPid, map[string]string{"tag": attrs.ID}); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
} else {
|
||||
*reply = utils.OK
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
175
apier/v1/tpstats_it_test.go
Normal file
175
apier/v1/tpstats_it_test.go
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
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 tpCfgPath string
|
||||
var tpCfg *config.CGRConfig
|
||||
var tpRPC *rpc.Client
|
||||
|
||||
func TestTPStatInitCfg(t *testing.T) {
|
||||
var err error
|
||||
tpCfgPath = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
tpCfg, err = config.NewCGRConfigFromFolder(tpCfgPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tpCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(tpCfg)
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestTPStatResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(tpCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
|
||||
func TestTPStatStartEngine(t *testing.T) {
|
||||
if _, err := engine.StopStartEngine(tpCfgPath, 1000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestTPStatRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tpRPC, err = jsonrpc.Dial("tcp", tpCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
var tpStat = &utils.TPStats{
|
||||
TPid: "TPS1",
|
||||
ID: "Stat1",
|
||||
Filters: []*utils.TPRequestFilter{
|
||||
&utils.TPRequestFilter{
|
||||
Type: "*string",
|
||||
FieldName: "Account",
|
||||
Values: []string{"1001", "1002"},
|
||||
},
|
||||
&utils.TPRequestFilter{
|
||||
Type: "*string_prefix",
|
||||
FieldName: "Destination",
|
||||
Values: []string{"10", "20"},
|
||||
},
|
||||
},
|
||||
ActivationInterval: &utils.TPActivationInterval{
|
||||
ActivationTime: "2014-07-29T15:00:00Z",
|
||||
ExpiryTime: "",
|
||||
},
|
||||
TTL: "1",
|
||||
Metrics: []string{"MetricValue", "MetricValueTwo"},
|
||||
Blocker: true,
|
||||
Stored: true,
|
||||
Weight: 20,
|
||||
Thresholds: nil,
|
||||
}
|
||||
|
||||
func TestTPStatGetTPStatIDs(t *testing.T) {
|
||||
var reply []string
|
||||
if err := tpRPC.Call("ApierV1.GetTPStatIDs", AttrGetTPStatIds{TPid: "TPS1"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTPStatSetTPStat(t *testing.T) {
|
||||
var result string
|
||||
if err := tpRPC.Call("ApierV1.SetTPStat", tpStat, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTPStatGetTPStat(t *testing.T) {
|
||||
var respond *utils.TPStats
|
||||
if err := tpRPC.Call("ApierV1.GetTPStat", &AttrGetTPStat{TPid: tpStat.TPid, ID: tpStat.ID}, &respond); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(tpStat, respond) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tpStat.TPid, respond.TPid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTPStatUpdateTPStat(t *testing.T) {
|
||||
var result string
|
||||
tpStat.Weight = 21
|
||||
tpStat.Filters = []*utils.TPRequestFilter{
|
||||
&utils.TPRequestFilter{
|
||||
Type: "*string",
|
||||
FieldName: "Account",
|
||||
Values: []string{"1001", "1002"},
|
||||
},
|
||||
&utils.TPRequestFilter{
|
||||
Type: "*string_prefix",
|
||||
FieldName: "Destination",
|
||||
Values: []string{"10", "20"},
|
||||
},
|
||||
&utils.TPRequestFilter{
|
||||
Type: "*rsr_fields",
|
||||
FieldName: "",
|
||||
Values: []string{"Subject(~^1.*1$)", "Destination(1002)"},
|
||||
},
|
||||
}
|
||||
if err := tpRPC.Call("ApierV1.SetTPStat", tpStat, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
var expectedTPS *utils.TPStats
|
||||
if err := tpRPC.Call("ApierV1.GetTPStat", &AttrGetTPStat{TPid: tpStat.TPid, ID: tpStat.ID}, &expectedTPS); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(tpStat, expectedTPS) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tpStat, expectedTPS)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTPStatRemTPStat(t *testing.T) {
|
||||
var resp string
|
||||
if err := tpRPC.Call("ApierV1.RemTPStat", &AttrGetTPStat{TPid: tpStat.TPid, ID: tpStat.ID}, &resp); err != nil {
|
||||
t.Error(err)
|
||||
} else if resp != utils.OK {
|
||||
t.Error("Unexpected reply returned", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTPStatCheckDelete(t *testing.T) {
|
||||
var respond *utils.TPStats
|
||||
if err := tpRPC.Call("ApierV1.GetTPStat", &AttrGetTPStat{TPid: "TPS1", ID: "Stat1"}, &respond); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTPStatKillEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -2024,8 +2024,11 @@ func APItoModelStats(st *utils.TPStats) (mdls TpStatsS) {
|
||||
mdl.Stored = st.Stored
|
||||
mdl.Weight = st.Weight
|
||||
mdl.QueueLength = st.QueueLength
|
||||
for _, val := range st.Metrics {
|
||||
mdl.Metrics = mdl.Metrics + utils.INFIELD_SEP + val
|
||||
for i, val := range st.Metrics {
|
||||
if i != 0 {
|
||||
mdl.Metrics += utils.INFIELD_SEP
|
||||
}
|
||||
mdl.Metrics += val
|
||||
}
|
||||
for _, val := range st.Thresholds {
|
||||
mdl.Thresholds = mdl.Thresholds + utils.INFIELD_SEP + val
|
||||
|
||||
@@ -15,6 +15,7 @@ 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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package engine
|
||||
|
||||
import (
|
||||
@@ -188,6 +189,34 @@ func TestApierTPTimingAsExportSlice(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPItoModelStats(t *testing.T) {
|
||||
tpS := &utils.TPStats{
|
||||
TPid: "TPS1",
|
||||
ID: "Stat1",
|
||||
Filters: []*utils.TPRequestFilter{
|
||||
&utils.TPRequestFilter{
|
||||
Type: "*string",
|
||||
FieldName: "Account",
|
||||
Values: []string{"1002"},
|
||||
},
|
||||
},
|
||||
ActivationInterval: &utils.TPActivationInterval{
|
||||
ActivationTime: "2014-07-29T15:00:00Z",
|
||||
ExpiryTime: "",
|
||||
},
|
||||
TTL: "1",
|
||||
Metrics: []string{"MetricValue"},
|
||||
Blocker: true,
|
||||
Stored: true,
|
||||
Weight: 20,
|
||||
Thresholds: nil,
|
||||
}
|
||||
expectedtpS := APItoModelStats(tpS)
|
||||
if !reflect.DeepEqual(expectedtpS, tpS) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", expectedtpS, tpS)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTPRatingPlanAsExportSlice(t *testing.T) {
|
||||
tpRpln := &utils.TPRatingPlan{
|
||||
TPid: "TEST_TPID",
|
||||
|
||||
@@ -180,7 +180,7 @@ func (ms *MongoStorage) EnsureIndexes() (err error) {
|
||||
Sparse: false,
|
||||
}
|
||||
for _, col := range []string{utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPDestinationRates, utils.TBLTPRatingPlans,
|
||||
utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPActions, utils.TBLTPActionPlans, utils.TBLTPActionTriggers} {
|
||||
utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPActions, utils.TBLTPActionPlans, utils.TBLTPActionTriggers, utils.TBLTPStats} {
|
||||
if err = db.C(col).EnsureIndex(idx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -379,6 +379,23 @@ func (ms *MongoStorage) GetTPResourceLimits(tpid, id string) ([]*utils.TPResourc
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetTPStats(tpid, id string) ([]*utils.TPStats, error) {
|
||||
filter := bson.M{
|
||||
"tpid": tpid,
|
||||
}
|
||||
if id != "" {
|
||||
filter["id"] = id
|
||||
}
|
||||
var results []*utils.TPStats
|
||||
session, col := ms.conn(utils.TBLTPStats)
|
||||
defer session.Close()
|
||||
err := col.Find(filter).All(&results)
|
||||
if len(results) == 0 {
|
||||
return results, utils.ErrNotFound
|
||||
}
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetTPDerivedChargers(tp *utils.TPDerivedChargers) ([]*utils.TPDerivedChargers, error) {
|
||||
filter := bson.M{"tpid": tp.TPid}
|
||||
if tp.Direction != "" {
|
||||
@@ -841,6 +858,20 @@ func (ms *MongoStorage) SetTPResourceLimits(tpRLs []*utils.TPResourceLimit) (err
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) SetTPRStats(tpS []*utils.TPStats) (err error) {
|
||||
if len(tpS) == 0 {
|
||||
return
|
||||
}
|
||||
session, col := ms.conn(utils.TBLTPStats)
|
||||
defer session.Close()
|
||||
tx := col.Bulk()
|
||||
for _, tp := range tpS {
|
||||
tx.Upsert(bson.M{"tpid": tp.TPid, "id": tp.ID}, tp)
|
||||
}
|
||||
_, err = tx.Run()
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) SetSMCost(smc *SMCost) error {
|
||||
if smc.CostDetails == nil {
|
||||
return nil
|
||||
@@ -1105,7 +1136,7 @@ func (ms *MongoStorage) GetCDRs(qryFltr *utils.CDRsFilter, remove bool) ([]*CDR,
|
||||
return cdrs, 0, nil
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetTPStats(tpid, id string) ([]*utils.TPStats, error) {
|
||||
func (ms *MongoStorage) GetTPStat(tpid, id string) ([]*utils.TPStats, error) {
|
||||
filter := bson.M{
|
||||
"tpid": tpid,
|
||||
}
|
||||
|
||||
@@ -190,9 +190,7 @@ func (self *SQLStorage) RemTpData(table, tpid string, args map[string]string) er
|
||||
if len(table) == 0 { // Remove tpid out of all tables
|
||||
for _, tblName := range []string{utils.TBLTPTimings, utils.TBLTPDestinations, utils.TBLTPRates, utils.TBLTPDestinationRates, utils.TBLTPRatingPlans, utils.TBLTPRateProfiles,
|
||||
utils.TBLTPSharedGroups, utils.TBLTPCdrStats, utils.TBLTPLcrs, utils.TBLTPActions, utils.TBLTPActionPlans, utils.TBLTPActionTriggers, utils.TBLTPAccountActions,
|
||||
utils.TBLTPDerivedChargers, utils.TBLTPAliases, utils.TBLTPUsers, utils.TBLTPResourceLimits,
|
||||
// utils.TBLTPStats
|
||||
} {
|
||||
utils.TBLTPDerivedChargers, utils.TBLTPAliases, utils.TBLTPUsers, utils.TBLTPResourceLimits, utils.TBLTPStats} {
|
||||
if err := tx.Table(tblName).Where("tpid = ?", tpid).Delete(nil).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
@@ -201,6 +199,7 @@ 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
|
||||
@@ -219,8 +218,10 @@ func (self *SQLStorage) SetTPTimings(timings []*utils.ApierTPTiming) error {
|
||||
if len(timings) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
tx := self.db.Begin()
|
||||
for _, timing := range timings {
|
||||
utils.Logger.Debug(fmt.Sprintf("#1(set) Id care trimite %s", timing.ID))
|
||||
if err := tx.Where(&TpTiming{Tpid: timing.TPid, Tag: timing.ID}).Delete(TpTiming{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
@@ -1170,6 +1171,8 @@ func (self *SQLStorage) GetTPDestinationRates(tpid, id string, pagination *utils
|
||||
func (self *SQLStorage) GetTPTimings(tpid, id string) ([]*utils.ApierTPTiming, error) {
|
||||
var tpTimings TpTimings
|
||||
q := self.db.Where("tpid = ?", tpid)
|
||||
utils.Logger.Debug(fmt.Sprintf("#1 Id care trimite %s", id))
|
||||
utils.Logger.Debug(fmt.Sprintf("#1 TPId care trimite %s", tpid))
|
||||
if len(id) != 0 {
|
||||
q = q.Where("tag = ?", id)
|
||||
}
|
||||
@@ -1177,6 +1180,7 @@ func (self *SQLStorage) GetTPTimings(tpid, id string) ([]*utils.ApierTPTiming, e
|
||||
return nil, err
|
||||
}
|
||||
ts := tpTimings.AsTPTimings()
|
||||
utils.Logger.Debug(fmt.Sprintf("#2 ce gaseste : %s", ts))
|
||||
if len(ts) == 0 {
|
||||
return ts, utils.ErrNotFound
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user