mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-22 07:38:45 +05:00
Added *profileIgnoreFilters for attributes
This commit is contained in:
committed by
Dan Christian Bogos
parent
381070c8f6
commit
869da96a64
@@ -32,7 +32,7 @@ import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/ericlagergren/decimal"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -165,6 +165,9 @@ func testCfgGetConfig(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -235,6 +238,9 @@ func testCfgSetGetConfig(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -346,7 +352,7 @@ func testCfgSetJSONGetJSONConfig(t *testing.T) {
|
||||
if !reflect.DeepEqual(`"OK"`, utils.ToJSON(reply)) {
|
||||
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "OK", utils.ToJSON(reply))
|
||||
}
|
||||
expectedGet := `{"attributes":{"accounts_conns":["*internal"],"enabled":true,"indexed_selects":false,"nested_fields":false,"opts":{"*attributeIDs":{"*default":[]},"*processRuns":{"":2,"*default":2},"*profileRuns":{"*default":0}},"prefix_indexed_fields":[],"resources_conns":["*internal"],"stats_conns":["*localhost"],"suffix_indexed_fields":[]}}`
|
||||
expectedGet := `{"attributes":{"accounts_conns":["*internal"],"enabled":true,"indexed_selects":false,"nested_fields":false,"opts":{"*attributeIDs":{"*default":[]},"*processRuns":{"":2,"*default":2},"*profileIgnoreFilters":{"*default":false},"*profileRuns":{"*default":0}},"prefix_indexed_fields":[],"resources_conns":["*internal"],"stats_conns":["*localhost"],"suffix_indexed_fields":[]}}`
|
||||
var replyGet string
|
||||
if err := cfgRPC.Call(context.Background(), utils.ConfigSv1GetConfigAsJSON,
|
||||
&config.SectionWithAPIOpts{
|
||||
@@ -525,6 +531,9 @@ func testCfgSetGetConfigStore(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -631,6 +640,9 @@ func testCfgGetAfterReloadStore(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@ func TestConfigSetGetConfig(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -158,6 +161,9 @@ func TestConfigSetGetReloadConfig(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -207,6 +213,9 @@ func TestConfigSetGetReloadConfig(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -250,7 +259,7 @@ func TestConfigGetSetConfigFromJSONErr(t *testing.T) {
|
||||
}
|
||||
var replyGet string
|
||||
errGet := rlcCfg.GetConfigAsJSON(context.Background(), argsGet, &replyGet)
|
||||
expectedGet := `{"attributes":{"accounts_conns":["*localhost"],"enabled":true,"indexed_selects":true,"nested_fields":false,"opts":{"*attributeIDs":{"*default":[]},"*processRuns":{"*default":1},"*profileRuns":{"*default":0}},"prefix_indexed_fields":[],"resources_conns":["*localhost"],"stats_conns":["*localhost"],"suffix_indexed_fields":[]}}`
|
||||
expectedGet := `{"attributes":{"accounts_conns":["*localhost"],"enabled":true,"indexed_selects":true,"nested_fields":false,"opts":{"*attributeIDs":{"*default":[]},"*processRuns":{"*default":1},"*profileIgnoreFilters":{"*default":false},"*profileRuns":{"*default":0}},"prefix_indexed_fields":[],"resources_conns":["*localhost"],"stats_conns":["*localhost"],"suffix_indexed_fields":[]}}`
|
||||
if err != nil {
|
||||
t.Errorf("Expected <%+v>, \nReceived <%+v>", nil, errGet)
|
||||
}
|
||||
|
||||
@@ -24,9 +24,10 @@ import (
|
||||
)
|
||||
|
||||
type AttributesOpts struct {
|
||||
AttributeIDs []*utils.DynamicStringSliceOpt
|
||||
ProcessRuns []*utils.DynamicIntOpt
|
||||
ProfileRuns []*utils.DynamicIntOpt
|
||||
AttributeIDs []*utils.DynamicStringSliceOpt
|
||||
ProcessRuns []*utils.DynamicIntOpt
|
||||
ProfileRuns []*utils.DynamicIntOpt
|
||||
ProfileIgnoreFilters []*utils.DynamicBoolOpt
|
||||
}
|
||||
|
||||
// AttributeSCfg is the configuration of attribute service
|
||||
@@ -65,6 +66,9 @@ func (attrOpts *AttributesOpts) loadFromJSONCfg(jsnCfg *AttributesOptsJson) {
|
||||
if jsnCfg.ProfileRuns != nil {
|
||||
attrOpts.ProfileRuns = append(attrOpts.ProfileRuns, utils.MapToDynamicIntOpts(jsnCfg.ProfileRuns)...)
|
||||
}
|
||||
if jsnCfg.ProfileIgnoreFilters != nil {
|
||||
attrOpts.ProfileIgnoreFilters = append(attrOpts.ProfileIgnoreFilters, utils.MapToDynamicBoolOpts(jsnCfg.ProfileIgnoreFilters)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (alS *AttributeSCfg) loadFromJSONCfg(jsnCfg *AttributeSJsonCfg) (err error) {
|
||||
@@ -107,9 +111,10 @@ func (alS *AttributeSCfg) loadFromJSONCfg(jsnCfg *AttributeSJsonCfg) (err error)
|
||||
// AsMapInterface returns the config as a map[string]interface{}
|
||||
func (alS AttributeSCfg) AsMapInterface(string) interface{} {
|
||||
opts := map[string]interface{}{
|
||||
utils.MetaAttributeIDsCfg: utils.DynamicStringSliceOptsToMap(alS.Opts.AttributeIDs),
|
||||
utils.MetaProcessRunsCfg: utils.DynamicIntOptsToMap(alS.Opts.ProcessRuns),
|
||||
utils.MetaProfileRunsCfg: utils.DynamicIntOptsToMap(alS.Opts.ProfileRuns),
|
||||
utils.MetaAttributeIDsCfg: utils.DynamicStringSliceOptsToMap(alS.Opts.AttributeIDs),
|
||||
utils.MetaProcessRunsCfg: utils.DynamicIntOptsToMap(alS.Opts.ProcessRuns),
|
||||
utils.MetaProfileRunsCfg: utils.DynamicIntOptsToMap(alS.Opts.ProfileRuns),
|
||||
utils.MetaProfileIgnoreFilters: utils.DynamicBoolOptsToMap(alS.Opts.ProfileIgnoreFilters),
|
||||
}
|
||||
mp := map[string]interface{}{
|
||||
utils.EnabledCfg: alS.Enabled,
|
||||
@@ -152,10 +157,15 @@ func (attrOpts AttributesOpts) Clone() *AttributesOpts {
|
||||
if attrOpts.ProfileRuns != nil {
|
||||
profileRuns = utils.CloneDynamicIntOpt(attrOpts.ProfileRuns)
|
||||
}
|
||||
var profileIgnoreFilters []*utils.DynamicBoolOpt
|
||||
if attrOpts.ProfileRuns != nil {
|
||||
profileIgnoreFilters = utils.CloneDynamicBoolOpt(attrOpts.ProfileIgnoreFilters)
|
||||
}
|
||||
return &AttributesOpts{
|
||||
AttributeIDs: attrIDs,
|
||||
ProcessRuns: processRuns,
|
||||
ProfileRuns: profileRuns,
|
||||
AttributeIDs: attrIDs,
|
||||
ProcessRuns: processRuns,
|
||||
ProfileRuns: profileRuns,
|
||||
ProfileIgnoreFilters: profileIgnoreFilters,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,9 +203,10 @@ func (alS AttributeSCfg) Clone() (cln *AttributeSCfg) {
|
||||
}
|
||||
|
||||
type AttributesOptsJson struct {
|
||||
AttributeIDs map[string][]string `json:"*attributeIDs"`
|
||||
ProcessRuns map[string]int `json:"*processRuns"`
|
||||
ProfileRuns map[string]int `json:"*profileRuns"`
|
||||
AttributeIDs map[string][]string `json:"*attributeIDs"`
|
||||
ProcessRuns map[string]int `json:"*processRuns"`
|
||||
ProfileRuns map[string]int `json:"*profileRuns"`
|
||||
ProfileIgnoreFilters map[string]bool `json:"*profileIgnoreFilters"`
|
||||
}
|
||||
|
||||
// Attribute service config section
|
||||
@@ -225,6 +236,9 @@ func diffAttributesOptsJsonCfg(d *AttributesOptsJson, v1, v2 *AttributesOpts) *A
|
||||
if !utils.DynamicIntOptEqual(v1.ProfileRuns, v2.ProfileRuns) {
|
||||
d.ProfileRuns = utils.DynamicIntOptsToMap(v2.ProfileRuns)
|
||||
}
|
||||
if !utils.DynamicBoolOptEqual(v1.ProfileIgnoreFilters, v2.ProfileIgnoreFilters) {
|
||||
d.ProfileIgnoreFilters = utils.DynamicBoolOptsToMap(v2.ProfileIgnoreFilters)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,12 @@ func TestAttributeSCfgloadFromJsonCfg(t *testing.T) {
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
ProfileIgnoreFilters: []*utils.DynamicBoolOpt{
|
||||
{
|
||||
FilterIDs: []string{utils.MetaDefault},
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
jsnCfg := NewDefaultCGRConfig()
|
||||
@@ -111,6 +117,9 @@ func TestAttributeSCfgAsMapInterface(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
@@ -152,6 +161,9 @@ func TestAttributeSCfgAsMapInterface2(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
@@ -186,6 +198,9 @@ func TestAttributeSCfgAsMapInterface3(t *testing.T) {
|
||||
utils.MetaProfileRunsCfg: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
utils.MetaProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
if conv, err := NewCGRConfigFromJSONStringWithDefaults(myJSONStr); err != nil {
|
||||
|
||||
@@ -701,7 +701,10 @@ const CGRATES_CFG_JSON = `
|
||||
},
|
||||
"*profileRuns": { // number of runs a profile will process during the event
|
||||
"*default": 0,
|
||||
},
|
||||
},
|
||||
"*profileIgnoreFilters": { // if we should check the filters
|
||||
"*default": false,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -173,6 +173,12 @@ func testCGRConfigReloadAttributeS(t *testing.T) {
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
ProfileIgnoreFilters: []*utils.DynamicBoolOpt{
|
||||
{
|
||||
FilterIDs: []string{utils.MetaDefault},
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(expAttr, cfg.AttributeSCfg()) {
|
||||
@@ -226,6 +232,12 @@ func testCGRConfigReloadAttributeSWithDB(t *testing.T) {
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
ProfileIgnoreFilters: []*utils.DynamicBoolOpt{
|
||||
{
|
||||
FilterIDs: []string{utils.MetaDefault},
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(expAttr, cfg.AttributeSCfg()) {
|
||||
|
||||
@@ -803,6 +803,9 @@ func TestDfAttributeServJsonCfg(t *testing.T) {
|
||||
ProfileRuns: map[string]int{
|
||||
utils.MetaDefault: 0,
|
||||
},
|
||||
ProfileIgnoreFilters: map[string]bool{
|
||||
utils.MetaDefault: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON))
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -56,7 +56,7 @@ func (alS *AttributeService) Shutdown() {
|
||||
|
||||
// attributeProfileForEvent returns the matching attribute
|
||||
func (alS *AttributeService) attributeProfileForEvent(ctx *context.Context, tnt string, attrsIDs []string,
|
||||
evNm utils.MapStorage, lastID string, processedPrfNo map[string]int, profileRuns int) (matchAttrPrfl *AttributeProfile, err error) {
|
||||
evNm utils.MapStorage, lastID string, processedPrfNo map[string]int, profileRuns int, ignoreFilters bool) (matchAttrPrfl *AttributeProfile, err error) {
|
||||
var attrIDs []string
|
||||
if len(attrsIDs) != 0 {
|
||||
attrIDs = attrsIDs
|
||||
@@ -84,11 +84,13 @@ func (alS *AttributeService) attributeProfileForEvent(ctx *context.Context, tnt
|
||||
}
|
||||
tntID := aPrfl.TenantIDInline()
|
||||
(evNm[utils.MetaVars].(utils.MapStorage))[utils.MetaAttrPrfTenantID] = tntID
|
||||
if pass, err := alS.filterS.Pass(ctx, tnt, aPrfl.FilterIDs,
|
||||
evNm); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
if len(attrsIDs) == 0 || !ignoreFilters {
|
||||
if pass, err := alS.filterS.Pass(ctx, tnt, aPrfl.FilterIDs,
|
||||
evNm); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (matchAttrPrfl == nil || matchAttrPrfl.Weight < aPrfl.Weight) &&
|
||||
tntID != lastID &&
|
||||
@@ -137,8 +139,13 @@ func (alS *AttributeService) processEvent(ctx *context.Context, tnt string, args
|
||||
utils.OptsAttributesAttributeIDs); err != nil {
|
||||
return
|
||||
}
|
||||
var ignFilters bool
|
||||
if ignFilters, err = GetBoolOpts(ctx, tnt, args, alS.filterS, alS.cgrcfg.AttributeSCfg().Opts.ProfileIgnoreFilters,
|
||||
utils.MetaProfileIgnoreFilters); err != nil {
|
||||
return
|
||||
}
|
||||
var attrPrf *AttributeProfile
|
||||
if attrPrf, err = alS.attributeProfileForEvent(ctx, tnt, attrIDs, evNm, lastID, processedPrfNo, profileRuns); err != nil {
|
||||
if attrPrf, err = alS.attributeProfileForEvent(ctx, tnt, attrIDs, evNm, lastID, processedPrfNo, profileRuns, ignFilters); err != nil {
|
||||
return
|
||||
}
|
||||
rply = &AttrSProcessEventReply{
|
||||
@@ -212,13 +219,18 @@ func (alS *AttributeService) V1GetAttributeForEvent(ctx *context.Context, args *
|
||||
utils.OptsAttributesAttributeIDs); err != nil {
|
||||
return
|
||||
}
|
||||
var ignFilters bool
|
||||
if ignFilters, err = GetBoolOpts(ctx, tnt, args, alS.filterS, alS.cgrcfg.AttributeSCfg().Opts.ProfileIgnoreFilters,
|
||||
utils.MetaProfileIgnoreFilters); err != nil {
|
||||
return
|
||||
}
|
||||
attrPrf, err := alS.attributeProfileForEvent(ctx, tnt, attrIDs, utils.MapStorage{
|
||||
utils.MetaReq: args.Event,
|
||||
utils.MetaOpts: args.APIOpts,
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
}, utils.EmptyString, make(map[string]int), 0, ignFilters)
|
||||
if err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
err = utils.NewErrServerError(err)
|
||||
|
||||
@@ -432,7 +432,7 @@ func TestAttributesattributeProfileForEventNoDBConn(t *testing.T) {
|
||||
lastID := ""
|
||||
alS.dm = nil
|
||||
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID, make(map[string]int), 0); err == nil || err != utils.ErrNoDatabaseConn {
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID, make(map[string]int), 0, false); err == nil || err != utils.ErrNoDatabaseConn {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNoDatabaseConn, err)
|
||||
} else if rcv != nil {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
|
||||
@@ -470,7 +470,7 @@ func TestAttributesattributeProfileForEventErrNotFound(t *testing.T) {
|
||||
}
|
||||
lastID := ""
|
||||
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID, make(map[string]int), 0); err == nil || err != utils.ErrNotFound {
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_3"}, evNm, lastID, make(map[string]int), 0, false); err == nil || err != utils.ErrNotFound {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
|
||||
} else if rcv != nil {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
|
||||
@@ -529,7 +529,7 @@ func TestAttributesattributeProfileForEventErrPass(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{},
|
||||
}
|
||||
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_1"}, evNm, lastID, make(map[string]int), 0); err == nil || err != utils.ErrWrongPath {
|
||||
if rcv, err := alS.attributeProfileForEvent(context.Background(), tnt, []string{"ATTR_1"}, evNm, lastID, make(map[string]int), 0, false); err == nil || err != utils.ErrWrongPath {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ErrWrongPath, err)
|
||||
} else if rcv != nil {
|
||||
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
|
||||
|
||||
@@ -229,7 +229,7 @@ func TestAttributeProfileForEvent(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
}, utils.EmptyString, make(map[string]int), 0, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -248,7 +248,7 @@ func TestAttributeProfileForEvent(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
}, utils.EmptyString, make(map[string]int), 0, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
@@ -267,7 +267,7 @@ func TestAttributeProfileForEvent(t *testing.T) {
|
||||
utils.MetaVars: utils.MapStorage{
|
||||
utils.OptsAttributesProcessRuns: 0,
|
||||
},
|
||||
}, utils.EmptyString, make(map[string]int), 0)
|
||||
}, utils.EmptyString, make(map[string]int), 0, false)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
|
||||
1
go.mod
1
go.mod
@@ -50,7 +50,6 @@ require (
|
||||
github.com/pierrec/lz4 v2.6.0+incompatible // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/segmentio/kafka-go v0.4.8
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc
|
||||
github.com/streadway/amqp v1.0.0
|
||||
github.com/tinylib/msgp v1.1.5 // indirect
|
||||
github.com/willf/bitset v1.1.11 // indirect
|
||||
|
||||
@@ -1678,11 +1678,7 @@ func (sS *SessionS) BiRPCv1AuthorizeEvent(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if thdS {
|
||||
var thIDs []string
|
||||
if thIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesThresholdIDs); err != nil {
|
||||
return
|
||||
}
|
||||
tIDs, err := sS.processThreshold(ctx, args, thIDs, true)
|
||||
tIDs, err := sS.processThreshold(ctx, args, true)
|
||||
if err != nil && err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> error: %s processing event %+v with ThresholdS.",
|
||||
@@ -1703,11 +1699,7 @@ func (sS *SessionS) BiRPCv1AuthorizeEvent(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if stS {
|
||||
var statIDs []string
|
||||
if statIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesStatIDs); err != nil {
|
||||
return
|
||||
}
|
||||
sIDs, err := sS.processStats(ctx, args, statIDs, false)
|
||||
sIDs, err := sS.processStats(ctx, args, false)
|
||||
if err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
@@ -1927,11 +1919,7 @@ func (sS *SessionS) BiRPCv1InitiateSession(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if thdS {
|
||||
var thIDs []string
|
||||
if thIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesThresholdIDs); err != nil {
|
||||
return
|
||||
}
|
||||
tIDs, err := sS.processThreshold(ctx, args, thIDs, true)
|
||||
tIDs, err := sS.processThreshold(ctx, args, true)
|
||||
if err != nil && err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> error: %s processing event %+v with ThresholdS.",
|
||||
@@ -1952,11 +1940,7 @@ func (sS *SessionS) BiRPCv1InitiateSession(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if stS {
|
||||
var statIDs []string
|
||||
if statIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesStatIDs); err != nil {
|
||||
return
|
||||
}
|
||||
sIDs, err := sS.processStats(ctx, args, statIDs, false)
|
||||
sIDs, err := sS.processStats(ctx, args, false)
|
||||
if err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
@@ -2219,11 +2203,7 @@ func (sS *SessionS) BiRPCv1TerminateSession(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if thdS {
|
||||
var thIDs []string
|
||||
if thIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesThresholdIDs); err != nil {
|
||||
return
|
||||
}
|
||||
_, err := sS.processThreshold(ctx, args, thIDs, true)
|
||||
_, err := sS.processThreshold(ctx, args, true)
|
||||
if err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
@@ -2244,11 +2224,7 @@ func (sS *SessionS) BiRPCv1TerminateSession(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if stS {
|
||||
var statIDs []string
|
||||
if statIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesStatIDs); err != nil {
|
||||
return
|
||||
}
|
||||
_, err := sS.processStats(ctx, args, statIDs, false)
|
||||
_, err := sS.processStats(ctx, args, false)
|
||||
if err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
@@ -2408,11 +2384,7 @@ func (sS *SessionS) BiRPCv1ProcessMessage(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if thdS {
|
||||
var thIDs []string
|
||||
if thIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesThresholdIDs); err != nil {
|
||||
return
|
||||
}
|
||||
tIDs, err := sS.processThreshold(ctx, args, thIDs, true)
|
||||
tIDs, err := sS.processThreshold(ctx, args, true)
|
||||
if err != nil && err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> error: %s processing event %+v with ThresholdS.",
|
||||
@@ -2433,11 +2405,7 @@ func (sS *SessionS) BiRPCv1ProcessMessage(ctx *context.Context,
|
||||
return
|
||||
}
|
||||
if stS {
|
||||
var stIDs []string
|
||||
if stIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesStatIDs); err != nil {
|
||||
return
|
||||
}
|
||||
sIDs, err := sS.processStats(ctx, args, stIDs, false)
|
||||
sIDs, err := sS.processStats(ctx, args, false)
|
||||
if err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
utils.Logger.Warning(
|
||||
@@ -2574,12 +2542,8 @@ func (sS *SessionS) BiRPCv1ProcessEvent(ctx *context.Context,
|
||||
}
|
||||
if thdS {
|
||||
rply.ThresholdIDs = make(map[string][]string)
|
||||
var thIDs []string
|
||||
if thIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesThresholdIDs); err != nil {
|
||||
return
|
||||
}
|
||||
for runID, cgrEv := range getDerivedEvents(events, utils.OptAsBool(args.APIOpts, utils.OptsSesThresholdSDerivedReply)) {
|
||||
tIDs, err := sS.processThreshold(ctx, cgrEv, thIDs, true)
|
||||
tIDs, err := sS.processThreshold(ctx, cgrEv, true)
|
||||
if err != nil && err.Error() != utils.ErrNotFound.Error() {
|
||||
if blockError {
|
||||
return utils.NewErrThresholdS(err)
|
||||
@@ -2607,12 +2571,8 @@ func (sS *SessionS) BiRPCv1ProcessEvent(ctx *context.Context,
|
||||
}
|
||||
if stS {
|
||||
rply.StatQueueIDs = make(map[string][]string)
|
||||
var stIDs []string
|
||||
if stIDs, err = utils.OptAsStringSlice(args.APIOpts, utils.OptsSesStatIDs); err != nil {
|
||||
return
|
||||
}
|
||||
for runID, cgrEv := range getDerivedEvents(events, utils.OptAsBool(args.APIOpts, utils.OptsSesStatSDerivedReply)) {
|
||||
sIDs, err := sS.processStats(ctx, cgrEv, stIDs, true)
|
||||
sIDs, err := sS.processStats(ctx, cgrEv, true)
|
||||
if err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
if blockError {
|
||||
@@ -3041,14 +3001,10 @@ func (sS *SessionS) processCDR(ctx *context.Context, cgrEv *utils.CGREvent, rply
|
||||
}
|
||||
|
||||
// processThreshold will receive the event and send it to ThresholdS to be processed
|
||||
func (sS *SessionS) processThreshold(ctx *context.Context, cgrEv *utils.CGREvent, thIDs []string, clnb bool) (tIDs []string, err error) {
|
||||
func (sS *SessionS) processThreshold(ctx *context.Context, cgrEv *utils.CGREvent, clnb bool) (tIDs []string, err error) {
|
||||
if len(sS.cgrCfg.SessionSCfg().ThresholdSConns) == 0 {
|
||||
return tIDs, utils.NewErrNotConnected(utils.ThresholdS)
|
||||
}
|
||||
// check if we have thresholdIDs
|
||||
if len(thIDs) != 0 {
|
||||
cgrEv.APIOpts[utils.OptsThresholdsThresholdIDs] = thIDs
|
||||
}
|
||||
cgrEv.SetCloneable(clnb)
|
||||
//initialize the returned variable
|
||||
err = sS.connMgr.Call(ctx, sS.cgrCfg.SessionSCfg().ThresholdSConns, utils.ThresholdSv1ProcessEvent, cgrEv, &tIDs)
|
||||
@@ -3056,7 +3012,7 @@ func (sS *SessionS) processThreshold(ctx *context.Context, cgrEv *utils.CGREvent
|
||||
}
|
||||
|
||||
// processStats will receive the event and send it to StatS to be processed
|
||||
func (sS *SessionS) processStats(ctx *context.Context, cgrEv *utils.CGREvent, stsIDs []string, clnb bool) (sIDs []string, err error) {
|
||||
func (sS *SessionS) processStats(ctx *context.Context, cgrEv *utils.CGREvent, clnb bool) (sIDs []string, err error) {
|
||||
if len(sS.cgrCfg.SessionSCfg().StatSConns) == 0 {
|
||||
return sIDs, utils.NewErrNotConnected(utils.StatS)
|
||||
}
|
||||
@@ -3064,10 +3020,6 @@ func (sS *SessionS) processStats(ctx *context.Context, cgrEv *utils.CGREvent, st
|
||||
statArgs := &engine.StatsArgsProcessEvent{
|
||||
CGREvent: cgrEv,
|
||||
}
|
||||
// check in case we have StatIDs inside flags
|
||||
if len(stsIDs) != 0 {
|
||||
cgrEv.APIOpts[utils.OptsStatsStatIDs] = stsIDs
|
||||
}
|
||||
statArgs.SetCloneable(clnb)
|
||||
//initialize the returned variable
|
||||
err = sS.connMgr.Call(ctx, sS.cgrCfg.SessionSCfg().StatSConns, utils.StatSv1ProcessEvent, statArgs, &sIDs)
|
||||
|
||||
@@ -2168,13 +2168,12 @@ var CGROptionsSet = NewStringSet([]string{OptsRatesRateProfileIDs, OptsRatesStar
|
||||
OptsAttributeS, OptsSesAttributeSDerivedReply, OptsSesBlockerError, OptsRoutesUsage,
|
||||
OptsCDRs, OptsSesCDRsDerivedReply, OptsChargerS, OptsResourceS, OptsSesResourceSAuthorize,
|
||||
OptsSesResourceSAlocate, OptsSesResourceSRelease, OptsSesResourceSDerivedReply, OptsRouteS,
|
||||
OptsSesRouteSDerivedReply, OptsSesRouteSIgnoreErrors, OptsSesRouteSMaxCost, OptsStatS,
|
||||
OptsSesStatSDerivedReply, OptsSesStatIDs, OptsSesSTIRAuthenticate, OptsSesSTIRDerivedReply,
|
||||
OptsSesSTIRInitiate, OptsThresholdS, OptsSesThresholdSDerivedReply, OptsSesThresholdIDs,
|
||||
OptsSesRouteSDerivedReply, OptsStatS, OptsSesStatSDerivedReply, OptsSesSTIRAuthenticate, OptsSesSTIRDerivedReply,
|
||||
OptsSesSTIRInitiate, OptsThresholdS, OptsSesThresholdSDerivedReply,
|
||||
OptsSesMaxUsage, OptsSesForceDuration, OptsSesInitiate, OptsSesUpdate, OptsSesTerminate,
|
||||
OptsSesMessage, OptsAttributeS, OptsChargerS, OptsCDRsExport, OptsCDRsRefund,
|
||||
OptsCDRsRerate, OptsStatS, OptsCDRsStore, OptsThresholdS, OptsRateS, OptsAccountS,
|
||||
OptsAccountsUsage, OptsStatsStatIDs, OptsActionsActionProfileIDs})
|
||||
OptsAccountsUsage, OptsStatsStatIDs, OptsActionsActionProfileIDs, MetaProfileIgnoreFilters})
|
||||
|
||||
// Event Opts
|
||||
const (
|
||||
@@ -2206,15 +2205,11 @@ const (
|
||||
OptsSesResourceSRelease = "*sesResourceSRelease"
|
||||
OptsSesResourceSDerivedReply = "*sesResourceSDerivedReply"
|
||||
OptsSesRouteSDerivedReply = "*sesRouteSDerivedReply"
|
||||
OptsSesRouteSIgnoreErrors = "*sesRouteSIgnoreErrors"
|
||||
OptsSesRouteSMaxCost = "*sesRouteSMaxCost"
|
||||
OptsSesStatSDerivedReply = "*sesStatSDerivedReply"
|
||||
OptsSesStatIDs = "*sesStatIDs"
|
||||
OptsSesSTIRAuthenticate = "*sesSTIRAuthenticate"
|
||||
OptsSesSTIRDerivedReply = "*sesSTIRDerivedReply"
|
||||
OptsSesSTIRInitiate = "*sesSTIRInitiate"
|
||||
OptsSesThresholdSDerivedReply = "*sesThresholdSDerivedReply"
|
||||
OptsSesThresholdIDs = "*sesThresholdIDs"
|
||||
OptsSesMaxUsage = "*sesMaxUsage"
|
||||
OptsSesForceDuration = "*sesForceDuration"
|
||||
OptsSesInitiate = "*sesInitiate"
|
||||
@@ -2286,12 +2281,13 @@ const (
|
||||
OptsStirPrivateKeyPath = "*stirPrivateKeyPath"
|
||||
|
||||
// Others
|
||||
OptsContext = "*context"
|
||||
Subsys = "*subsys"
|
||||
MetaMethod = "*reqMethod"
|
||||
MetaEventType = "*eventType"
|
||||
EventType = "EventType"
|
||||
SchedulerInit = "SchedulerInit"
|
||||
OptsContext = "*context"
|
||||
Subsys = "*subsys"
|
||||
MetaMethod = "*reqMethod"
|
||||
MetaEventType = "*eventType"
|
||||
EventType = "EventType"
|
||||
SchedulerInit = "SchedulerInit"
|
||||
MetaProfileIgnoreFilters = "*profileIgnoreFilters"
|
||||
|
||||
RemoteHostOpt = "*rmtHost"
|
||||
CacheOpt = "*cache"
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cron"
|
||||
"github.com/ericlagergren/decimal"
|
||||
)
|
||||
|
||||
func TestLibratesTenantID(t *testing.T) {
|
||||
@@ -779,227 +778,6 @@ func TestRateProfileRunTimesPassingActivationTIme(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCostForIntervals(t *testing.T) {
|
||||
minDecimal, err := NewDecimalFromUsage("1m")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
secDecimal, err := NewDecimalFromUsage("1s")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rt0 := &Rate{
|
||||
ID: "RATE0",
|
||||
IntervalRates: []*IntervalRate{
|
||||
{
|
||||
IntervalStart: NewDecimal(0, 0),
|
||||
Unit: minDecimal,
|
||||
Increment: minDecimal,
|
||||
RecurrentFee: NewDecimal(24, 1),
|
||||
},
|
||||
{
|
||||
IntervalStart: NewDecimal(int64(60*time.Second), 0),
|
||||
Unit: minDecimal,
|
||||
Increment: secDecimal,
|
||||
RecurrentFee: NewDecimal(24, 1),
|
||||
},
|
||||
},
|
||||
}
|
||||
rt0.Compile()
|
||||
rt1 := &Rate{
|
||||
ID: "RATE1",
|
||||
IntervalRates: []*IntervalRate{
|
||||
{
|
||||
|
||||
IntervalStart: NewDecimal(0, 0),
|
||||
Unit: minDecimal,
|
||||
Increment: secDecimal,
|
||||
RecurrentFee: NewDecimal(12, 1),
|
||||
},
|
||||
{
|
||||
|
||||
IntervalStart: NewDecimal(int64(2*time.Minute), 0),
|
||||
Unit: minDecimal,
|
||||
Increment: secDecimal,
|
||||
RecurrentFee: NewDecimal(6, 1),
|
||||
},
|
||||
},
|
||||
}
|
||||
rt1.Compile()
|
||||
rtsMap := map[string]*IntervalRate{
|
||||
"RATE0_0": rt0.IntervalRates[0],
|
||||
"RATE0_1": rt0.IntervalRates[1],
|
||||
"RATE1_0": rt1.IntervalRates[0],
|
||||
"RATE1_1": rt1.IntervalRates[1],
|
||||
}
|
||||
|
||||
rtIvls := []*RateSInterval{
|
||||
{
|
||||
IntervalStart: NewDecimal(0, 0),
|
||||
Increments: []*RateSIncrement{
|
||||
{
|
||||
IncrementStart: NewDecimal(0, 0),
|
||||
Usage: NewDecimal(int64(time.Minute), 0),
|
||||
RateIntervalIndex: 0,
|
||||
RateID: "RATE0_0",
|
||||
CompressFactor: 1,
|
||||
},
|
||||
{
|
||||
IncrementStart: NewDecimal(int64(time.Minute), 0),
|
||||
Usage: NewDecimal(int64(30*time.Second), 0),
|
||||
RateIntervalIndex: 1,
|
||||
RateID: "RATE0_1",
|
||||
CompressFactor: 30,
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
{
|
||||
IntervalStart: NewDecimal(int64(90*time.Second), 0),
|
||||
Increments: []*RateSIncrement{
|
||||
{
|
||||
IncrementStart: NewDecimal(int64(90*time.Second), 0),
|
||||
Usage: NewDecimal(int64(30*time.Second), 0),
|
||||
RateIntervalIndex: 0,
|
||||
RateID: "RATE1_0",
|
||||
CompressFactor: 30,
|
||||
},
|
||||
{
|
||||
IncrementStart: NewDecimal(int64(2*time.Minute), 0),
|
||||
Usage: NewDecimal(int64(10*time.Minute), 0),
|
||||
RateIntervalIndex: 1,
|
||||
RateID: "RATE1_1",
|
||||
CompressFactor: 10,
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
}
|
||||
eDcml, _ := new(decimal.Big).SetFloat64(4.3).Float64()
|
||||
cost := CostForIntervals(rtIvls, rtsMap)
|
||||
if costFlt, _ := cost.Float64(); costFlt != eDcml {
|
||||
t.Errorf("eDcml: %f, received: %+v", eDcml, cost)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCostForIntervalsWIthFixedFee(t *testing.T) {
|
||||
minDecimal, err := NewDecimalFromUsage("1m")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
secDecimal, err := NewDecimalFromUsage("1s")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
rt0 := &Rate{
|
||||
ID: "RATE0",
|
||||
IntervalRates: []*IntervalRate{
|
||||
{
|
||||
IntervalStart: NewDecimal(0, 0),
|
||||
FixedFee: NewDecimal(4, 1),
|
||||
RecurrentFee: NewDecimal(24, 1),
|
||||
Unit: minDecimal,
|
||||
Increment: minDecimal,
|
||||
},
|
||||
{
|
||||
IntervalStart: NewDecimal(int64(60*time.Second), 0),
|
||||
RecurrentFee: NewDecimal(24, 1),
|
||||
Unit: minDecimal,
|
||||
Increment: secDecimal,
|
||||
},
|
||||
},
|
||||
}
|
||||
rt0.Compile()
|
||||
rt1 := &Rate{
|
||||
ID: "RATE1",
|
||||
IntervalRates: []*IntervalRate{
|
||||
//{},
|
||||
{
|
||||
IntervalStart: NewDecimal(0, 0),
|
||||
FixedFee: NewDecimal(2, 1),
|
||||
RecurrentFee: NewDecimal(12, 1),
|
||||
Unit: minDecimal,
|
||||
Increment: secDecimal,
|
||||
},
|
||||
{
|
||||
IntervalStart: NewDecimal(int64(2*time.Minute), 0),
|
||||
RecurrentFee: NewDecimal(6, 1),
|
||||
Unit: minDecimal,
|
||||
Increment: secDecimal,
|
||||
},
|
||||
},
|
||||
}
|
||||
rt1.Compile()
|
||||
rtsMap := map[string]*IntervalRate{
|
||||
"RATE0_0": rt0.IntervalRates[0],
|
||||
"RATE0_1": rt0.IntervalRates[1],
|
||||
"RATE1_0": rt1.IntervalRates[0],
|
||||
"RATE1_1": rt1.IntervalRates[1],
|
||||
}
|
||||
|
||||
rtIvls := []*RateSInterval{
|
||||
{
|
||||
IntervalStart: NewDecimal(0, 0),
|
||||
Increments: []*RateSIncrement{
|
||||
{ // cost 0,4
|
||||
IncrementStart: NewDecimal(0, 0),
|
||||
RateIntervalIndex: 0,
|
||||
RateID: "RATE0_0",
|
||||
CompressFactor: 1,
|
||||
Usage: NewDecimal(-1, 0),
|
||||
},
|
||||
{ // cost 2,4
|
||||
IncrementStart: NewDecimal(0, 0),
|
||||
RateIntervalIndex: 0,
|
||||
RateID: "RATE0_0",
|
||||
CompressFactor: 1,
|
||||
Usage: NewDecimal(int64(time.Minute), 0),
|
||||
},
|
||||
{ // cost 1,2
|
||||
IncrementStart: NewDecimal(int64(time.Minute), 0),
|
||||
RateIntervalIndex: 1,
|
||||
RateID: "RATE0_1",
|
||||
CompressFactor: 30,
|
||||
Usage: NewDecimal(int64(30*time.Second), 0),
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
{
|
||||
IntervalStart: NewDecimal(int64(90*time.Second), 0),
|
||||
Increments: []*RateSIncrement{
|
||||
{ // cost 0,2
|
||||
IncrementStart: NewDecimal(int64(90*time.Second), 0),
|
||||
RateIntervalIndex: 0,
|
||||
RateID: "RATE1_0",
|
||||
CompressFactor: 1,
|
||||
Usage: NewDecimal(-1, 0),
|
||||
},
|
||||
{ // cost 0,6
|
||||
IncrementStart: NewDecimal(int64(90*time.Second), 0),
|
||||
RateIntervalIndex: 0,
|
||||
RateID: "RATE1_0",
|
||||
CompressFactor: 30,
|
||||
Usage: NewDecimal(int64(30*time.Second), 0),
|
||||
},
|
||||
{ // cost 0,1
|
||||
IncrementStart: NewDecimal(int64(2*time.Minute), 0),
|
||||
RateIntervalIndex: 1,
|
||||
RateID: "RATE1_1",
|
||||
CompressFactor: 10,
|
||||
Usage: NewDecimal(int64(10*time.Second), 0),
|
||||
},
|
||||
},
|
||||
CompressFactor: 1,
|
||||
},
|
||||
}
|
||||
eDcml, _ := new(decimal.Big).SetFloat64(4.9).Float64()
|
||||
cost := CostForIntervals(rtIvls, rtsMap)
|
||||
if costFlt, _ := cost.Float64(); costFlt != eDcml {
|
||||
t.Errorf("eDcml: %f, received: %+v", eDcml, costFlt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRateProfileCostCorrectCost(t *testing.T) {
|
||||
rPrfCost := &RateProfileCost{
|
||||
ID: "Test1",
|
||||
@@ -1604,51 +1382,6 @@ func TestAsExtRateSIntervalErrorsCheck(t *testing.T) {
|
||||
rI.Increments[0].cost = NewDecimal(0, 0).Big
|
||||
}
|
||||
|
||||
func TestCostForIntervalsWithPartialIntervals(t *testing.T) {
|
||||
rt0 := &Rate{
|
||||
ID: "RT_2",
|
||||
IntervalRates: []*IntervalRate{
|
||||
{
|
||||
IntervalStart: NewDecimal(0, 0),
|
||||
RecurrentFee: NewDecimal(2, 2),
|
||||
Unit: NewDecimal(int64(time.Second), 0),
|
||||
Increment: NewDecimal(int64(time.Second), 0),
|
||||
},
|
||||
{
|
||||
IntervalStart: NewDecimal(int64(time.Minute), 0),
|
||||
FixedFee: NewDecimal(2, 2),
|
||||
Unit: NewDecimal(int64(time.Second), 0),
|
||||
Increment: NewDecimal(int64(time.Second), 0),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
rtsMap := map[string]*IntervalRate{
|
||||
"RT_2_0": rt0.IntervalRates[0],
|
||||
"RT_2_1": rt0.IntervalRates[1],
|
||||
}
|
||||
|
||||
rtIvls := []*RateSInterval{
|
||||
{
|
||||
IntervalStart: NewDecimal(int64(2*time.Minute), 0),
|
||||
CompressFactor: 1,
|
||||
Increments: []*RateSIncrement{
|
||||
{
|
||||
IncrementStart: NewDecimal(int64(2*time.Minute), 0),
|
||||
RateIntervalIndex: 1,
|
||||
RateID: "RT_2_1",
|
||||
CompressFactor: 1,
|
||||
Usage: NewDecimal(-1, 0),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if cost := CostForIntervals(rtIvls, rtsMap); cost.Cmp(decimal.New(2, 2)) != 0 {
|
||||
t.Errorf("received cost: %s", cost)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRateProfileCostEquals(t *testing.T) {
|
||||
rtPrfCost := &RateProfileCost{
|
||||
ID: "RATE_1",
|
||||
|
||||
Reference in New Issue
Block a user