mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-16 13:49:53 +05:00
More derived charging infrastucture and tests
This commit is contained in:
54
apier/derivedcharging.go
Normal file
54
apier/derivedcharging.go
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute 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 WITH*out 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 apier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
// Get DerivedChargers applying to our call, appends general configured to account specific ones if that is configured
|
||||
func (self *ApierV1) DerivedChargers(attrs utils.AttrDerivedChargers, reply *utils.DerivedChargers) (err error) {
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Direction", "Account", "Subject"}); len(missing) != 0 {
|
||||
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
if hDc, err := engine.HandleGetDerivedChargers(self.AccountDb, self.Config, attrs); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
} else if hDc != nil {
|
||||
*reply = hDc
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrSetDerivedChargers struct {
|
||||
Tenant, Tor, Direction, Account, Subject string
|
||||
DerivedChargers utils.DerivedChargers
|
||||
}
|
||||
|
||||
func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *utils.DerivedChargers) (err error) {
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Direction", "Account", "Subject", "DerivedChargers"}); len(missing) != 0 {
|
||||
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
|
||||
}
|
||||
if err := self.AccountDb.SetDerivedChargers(utils.DerivedChargersKey(attrs.Tenant, attrs.Tor, attrs.Direction, attrs.Account, attrs.Subject),
|
||||
attrs.DerivedChargers); err != nil {
|
||||
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
45
apier/derivedcharging_test.go
Normal file
45
apier/derivedcharging_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute 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 WITH*out 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 apier
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var apierDcT *ApierV1
|
||||
|
||||
func init() {
|
||||
dataStorage, _ := engine.NewMapStorage()
|
||||
cfg, _ := config.NewDefaultCGRConfig()
|
||||
apierDcT = &ApierV1{AccountDb: engine.AccountingStorage(dataStorage), Config: cfg}
|
||||
}
|
||||
|
||||
func TestGetEmptyDC(t *testing.T) {
|
||||
attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "dan", Subject: "dan"}
|
||||
var dcs utils.DerivedChargers
|
||||
if err := apierDcT.DerivedChargers(attrs, &dcs); err != nil {
|
||||
t.Error("Unexpected error", err.Error())
|
||||
} else if !reflect.DeepEqual(dcs, apierDcT.Config.DerivedChargers) {
|
||||
t.Error("Returned DerivedChargers not matching the configured ones")
|
||||
}
|
||||
}
|
||||
52
engine/derivedcharging.go
Normal file
52
engine/derivedcharging.go
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute 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 WITH*out 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 engine
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
// Transparently handles merging between storage data and configuration, useful as local handler
|
||||
func HandleGetDerivedChargers(acntStorage AccountingStorage, cfg *config.CGRConfig, attrs utils.AttrDerivedChargers) (utils.DerivedChargers, error) {
|
||||
var dcs utils.DerivedChargers
|
||||
var err error
|
||||
strictKey := utils.DerivedChargersKey(attrs.Tenant, attrs.Tor, attrs.Direction, attrs.Account, attrs.Subject)
|
||||
anySubjKey := utils.DerivedChargersKey(attrs.Tenant, attrs.Tor, attrs.Direction, attrs.Account, utils.ANY)
|
||||
for _, dcKey := range []string{strictKey, anySubjKey} {
|
||||
if dcsDb, err := acntStorage.GetDerivedChargers(dcKey, false); err != nil && err.Error() != utils.ERR_NOT_FOUND {
|
||||
return nil, err
|
||||
} else if dcsDb != nil {
|
||||
dcs = dcsDb
|
||||
break
|
||||
}
|
||||
}
|
||||
if dcs == nil {
|
||||
dcs = cfg.DerivedChargers
|
||||
return dcs, nil
|
||||
}
|
||||
if cfg.CombinedDerivedChargers {
|
||||
for _, cfgDc := range cfg.DerivedChargers {
|
||||
if dcs, err = dcs.Append(cfgDc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return dcs, nil
|
||||
}
|
||||
88
engine/derivedcharging_test.go
Normal file
88
engine/derivedcharging_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute 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 WITH*out 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 engine
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var cfgDcT *config.CGRConfig
|
||||
var acntDb AccountingStorage
|
||||
|
||||
func init() {
|
||||
cfgDcT, _ = config.NewDefaultCGRConfig()
|
||||
acntDb, _ = NewMapStorage()
|
||||
acntDb.CacheAccounting(nil, nil, nil, nil)
|
||||
}
|
||||
|
||||
// Accounting db has no DerivedChargers nor configured defaults
|
||||
func TestHandleGetEmptyDC(t *testing.T) {
|
||||
attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "test2", Subject: "test2"}
|
||||
if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
|
||||
t.Error("Unexpected error", err.Error())
|
||||
} else if !reflect.DeepEqual(dcs, cfgDcT.DerivedChargers) {
|
||||
t.Error("Returned DerivedChargers not matching the configured ones")
|
||||
}
|
||||
}
|
||||
|
||||
// Accounting db has no DerivedChargers, configured defaults
|
||||
func TestHandleGetConfiguredDC(t *testing.T) {
|
||||
cfgedDC := utils.DerivedChargers{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"}}
|
||||
cfgDcT.DerivedChargers = cfgedDC
|
||||
attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "test3", Subject: "test3"}
|
||||
if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
|
||||
t.Error("Unexpected error", err.Error())
|
||||
} else if !reflect.DeepEqual(dcs, cfgedDC) {
|
||||
t.Error("Returned DerivedChargers not matching the configured ones")
|
||||
}
|
||||
}
|
||||
|
||||
// Receive composed derived chargers
|
||||
func TestHandleGetStoredDC(t *testing.T) {
|
||||
keyCharger1 := utils.DerivedChargersKey("cgrates.org", "call", "*out", "rif", "rif")
|
||||
charger1 := utils.DerivedChargers{
|
||||
&utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
|
||||
&utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
|
||||
}
|
||||
if err := acntDb.SetDerivedChargers(keyCharger1, charger1); err != nil {
|
||||
t.Error("Error on setDerivedChargers", err.Error())
|
||||
}
|
||||
// Expected Charger should have default configured values added
|
||||
expCharger1 := append(charger1, &utils.DerivedCharger{RunId: "responder1", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"})
|
||||
acntDb.CacheAccounting(nil, nil, nil, nil)
|
||||
attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "rif", Subject: "rif"}
|
||||
if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
|
||||
t.Error("Unexpected error", err.Error())
|
||||
} else if !reflect.DeepEqual(dcs, expCharger1) {
|
||||
t.Error("Returned DerivedChargers not matching the configured ones")
|
||||
}
|
||||
cfgDcT.CombinedDerivedChargers = false
|
||||
if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
|
||||
t.Error("Unexpected error", err.Error())
|
||||
} else if !reflect.DeepEqual(dcs, charger1) {
|
||||
t.Error("Returned DerivedChargers not matching the configured ones")
|
||||
}
|
||||
}
|
||||
@@ -839,7 +839,7 @@ func TestLoadDerivedChargers(t *testing.T) {
|
||||
&utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
|
||||
}
|
||||
keyCharger1 := utils.ConcatenatedKey("cgrates.org", "call", "*out", "dan", "dan")
|
||||
keyCharger1 := utils.DerivedChargersKey("cgrates.org", "call", "*out", "dan", "dan")
|
||||
if !reflect.DeepEqual(csvr.derivedChargers[keyCharger1], expCharger1) {
|
||||
t.Error("Unexpected charger", csvr.derivedChargers[keyCharger1])
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ func (rs *Responder) GetMaxSessionTime(arg CallDescriptor, reply *float64) (err
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) DerivedChargers(attrs utils.AttrDerivedChargers, dcs *utils.DerivedChargers) error {
|
||||
func (rs *Responder) GetDerivedChargers(attrs utils.AttrDerivedChargers, dcs *utils.DerivedChargers) error {
|
||||
// ToDo: Make it work with balancer if needed
|
||||
|
||||
if dcsH, err := HandleGetDerivedChargers(accountingStorage, config.CgrConfig(), attrs); err != nil {
|
||||
@@ -332,7 +332,7 @@ type Connector interface {
|
||||
MaxDebit(CallDescriptor, *CallCost) error
|
||||
RefundIncrements(CallDescriptor, *float64) error
|
||||
GetMaxSessionTime(CallDescriptor, *float64) error
|
||||
DerivedChargers(utils.AttrDerivedChargers, utils.DerivedChargers) error
|
||||
GetDerivedChargers(utils.AttrDerivedChargers, utils.DerivedChargers) error
|
||||
}
|
||||
|
||||
type RPCClientConnector struct {
|
||||
@@ -359,6 +359,6 @@ func (rcc *RPCClientConnector) GetMaxSessionTime(cd CallDescriptor, resp *float6
|
||||
return rcc.Client.Call("Responder.GetMaxSessionTime", cd, resp)
|
||||
}
|
||||
|
||||
func (rcc *RPCClientConnector) DerivedChargers(attrs utils.AttrDerivedChargers, dcs utils.DerivedChargers) error {
|
||||
func (rcc *RPCClientConnector) GetDerivedChargers(attrs utils.AttrDerivedChargers, dcs utils.DerivedChargers) error {
|
||||
return rcc.Client.Call("ApierV1.DerivedChargers", attrs, dcs)
|
||||
}
|
||||
|
||||
43
engine/responder_test.go
Normal file
43
engine/responder_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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 engine
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test internal abilites of GetDerivedChargers
|
||||
func TestResponderGetDerivedChargers(t *testing.T) {
|
||||
cfg, _ := config.NewDefaultCGRConfig()
|
||||
cfgedDC := utils.DerivedChargers{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"}}
|
||||
cfg.DerivedChargers = cfgedDC
|
||||
config.SetCgrConfig(cfg)
|
||||
r := Responder{}
|
||||
attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Tor: "call", Direction: "*out", Account: "dan", Subject: "dan"}
|
||||
var dcs utils.DerivedChargers
|
||||
if err := r.GetDerivedChargers(attrs, &dcs); err != nil {
|
||||
t.Error("Unexpected error", err.Error())
|
||||
} else if !reflect.DeepEqual(dcs, cfgedDC) {
|
||||
t.Errorf("Expecting: %v, received: %v ", cfgedDC, dcs)
|
||||
}
|
||||
}
|
||||
@@ -449,7 +449,7 @@ func (ms *MapStorage) GetDerivedChargers(key string, checkDb bool) (dcs utils.De
|
||||
err = ms.ms.Unmarshal(values, &dcs)
|
||||
cache2go.Cache(key, dcs)
|
||||
} else {
|
||||
return nil, errors.New("not found")
|
||||
return nil, errors.New(utils.ERR_NOT_FOUND)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user