More derived charging infrastucture and tests

This commit is contained in:
DanB
2014-04-24 10:14:02 +02:00
parent 2a253892c5
commit b1b3f4ab18
8 changed files with 287 additions and 5 deletions

54
apier/derivedcharging.go Normal file
View 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
}

View 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
View 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
}

View 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")
}
}

View File

@@ -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])
}

View File

@@ -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
View 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)
}
}

View File

@@ -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
}