mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
6686 lines
191 KiB
Go
6686 lines
191 KiB
Go
/*
|
|
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 attributes
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cgrates/birpc/context"
|
|
"github.com/cgrates/cgrates/config"
|
|
"github.com/cgrates/cgrates/engine"
|
|
"github.com/cgrates/cgrates/utils"
|
|
)
|
|
|
|
var (
|
|
expTimeAttributes = time.Now().Add(20 * time.Minute)
|
|
attrS *AttributeS
|
|
dmAtr *engine.DataManager
|
|
attrEvs = []*utils.CGREvent{
|
|
{ //matching AttributeProfile1
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Attribute": "AttributeProfile1",
|
|
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
|
|
"UsageInterval": "1s",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
},
|
|
{ //matching AttributeProfile2
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Attribute": "AttributeProfile2",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
},
|
|
{ //matching AttributeProfilePrefix
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Attribute": "AttributeProfilePrefix",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
},
|
|
{ //matching AttributeProfilePrefix
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"DistinctMatch": 20,
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
},
|
|
}
|
|
atrPs = []*utils.AttributeProfile{
|
|
{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "AttributeProfile1",
|
|
FilterIDs: []string{"FLTR_ATTR_1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + utils.AccountField,
|
|
Value: utils.NewRSRParsersMustCompile("1010", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "AttributeProfile2",
|
|
FilterIDs: []string{"FLTR_ATTR_2", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + utils.AccountField,
|
|
Value: utils.NewRSRParsersMustCompile("1010", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "AttributeProfilePrefix",
|
|
FilterIDs: []string{"FLTR_ATTR_3", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + utils.AccountField,
|
|
Value: utils.NewRSRParsersMustCompile("1010", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "AttributeIDMatch",
|
|
FilterIDs: []string{"*gte:~*req.DistinctMatch:20"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + utils.AccountField,
|
|
Value: utils.NewRSRParsersMustCompile("1010", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
func TestParseAtributeUsageDiffVal1(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"usage1": "20",
|
|
"usage2": "35",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUsageDifference, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.wrong;~*req.usage2", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestParseAtributeUsageDiffVal2(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"usage1": "20",
|
|
"usage2": "35",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUsageDifference, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.usage1;~*req.wrong", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeUsageDiffTimeVal1(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"usage1": "20",
|
|
"usage2": "35s",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUsageDifference, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.usage1;~*req.usage2", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "Unsupported time format"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeUsageDiffTimeVal2(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"usage1": "20s",
|
|
"usage2": "35",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUsageDifference, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.usage1;~*req.usage2", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "Unsupported time format"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeSum(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"not_valid": "field",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaSum, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.valid", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeDifference(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"not_valid": "field",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaDifference, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.valid", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeMultiply(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"not_valid": "field",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaMultiply, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.valid", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeDivide(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"not_valid": "field",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaDivide, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.valid", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeExponentVal1(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"number": "20",
|
|
"exponent": "2",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaValueExponent, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.wrong;~*req.exponent", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeExponentVal2(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"number": "20",
|
|
"exponent": "2",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaValueExponent, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.number;~*req.wrong", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeExponentWrongNumber(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"number": "not_a_number",
|
|
"exponent": "2",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaValueExponent, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.number;~*req.exponent", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "invalid value <not_a_number> to *valueExponent"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeExponentWrongExponent(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"number": "4",
|
|
"exponent": "NaN",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaValueExponent, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.number;~*req.exponent", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := `strconv.Atoi: parsing "NaN": invalid syntax`
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeUnixTimestampWrongField(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"unix_timestamp": "not_a_unix_timestamp",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUnixTimestamp, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.wrong", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeUnixTimestampWrongVal(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"unix_timestamp": "not_a_unix_timestamp",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUnixTimestamp, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.unix_timestamp", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "Unsupported time format"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributePrefixPath(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"prefix": "prfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaPrefix, "```", utils.NewRSRParsersMustCompile("~*req.prefix", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "Closed unspilit syntax"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributePrefixField(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"prefix": "prfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaPrefix, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.wrong", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeSuffixPath(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"suffix": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaSuffix, "```", utils.NewRSRParsersMustCompile("~*req.suffix", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "Closed unspilit syntax"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeSuffixField(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"suffix": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaSuffix, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.wrong", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageLessThanTwo(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "sfx",
|
|
"cc2": "sfx",
|
|
// "cc3": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.cc2", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "invalid arguments <[{\"Rules\":\"~*req.cc1\",\"Path\":\"~*req.cc1\"},{\"Rules\":\"~*req.cc2\",\"Path\":\"~*req.cc2\"}]> to *ccUsage"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("expected %q, received %q", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageField1(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "20",
|
|
"cc2": "sfx",
|
|
"cc3": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.wrong;~*req.cc2;~*req.cc3", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageVal1(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "not_valid",
|
|
"cc2": "sfx",
|
|
"cc3": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.cc2;~*req.cc3", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := `invalid requestNumber <not_valid> to *ccUsage`
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageField2(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "20",
|
|
"cc2": "sfx",
|
|
"cc3": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.wrong;~*req.cc3", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageVal2(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "20",
|
|
"cc2": "sfx",
|
|
"cc3": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.cc2;~*req.cc3", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := `invalid usedCCTime <sfx> to *ccUsage`
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageField3(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "20",
|
|
"cc2": "20",
|
|
"cc3": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.cc2;~*req.wrong", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageVal3(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "20",
|
|
"cc2": "20",
|
|
"cc3": "sfx",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.cc2;~*req.cc3", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := `invalid debitInterval <sfx> to *ccUsage`
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageNoErr(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "20",
|
|
"cc2": "20",
|
|
"cc3": "20",
|
|
},
|
|
}
|
|
out, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.cc2;~*req.cc3", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
exp := 400 * time.Nanosecond
|
|
if out.(time.Duration) != exp {
|
|
t.Errorf("Expected %v\n but received %v", exp, out)
|
|
}
|
|
}
|
|
|
|
func TestUniqueAlteredFields(t *testing.T) {
|
|
flds := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{Fields: []string{"field1"}},
|
|
},
|
|
}
|
|
exp := make(utils.StringSet)
|
|
for _, altered := range flds.AlteredFields {
|
|
exp.AddSlice(altered.Fields)
|
|
}
|
|
if rcv := flds.UniqueAlteredFields(); !reflect.DeepEqual(exp, rcv) {
|
|
t.Errorf("Expected <%+v>, Received <%+v>", exp, rcv)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProfileForEventWeightFromDynamicsErr(t *testing.T) {
|
|
|
|
defer func() {
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
}()
|
|
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
attrS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
attrIDs, err := utils.OptAsStringSlice(attrEvs[0].APIOpts, utils.OptsAttributesProfileIDs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value := utils.NewRSRParsersMustCompile("abcd123", utils.RSRSep)
|
|
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaPassword,
|
|
Value: value,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
FilterIDs: []string{"*stirng:~*req.Account:1001"},
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
attrEvs := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
Event: map[string]any{
|
|
"Attribute": "AttributeProfile1",
|
|
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
|
|
"UsageInterval": "1s",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
|
|
expErr := "NOT_IMPLEMENTED:*stirng"
|
|
_, err = attrS.attributeProfileForEvent(context.TODO(), attrEvs.Tenant,
|
|
attrIDs, utils.MapStorage{
|
|
utils.MetaReq: attrEvs.Event,
|
|
utils.MetaOpts: attrEvs.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}, utils.EmptyString, make(map[string]int), 0, false)
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributeProcessEventBlockerFromDynamicsErr(t *testing.T) {
|
|
defer func() {
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
}()
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
attrS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
value := utils.NewRSRParsersMustCompile("abcd123", utils.RSRSep)
|
|
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaPassword,
|
|
Value: value,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
FilterIDs: []string{"*stirng:~*req.Account:1001"},
|
|
Blocker: false,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
attrEvs := &utils.CGREvent{
|
|
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Attribute": "AttributeProfile1",
|
|
"Account": "1010",
|
|
utils.AnswerTime: time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC),
|
|
"UsageInterval": "1s",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: attrEvs.Event,
|
|
utils.MetaOpts: attrEvs.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
|
|
expErr := "NOT_IMPLEMENTED:*stirng"
|
|
_, err = attrS.processEvent(context.TODO(), attrEvs.Tenant, attrEvs, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributeSProcessEventPassErr(t *testing.T) {
|
|
|
|
defer func() {
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
attrS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: []string{"*apiban:~*req.<~*req.IP>{*}:*all"},
|
|
Path: "*req.Password",
|
|
Type: utils.MetaPassword,
|
|
Value: utils.NewRSRParsersMustCompile("abcd123", utils.RSRSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := dm.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"PassField": "Test",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
|
|
eNM := utils.MapStorage{
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
utils.MetaReq: utils.MapStorage{
|
|
"bannedIP": "1.2.3.251",
|
|
"bannedIP2": "1.2.3.252",
|
|
"IP": "1.2.3.253",
|
|
"IP2": "1.2.3.254",
|
|
},
|
|
}
|
|
|
|
expErr := `invalid converter value in string: <*>, err: unsupported converter definition: <*>`
|
|
_, err = attrS.processEvent(context.TODO(), attrPrf.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("Expected error %s received: %v", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributeSProcessAttrBlockerFromDynamicsErr(t *testing.T) {
|
|
defer func() {
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
attrS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Blockers: utils.DynamicBlockers{{
|
|
FilterIDs: []string{"*stirng:~*req.Account:1001"},
|
|
Blocker: false,
|
|
}},
|
|
Path: "*req.Password",
|
|
Type: utils.MetaPassword,
|
|
Value: utils.NewRSRParsersMustCompile("abcd123", utils.RSRSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := dm.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"PassField": "Test",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
|
|
expErr := "NOT_IMPLEMENTED:*stirng"
|
|
_, err = attrS.processEvent(context.TODO(), attrPrf.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("Expected error %s received: %v", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributeSProcessSubstituteRmvBlockerTrue(t *testing.T) {
|
|
defer func() {
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
attrS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaRemove,
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile(utils.MetaRemove, utils.RSRSep),
|
|
},
|
|
{
|
|
Blockers: utils.DynamicBlockers{{
|
|
Blocker: true,
|
|
}},
|
|
Path: "*req.Password",
|
|
Type: utils.MetaPassword,
|
|
Value: utils.NewRSRParsersMustCompile("abcd123", utils.RSRSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := dm.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"PassField": "Test",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVariable: utils.MetaRemove,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
|
|
exp := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{{
|
|
MatchedProfileID: "cgrates.org:ATTR_TEST",
|
|
Fields: []string{utils.MetaRemove, "*req.Password"},
|
|
}},
|
|
CGREvent: ev,
|
|
}
|
|
|
|
rcv, err := attrS.processEvent(context.TODO(), attrPrf.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(utils.ToJSON(exp), utils.ToJSON(rcv)) {
|
|
t.Errorf("Expected \n<%+v>,\n Received \n<%+v>", utils.ToJSON(exp), utils.ToJSON(rcv))
|
|
}
|
|
|
|
}
|
|
|
|
func TestV1GetAttributeForEventAttrProfEventErr(t *testing.T) {
|
|
|
|
defer func() {
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttributeProfile1",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
},
|
|
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
FilterIDs: []string{"*stirng:~*req.Account:1001"},
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Attribute": "AttributeProfile1",
|
|
},
|
|
APIOpts: map[string]any{},
|
|
}
|
|
var rply utils.APIAttributeProfile
|
|
expErr := "SERVER_ERROR: NOT_IMPLEMENTED:*stirng"
|
|
err = alS.V1GetAttributeForEvent(context.Background(), ev, &rply)
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributesV1ProcessEventFieldMissingErr(t *testing.T) {
|
|
|
|
defer func() {
|
|
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{{Blocker: false}},
|
|
Weights: utils.DynamicWeights{{Weight: 20}},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
"testfield": utils.MetaAttributes,
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
var rply AttrSProcessEventReply
|
|
expErr := "MANDATORY_IE_MISSING: [testfield]"
|
|
err = alS.V1ProcessEvent(context.Background(), ev, &rply)
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("Expected error <%+v>, received error <%+v>", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestParseAtributeUsageDiffDetectLayoutErr2(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"UnixTimeStamp": "1554364297",
|
|
"usage2": "35",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUsageDifference, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.UnixTimeStamp;~*req.usage2", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
errExp := "Unsupported time format"
|
|
if err == nil || err.Error() != errExp {
|
|
t.Errorf("Expected %v\n but received %v", errExp, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeMetaPrefixParseDPErr(t *testing.T) {
|
|
dp := utils.MapStorage{}
|
|
|
|
_, err := ParseAttribute(dp, utils.MetaPrefix, "constant;`>;q=0.7;expires=3600`;~*req.Account", utils.NewRSRParsersMustCompile("~*req.UnixTimeStamp;~*req.usage2", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeMetaSuffixParseDPErr(t *testing.T) {
|
|
dp := utils.MapStorage{}
|
|
|
|
_, err := ParseAttribute(dp, utils.MetaSuffix, "constant;`>;q=0.7;expires=3600`;~*req.Account", utils.NewRSRParsersMustCompile("~*req.UnixTimeStamp;~*req.usage2", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err != utils.ErrNotFound {
|
|
t.Errorf("Expected %v\n but received %v", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestParseAtributeCCUsageNegativeReqNr(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cc1": "-1",
|
|
"cc2": "-20",
|
|
"cc3": "-20",
|
|
},
|
|
}
|
|
out, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cc1;~*req.cc2;~*req.cc3", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
exp := -20 * time.Nanosecond
|
|
if out.(time.Duration) != exp {
|
|
t.Errorf("Expected %v\n but received %v", exp, out)
|
|
}
|
|
}
|
|
func TestAttributeFromHTTP(t *testing.T) {
|
|
exp := "Account"
|
|
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
fmt.Fprint(w, exp)
|
|
|
|
}))
|
|
|
|
defer testServer.Close()
|
|
attrType := utils.MetaHTTP + utils.HashtagSep + utils.IdxStart + testServer.URL + utils.IdxEnd
|
|
|
|
attrID := attrType + ":*req.Category:*attributes"
|
|
expAttrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: attrType + ":*req.Category:*attributes",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Category",
|
|
Type: attrType,
|
|
Value: utils.NewRSRParsersMustCompile("*attributes", utils.InfieldSep),
|
|
},
|
|
},
|
|
}
|
|
attrPrf, err := utils.NewAttributeFromInline(config.CgrConfig().GeneralCfg().DefaultTenant, attrID)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expAttrPrf1, attrPrf) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(expAttrPrf1), utils.ToJSON(attrPrf))
|
|
}
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{},
|
|
}
|
|
|
|
attr := attrPrf.Attributes[0]
|
|
if out, err := ParseAttribute(dp, attr.Type, attr.Path, attr.Value,
|
|
0, utils.EmptyString, utils.EmptyString); err != nil {
|
|
t.Fatal(err)
|
|
} else if exp != out {
|
|
t.Errorf("Expected %q, Received %q", exp, out)
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1GetAttributeForEventProfileIgnoreOpts(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
aA := NewAttributeService(dm, filterS, cfg)
|
|
cfg.AttributeSCfg().Opts.ProfileIgnoreFilters = []*config.DynamicBoolOpt{
|
|
config.NewDynamicBoolOpt(nil, "", true, nil),
|
|
}
|
|
acPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AC1",
|
|
FilterIDs: []string{"*string:~*req.Attribute:testAttrValue"},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
if err := dm.SetAttributeProfile(context.Background(), acPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent1",
|
|
Event: map[string]any{
|
|
"Attribute": "testAttrValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
utils.OptsAttributesProfileIDs: []string{"AC1"},
|
|
utils.MetaProfileIgnoreFilters: false,
|
|
},
|
|
}
|
|
rply := &utils.APIAttributeProfile{}
|
|
expected := &utils.APIAttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AC1",
|
|
FilterIDs: []string{"*string:~*req.Attribute:testAttrValue"},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
Attributes: []*utils.ExternalAttribute{},
|
|
}
|
|
|
|
err = aA.V1GetAttributeForEvent(context.Background(), ev, rply)
|
|
if err != nil {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
|
|
}
|
|
if !reflect.DeepEqual(expected, rply) {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expected), utils.ToJSON(rply))
|
|
}
|
|
// correct filter but ignore filters opt on false
|
|
ev2 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent2",
|
|
Event: map[string]any{
|
|
"Attribute": "testAttrValue2",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
utils.OptsAttributesProfileIDs: []string{"AC1"},
|
|
utils.MetaProfileIgnoreFilters: true,
|
|
},
|
|
}
|
|
rply2 := &utils.APIAttributeProfile{}
|
|
expected2 := &utils.APIAttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AC1",
|
|
FilterIDs: []string{"*string:~*req.Attribute:testAttrValue"},
|
|
Attributes: []*utils.ExternalAttribute{},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// with ignore filters on true and with bad filter
|
|
err = aA.V1GetAttributeForEvent(context.Background(), ev2, rply2)
|
|
if err != nil {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
|
|
}
|
|
if !reflect.DeepEqual(expected2, rply2) {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expected2), utils.ToJSON(rply2))
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1GetAttributeForEventErr(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
var ev utils.CGREvent
|
|
rply := &utils.APIAttributeProfile{}
|
|
err = alS.V1GetAttributeForEvent(context.Background(), &ev, rply)
|
|
if err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ErrNotFound, err)
|
|
}
|
|
|
|
}
|
|
func TestAttributePopulateAttrService(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().StringIndexedFields = nil
|
|
cfg.AttributeSCfg().PrefixIndexedFields = nil
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
}
|
|
|
|
func TestAttributeAddFilters(t *testing.T) {
|
|
fltrAttr1 := &engine.Filter{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "FLTR_ATTR_1",
|
|
Rules: []*engine.FilterRule{
|
|
{
|
|
Type: utils.MetaString,
|
|
Element: "~*req.Attribute",
|
|
Values: []string{"AttributeProfile1"},
|
|
},
|
|
{
|
|
Type: utils.MetaGreaterOrEqual,
|
|
Element: "~*req.UsageInterval",
|
|
Values: []string{time.Second.String()},
|
|
},
|
|
{
|
|
Type: utils.MetaGreaterOrEqual,
|
|
Element: "~*req." + utils.Weight,
|
|
Values: []string{"9.0"},
|
|
},
|
|
},
|
|
}
|
|
dmAtr.SetFilter(context.Background(), fltrAttr1, true)
|
|
fltrAttr2 := &engine.Filter{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "FLTR_ATTR_2",
|
|
Rules: []*engine.FilterRule{
|
|
{
|
|
Type: utils.MetaString,
|
|
Element: "~*req.Attribute",
|
|
Values: []string{"AttributeProfile2"},
|
|
},
|
|
},
|
|
}
|
|
dmAtr.SetFilter(context.Background(), fltrAttr2, true)
|
|
fltrAttrPrefix := &engine.Filter{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "FLTR_ATTR_3",
|
|
Rules: []*engine.FilterRule{
|
|
{
|
|
Type: utils.MetaPrefix,
|
|
Element: "~*req.Attribute",
|
|
Values: []string{"AttributeProfilePrefix"},
|
|
},
|
|
},
|
|
}
|
|
dmAtr.SetFilter(context.Background(), fltrAttrPrefix, true)
|
|
fltrAttr4 := &engine.Filter{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "FLTR_ATTR_4",
|
|
Rules: []*engine.FilterRule{
|
|
{
|
|
Type: utils.MetaGreaterOrEqual,
|
|
Element: "~*req." + utils.Weight,
|
|
Values: []string{"200.00"},
|
|
},
|
|
},
|
|
}
|
|
dmAtr.SetFilter(context.Background(), fltrAttr4, true)
|
|
}
|
|
|
|
func TestAttributeCache(t *testing.T) {
|
|
for _, atr := range atrPs {
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), atr, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
}
|
|
//verify each attribute from cache
|
|
for _, atr := range atrPs {
|
|
if tempAttr, err := dmAtr.GetAttributeProfile(context.TODO(), atr.Tenant, atr.ID,
|
|
true, false, utils.NonTransactional); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
} else if !reflect.DeepEqual(atr, tempAttr) {
|
|
t.Errorf("Expecting: %+v, received: %+v", atr, tempAttr)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAttributeProfileForEvent(t *testing.T) {
|
|
attrIDs, err := utils.OptAsStringSlice(attrEvs[0].APIOpts, utils.OptsAttributesProfileIDs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
atrp, err := attrS.attributeProfileForEvent(context.TODO(), attrEvs[0].Tenant,
|
|
attrIDs, utils.MapStorage{
|
|
utils.MetaReq: attrEvs[0].Event,
|
|
utils.MetaOpts: attrEvs[0].APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}, utils.EmptyString, make(map[string]int), 0, false)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(atrPs[0], atrp) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(atrPs[0]), utils.ToJSON(atrp))
|
|
}
|
|
|
|
attrIDs, err = utils.OptAsStringSlice(attrEvs[1].APIOpts, utils.OptsAttributesProfileIDs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
atrp, err = attrS.attributeProfileForEvent(context.TODO(), attrEvs[1].Tenant,
|
|
attrIDs, utils.MapStorage{
|
|
utils.MetaReq: attrEvs[1].Event,
|
|
utils.MetaOpts: attrEvs[1].APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}, utils.EmptyString, make(map[string]int), 0, false)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(atrPs[1], atrp) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(atrPs[1]), utils.ToJSON(atrp))
|
|
}
|
|
|
|
attrIDs, err = utils.OptAsStringSlice(attrEvs[2].APIOpts, utils.OptsAttributesProfileIDs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
atrp, err = attrS.attributeProfileForEvent(context.TODO(), attrEvs[2].Tenant,
|
|
attrIDs, utils.MapStorage{
|
|
utils.MetaReq: attrEvs[2].Event,
|
|
utils.MetaOpts: attrEvs[2].APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}, utils.EmptyString, make(map[string]int), 0, false)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(atrPs[2], atrp) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(atrPs[2]), utils.ToJSON(atrp))
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEvent(t *testing.T) {
|
|
attrEvs[0].Event["Account"] = "1010" //Field added in event after process
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{{
|
|
MatchedProfileID: "cgrates.org:AttributeProfile1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Account"},
|
|
}},
|
|
CGREvent: attrEvs[0],
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: attrEvs[0].Event,
|
|
utils.MetaOpts: attrEvs[0].APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
atrp, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[0], eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply, atrp) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(atrp))
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventWithNotFound(t *testing.T) {
|
|
attrEvs[3].Event["Account"] = "1010" //Field added in event after process
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: attrEvs[3].Event,
|
|
utils.MetaOpts: attrEvs[3].APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
if _, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[3], eNM,
|
|
engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0); err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventWithIDs(t *testing.T) {
|
|
attrEvs[3].Event["Account"] = "1010" //Field added in event after process
|
|
attrEvs[3].APIOpts[utils.OptsAttributesProfileIDs] = []string{"AttributeIDMatch"}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{{
|
|
MatchedProfileID: "cgrates.org:AttributeIDMatch",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Account"},
|
|
}},
|
|
CGREvent: attrEvs[3],
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: attrEvs[3].Event,
|
|
utils.MetaOpts: attrEvs[3].APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
if atrp, err := attrS.processEvent(context.TODO(), attrEvs[0].Tenant, attrEvs[3], eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0); err != nil {
|
|
} else if !reflect.DeepEqual(eRply, atrp) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(atrp))
|
|
}
|
|
}
|
|
|
|
func TestAttributeEventReplyDigest(t *testing.T) {
|
|
eRpl := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.AccountField, utils.Subject},
|
|
}},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "testAttributeSProcessEvent",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1001",
|
|
utils.Subject: "1001",
|
|
},
|
|
},
|
|
}
|
|
expRpl := "Account:1001,Subject:1001"
|
|
val := eRpl.Digest()
|
|
if !reflect.DeepEqual(val, expRpl) {
|
|
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expRpl), utils.ToJSON(val))
|
|
}
|
|
}
|
|
|
|
func TestAttributeEventReplyDigest2(t *testing.T) {
|
|
eRpl := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{},
|
|
}},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "testAttributeSProcessEvent",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1001",
|
|
utils.Subject: "1001",
|
|
},
|
|
},
|
|
}
|
|
expRpl := ""
|
|
val := eRpl.Digest()
|
|
if !reflect.DeepEqual(val, expRpl) {
|
|
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expRpl), utils.ToJSON(val))
|
|
}
|
|
}
|
|
|
|
func TestAttributeEventReplyDigest3(t *testing.T) {
|
|
eRpl := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{"*req.Subject"},
|
|
}},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "testAttributeSProcessEvent",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1001",
|
|
utils.Subject: "1001",
|
|
},
|
|
},
|
|
}
|
|
expRpl := "Subject:1001"
|
|
val := eRpl.Digest()
|
|
if !reflect.DeepEqual(val, expRpl) {
|
|
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expRpl), utils.ToJSON(val))
|
|
}
|
|
}
|
|
|
|
func TestAttributeEventReplyDigest4(t *testing.T) {
|
|
eRpl := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{"*req.Subject"},
|
|
}},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "testAttributeSProcessEvent",
|
|
Event: map[string]any{
|
|
utils.AccountField: "1001",
|
|
},
|
|
},
|
|
}
|
|
expRpl := ""
|
|
val := eRpl.Digest()
|
|
if !reflect.DeepEqual(val, expRpl) {
|
|
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expRpl), utils.ToJSON(val))
|
|
}
|
|
}
|
|
|
|
func TestAttributeIndexer(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
expTimeStr := expTimeAttributes.Format("2006-01-02T15-04-05Z")
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrPrf",
|
|
FilterIDs: []string{"*string:~*req.Account:1007", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z|" + expTimeStr},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + utils.AccountField,
|
|
Value: utils.NewRSRParsersMustCompile("1010", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
eIdxes := map[string]utils.StringSet{
|
|
"*string:*req.Account:1007": {
|
|
"AttrPrf": struct{}{},
|
|
},
|
|
}
|
|
if rcvIdx, err := dmAtr.GetIndexes(context.TODO(), utils.CacheAttributeFilterIndexes,
|
|
attrPrf.Tenant, "", utils.NonTransactional, false, false); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
if !reflect.DeepEqual(eIdxes, rcvIdx) {
|
|
t.Errorf("Expecting %+v, received: %+v", eIdxes, rcvIdx)
|
|
}
|
|
}
|
|
//Set AttributeProfile with new context (*sessions)
|
|
cpAttrPrf := new(utils.AttributeProfile)
|
|
*cpAttrPrf = *attrPrf
|
|
cpAttrPrf.FilterIDs = append(attrPrf.FilterIDs, "*string:~*opts.*context:*sessions")
|
|
eIdxes["*string:*opts.*context:*sessions"] = utils.StringSet{
|
|
"AttrPrf": {},
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), cpAttrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if rcvIdx, err := dmAtr.GetIndexes(context.TODO(), utils.CacheAttributeFilterIndexes,
|
|
attrPrf.Tenant, "", utils.NonTransactional, false, false); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(eIdxes, rcvIdx) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx))
|
|
}
|
|
|
|
expected := map[string]utils.StringSet{
|
|
"*string:*opts.*context:*sessions": {
|
|
"AttrPrf": {},
|
|
},
|
|
"*string:*req.Account:1007": {
|
|
"AttrPrf": {},
|
|
},
|
|
}
|
|
//verify if old index was deleted ( context *any)
|
|
if rcv, err := dmAtr.GetIndexes(context.TODO(), utils.CacheAttributeFilterIndexes,
|
|
attrPrf.Tenant, "", utils.NonTransactional, false, false); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(rcv, expected) {
|
|
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", expected, rcv)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessWithMultipleRuns1(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.InitialField:InitialValue", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
attrPrf3 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_3",
|
|
FilterIDs: []string{"*string:~*req.Field2:Value2", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field3",
|
|
Value: utils.NewRSRParsersMustCompile("Value3", utils.InfieldSep),
|
|
},
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Destination",
|
|
Value: utils.NewRSRParsersMustCompile("2044", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf3, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 3,
|
|
},
|
|
}
|
|
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
eRply := AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_3",
|
|
Fields: []string{
|
|
utils.MetaReq + utils.NestingSep + "Field3",
|
|
utils.MetaReq + utils.NestingSep + "Destination"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: reply.CGREvent.ID,
|
|
Event: map[string]any{
|
|
utils.Destination: "2044",
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
"Field3": "Value3",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 3,
|
|
},
|
|
},
|
|
blocker: false,
|
|
}
|
|
if !reflect.DeepEqual(eRply, reply) {
|
|
t.Fatalf("Expecting %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessWithMultipleRuns2(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.InitialField:InitialValue", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
attrPrf3 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_3",
|
|
FilterIDs: []string{"*string:~*req.NotFound:NotFound", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field3",
|
|
Value: utils.NewRSRParsersMustCompile("Value3", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf3, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessWithMultipleRuns3(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.InitialField:InitialValue", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
attrPrf3 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_3",
|
|
FilterIDs: []string{"*string:~*req.Field2:Value2", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field3",
|
|
Value: utils.NewRSRParsersMustCompile("Value3", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf3, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
for idx, altered := range eRply.AlteredFields {
|
|
if altered.MatchedProfileID != reply.AlteredFields[idx].MatchedProfileID {
|
|
t.Errorf("Expecting %+v, received: %+v", altered.MatchedProfileID, reply.AlteredFields[idx].MatchedProfileID)
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessWithMultipleRuns4(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.InitialField:InitialValue", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeMultipleProcessWithBlocker(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
return
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.InitialField:InitialValue", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
attrPrf3 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_3",
|
|
FilterIDs: []string{"*string:~*req.Field2:Value2", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field3",
|
|
Value: utils.NewRSRParsersMustCompile("Value3", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf3, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eRply.AlteredFields), utils.ToJSON(reply.AlteredFields))
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeMultipleProcessWithBlocker2(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.InitialField:InitialValue", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
attrPrf3 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_3",
|
|
FilterIDs: []string{"*string:~*req.Field2:Value2", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field3",
|
|
Value: utils.NewRSRParsersMustCompile("Value3", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf3, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessValue(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Field1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"Field2": "Value1",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeAttributeFilterIDs(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: []string{"*string:~*req.PassField:Test"},
|
|
Path: utils.MetaReq + utils.NestingSep + "PassField",
|
|
Value: utils.NewRSRParsersMustCompile("Pass", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: []string{"*string:~*req.PassField:RandomValue"},
|
|
Path: utils.MetaReq + utils.NestingSep + "NotPassField",
|
|
Value: utils.NewRSRParsersMustCompile("NotPass", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: []string{"*notexists:~*req.RandomField:"},
|
|
Path: utils.MetaReq + utils.NestingSep + "RandomField",
|
|
Value: utils.NewRSRParsersMustCompile("RandomValue", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"PassField": "Test",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "PassField",
|
|
utils.MetaReq + utils.NestingSep + "RandomField"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"PassField": "Pass",
|
|
"RandomField": "RandomValue",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventConstant(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("ConstVal", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"Field2": "ConstVal",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eRply.AlteredFields), utils.ToJSON(reply.AlteredFields))
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventVariable(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Field1", utils.InfieldSep),
|
|
},
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.TheField", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"Field2": "TheVal",
|
|
"TheField": "TheVal",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventComposed(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaComposed,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Field1", utils.InfieldSep),
|
|
},
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaComposed,
|
|
Value: utils.NewRSRParsersMustCompile("_", utils.InfieldSep),
|
|
},
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaComposed,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.TheField", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"Field2": "Value1_TheVal",
|
|
"TheField": "TheVal",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Fatalf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventSum(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaSum,
|
|
Value: utils.NewRSRParsersMustCompile("10;~*req.NumField;20", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
"NumField": "20",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
"NumField": "20",
|
|
"Field2": "50",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventUsageDifference(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaUsageDifference,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.UnixTimeStamp;~*req.UnixTimeStamp2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
"UnixTimeStamp": "1554364297",
|
|
"UnixTimeStamp2": "1554364287",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
"UnixTimeStamp": "1554364297",
|
|
"UnixTimeStamp2": "1554364287",
|
|
"Field2": "10s",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeProcessEventValueExponent(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaValueExponent,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Multiplier;~*req.Pow", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
"Multiplier": "2",
|
|
"Pow": "3",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
"TheField": "TheVal",
|
|
"Multiplier": "2",
|
|
"Pow": "3",
|
|
"Field2": "2000",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func BenchmarkAttributeProcessEventConstant(b *testing.B) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
b.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
b.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
b.Error(err)
|
|
} else if test != true {
|
|
b.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("ConstVal", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
b.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
b.Errorf("Error: %+v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkAttributeProcessEventVariable(b *testing.B) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
b.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
b.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
b.Error(err)
|
|
} else if test != true {
|
|
b.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Value1", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Field1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: true,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1, true); err != nil {
|
|
b.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Field1": "Value1",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
b.Errorf("Error: %+v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetAttributeProfileFromInline(t *testing.T) {
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
engine.Cache.Clear(nil)
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
attrID := "*sum:*req.Field2:10&~*req.NumField&20"
|
|
expAttrPrf1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: attrID,
|
|
Attributes: []*utils.Attribute{{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaSum,
|
|
Value: utils.NewRSRParsersMustCompile("10;~*req.NumField;20", utils.InfieldSep),
|
|
}},
|
|
}
|
|
cfg := config.NewDefaultCGRConfig()
|
|
attr, err := engine.NewDataManager(nil, cfg, nil).GetAttributeProfile(context.TODO(), config.CgrConfig().GeneralCfg().DefaultTenant, attrID, false, false, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expAttrPrf1, attr) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(expAttrPrf1), utils.ToJSON(attr))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeConstant(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_CONSTANT",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("Val2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_CONSTANT
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeConstant",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
ev.Event["Field2"] = "Val2"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_CONSTANT",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: ev,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeVariable(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_VARIABLE",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_VARIABLE
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeVariable",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "Val2",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "Val2"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_VARIABLE",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeComposed(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_COMPOSED",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaComposed,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField", utils.InfieldSep),
|
|
},
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaComposed,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_COMPOSED
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeComposed",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "Val2",
|
|
"RandomField2": "Concatenated",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "Val2Concatenated"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_COMPOSED",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeUsageDifference(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_USAGE_DIFF",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaUsageDifference,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField;~*req.RandomField2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_USAGE_DIFF
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeUsageDifference",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1514808000",
|
|
"RandomField2": "1514804400",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "1h0m0s"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_USAGE_DIFF",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeSum(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_SUM",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaSum,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField;~*req.RandomField2;10", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_SUM
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeSum",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1",
|
|
"RandomField2": "5",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "16"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_SUM",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeDiff(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_DIFF",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaDifference,
|
|
Value: utils.NewRSRParsersMustCompile("55;~*req.RandomField;~*req.RandomField2;10", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_DIFF
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeDiff",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1",
|
|
"RandomField2": "5",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "39"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_DIFF",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeMultiply(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_MULTIPLY",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaMultiply,
|
|
Value: utils.NewRSRParsersMustCompile("55;~*req.RandomField;~*req.RandomField2;10", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_MULTIPLY
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeMultiply",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1",
|
|
"RandomField2": "5",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "2750"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_MULTIPLY",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeDivide(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_DIVIDE",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaDivide,
|
|
Value: utils.NewRSRParsersMustCompile("55.0;~*req.RandomField;~*req.RandomField2;4", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_DIVIDE
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeDivide",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1",
|
|
"RandomField2": "5",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "2.75"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_DIVIDE",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeValueExponent(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_VAL_EXP",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaValueExponent,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField2;4", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_VAL_EXP
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeValueExponent",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1",
|
|
"RandomField2": "5",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "50000"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_VAL_EXP",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeUnixTimeStamp(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_UNIX_TIMESTAMP",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaUnixTimestamp,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_UNIX_TIMESTAMP
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeUnixTimeStamp",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1",
|
|
"RandomField2": "2013-12-30T15:00:01Z",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "1388415601"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_UNIX_TIMESTAMP",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributePrefix(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_PREFIX",
|
|
FilterIDs: []string{"*string:~*req.ATTR:ATTR_PREFIX", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaPrefix,
|
|
Value: utils.NewRSRParsersMustCompile("abc_", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_VAL_EXP
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeValueExponent",
|
|
Event: map[string]any{
|
|
"ATTR": "ATTR_PREFIX",
|
|
"Field2": "Val2",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "abc_Val2"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_PREFIX",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestProcessAttributeSuffix(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_SUFFIX",
|
|
FilterIDs: []string{"*string:~*req.ATTR:ATTR_SUFFIX", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaSuffix,
|
|
Value: utils.NewRSRParsersMustCompile("_abc", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_VAL_EXP
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeValueExponent",
|
|
Event: map[string]any{
|
|
"ATTR": "ATTR_SUFFIX",
|
|
"Field2": "Val2",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: ev.Event,
|
|
utils.MetaOpts: ev.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
rcv, err := attrS.processEvent(context.TODO(), ev.Tenant, ev, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "Val2_abc"
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_SUFFIX",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestAttributeIndexSelectsFalse(t *testing.T) {
|
|
// change the IndexedSelects to false
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().StringIndexedFields = nil
|
|
cfg.AttributeSCfg().PrefixIndexedFields = nil
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
|
|
//refresh the DM
|
|
if err := dmAtr.DataDB().Flush(""); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
|
t.Error(err)
|
|
} else if test != true {
|
|
t.Errorf("Expecting: true got :%+v", test)
|
|
}
|
|
expTimeStr := expTimeAttributes.Format("2006-01-02T15:04:05Z")
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrPrf",
|
|
FilterIDs: []string{"*string:~*req.Account:1007", "*ai:~*req.AnswerTime:2014-07-14T14:35:00Z|" + expTimeStr, "*string:~*opts.*context:*cdrs"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + utils.AccountField,
|
|
Value: utils.NewRSRParsersMustCompile("1010", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"Account": "1007",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err == nil || err != utils.ErrNotFound {
|
|
t.Errorf("Expected not found, reveiced: %+v", err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestProcessAttributeWithSameWeight(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Field1:Val1", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field3",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("~*req.RandomField", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{ //matching ATTR_UNIX_TIMESTAMP
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "TestProcessAttributeUnixTimeStamp",
|
|
Event: map[string]any{
|
|
"Field1": "Val1",
|
|
"RandomField": "1",
|
|
utils.Weight: "20.0",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
var rcv AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &rcv); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
clnEv := ev.Clone()
|
|
clnEv.Event["Field2"] = "1"
|
|
clnEv.Event["Field3"] = "1"
|
|
eRply := AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field3"},
|
|
},
|
|
},
|
|
CGREvent: clnEv,
|
|
}
|
|
sort.Slice(rcv.AlteredFields, func(i, j int) bool {
|
|
return rcv.AlteredFields[i].MatchedProfileID < rcv.AlteredFields[j].MatchedProfileID
|
|
})
|
|
if !reflect.DeepEqual(eRply, rcv) {
|
|
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestAttributeMultipleProcessWithFiltersExists(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf1Exists := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1_EXISTS",
|
|
FilterIDs: []string{"*exists:~*req.InitialField:", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2Exists := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2_EXISTS",
|
|
FilterIDs: []string{"*exists:~*req.Field1:", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1Exists, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2Exists, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
// Add attribute in DM
|
|
if _, err := dmAtr.GetAttributeProfile(context.TODO(), attrPrf1Exists.Tenant, attrPrf1Exists.ID, true, false, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if _, err := dmAtr.GetAttributeProfile(context.TODO(), attrPrf2Exists.Tenant, attrPrf2Exists.ID, true, false, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1_EXISTS",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2_EXISTS",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1_EXISTS",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2_EXISTS",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeMultipleProcessWithFiltersNotEmpty(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dmAtr = engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dmAtr)
|
|
attrS = NewAttributeService(dmAtr, fltrs, cfg)
|
|
attrPrf1NotEmpty := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1_NOTEMPTY",
|
|
FilterIDs: []string{"*notempty:~*req.InitialField:", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2NotEmpty := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2_NOTEMPTY",
|
|
FilterIDs: []string{"*notempty:~*req.Field1:", "*ai:*now:2014-07-14T14:25:00Z", "*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf1NotEmpty, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dmAtr.SetAttributeProfile(context.TODO(), attrPrf2NotEmpty, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
// Add attribute in DM
|
|
if _, err := dmAtr.GetAttributeProfile(context.TODO(), attrPrf1NotEmpty.Tenant, attrPrf1NotEmpty.ID, true, false, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if _, err := dmAtr.GetAttributeProfile(context.TODO(), attrPrf2NotEmpty.Tenant, attrPrf2NotEmpty.ID, true, false, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
},
|
|
}
|
|
eRply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1_NOTEMPTY",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2_NOTEMPTY",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1_NOTEMPTY",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2_NOTEMPTY",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
|
}
|
|
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
|
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
|
}
|
|
}
|
|
|
|
func TestAttributeMetaTenant(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
idb, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(idb, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dm)
|
|
attrS = NewAttributeService(dm, fltrs, cfg)
|
|
attr1 := &utils.AttributeProfile{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_TNT",
|
|
FilterIDs: []string{"*string:~*opts.*context:*sessions"},
|
|
Attributes: []*utils.Attribute{{
|
|
Type: utils.MetaPrefix,
|
|
Path: utils.MetaTenant,
|
|
Value: utils.NewRSRParsersMustCompile("prfx_", utils.InfieldSep),
|
|
}},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
|
|
// Add attribute in DM
|
|
if err := dm.SetAttributeProfile(context.TODO(), attr1, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if _, err := dm.GetAttributeProfile(context.TODO(), attr1.Tenant, attr1.ID, true, false, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
Event: map[string]any{},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
}
|
|
eRply := AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_TNT",
|
|
Fields: []string{utils.MetaTenant},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "prfx_" + config.CgrConfig().GeneralCfg().DefaultTenant,
|
|
Event: map[string]any{},
|
|
APIOpts: map[string]any{
|
|
utils.OptsContext: utils.MetaSessionS,
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !reflect.DeepEqual(eRply, reply) {
|
|
t.Errorf("Expecting %s, received: %s", utils.ToJSON(eRply), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func TestAttributesPorcessEventMatchingProcessRuns(t *testing.T) {
|
|
engine.Cache.Clear(nil)
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().Enabled = true
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, nil)
|
|
fltrS := engine.NewFilterS(cfg, nil, dm)
|
|
fltr := &engine.Filter{
|
|
Tenant: "cgrates.org",
|
|
ID: "Process_Runs_Fltr",
|
|
Rules: []*engine.FilterRule{
|
|
{
|
|
Type: utils.MetaGreaterThan,
|
|
Element: "~*vars.*processRuns",
|
|
Values: []string{"1"},
|
|
},
|
|
},
|
|
}
|
|
if err := dm.SetFilter(context.Background(), fltr, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attrPfr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_ProcessRuns",
|
|
FilterIDs: []string{"Process_Runs_Fltr"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.CompanyName",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("ITSYS COMMUNICATIONS SRL", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
// this I'll match first, no fltr and processRuns will be 1
|
|
attrPfr2 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_MatchSecond",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaVariable,
|
|
Value: utils.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep),
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
|
|
attrPfr.Compile()
|
|
fltr.Compile()
|
|
attrPfr2.Compile()
|
|
if err := dm.SetAttributeProfile(context.Background(), attrPfr, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dm.SetAttributeProfile(context.Background(), attrPfr2, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr := NewAttributeService(dm, fltrS, cfg)
|
|
|
|
ev := &utils.CGREvent{
|
|
Event: map[string]any{
|
|
"Account": "pc_test",
|
|
"CompanyName": "MY_company_will_be_changed",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
reply := &AttrSProcessEventReply{}
|
|
expReply := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_MatchSecond",
|
|
Fields: []string{"*req.Password"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_ProcessRuns",
|
|
Fields: []string{"*req.CompanyName"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
Event: map[string]any{
|
|
"Account": "pc_test",
|
|
"CompanyName": "ITSYS COMMUNICATIONS SRL",
|
|
"Password": "CGRateS.org",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
},
|
|
}
|
|
if err := attr.V1ProcessEvent(context.Background(), ev, reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(expReply, reply) {
|
|
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expReply), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func TestAttributeMultipleProfileRunns(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
idb, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(idb, cfg, nil)
|
|
engine.Cache.Clear(nil)
|
|
fltrs := engine.NewFilterS(cfg, nil, dm)
|
|
attrS = NewAttributeService(dm, fltrs, cfg)
|
|
attrPrf1Exists := &utils.AttributeProfile{
|
|
Tenant: cfg.GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{},
|
|
Attributes: []*utils.Attribute{{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field1",
|
|
Value: utils.NewRSRParsersMustCompile("Value1", utils.InfieldSep),
|
|
}},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
attrPrf2Exists := &utils.AttributeProfile{
|
|
Tenant: cfg.GeneralCfg().DefaultTenant,
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{},
|
|
Attributes: []*utils.Attribute{{
|
|
Path: utils.MetaReq + utils.NestingSep + "Field2",
|
|
Value: utils.NewRSRParsersMustCompile("Value2", utils.InfieldSep),
|
|
}},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 5,
|
|
},
|
|
},
|
|
}
|
|
// Add attribute in DM
|
|
if err := dm.SetAttributeProfile(context.TODO(), attrPrf1Exists, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := dm.SetAttributeProfile(context.TODO(), attrPrf2Exists, true); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
// Add attribute in DM
|
|
if _, err := dm.GetAttributeProfile(context.TODO(), attrPrf1Exists.Tenant, attrPrf1Exists.ID, true, false, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if _, err := dm.GetAttributeProfile(context.TODO(), attrPrf2Exists.Tenant, attrPrf2Exists.ID, true, false, utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
}
|
|
ev := &utils.CGREvent{
|
|
Tenant: cfg.GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileRuns: 2,
|
|
utils.OptsAttributesProcessRuns: 40,
|
|
},
|
|
}
|
|
eRply := AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: cfg.GeneralCfg().DefaultTenant,
|
|
ID: ev.ID,
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileRuns: 2,
|
|
utils.OptsAttributesProcessRuns: 40,
|
|
},
|
|
},
|
|
}
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply, reply) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(reply))
|
|
}
|
|
|
|
ev = &utils.CGREvent{
|
|
Tenant: cfg.GeneralCfg().DefaultTenant,
|
|
ID: utils.GenUUID(),
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileRuns: 1,
|
|
utils.OptsAttributesProcessRuns: 40,
|
|
},
|
|
}
|
|
eRply = AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_1",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field1"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_2",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Field2"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: cfg.GeneralCfg().DefaultTenant,
|
|
ID: ev.ID,
|
|
Event: map[string]any{
|
|
"InitialField": "InitialValue",
|
|
"Field1": "Value1",
|
|
"Field2": "Value2",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileRuns: 1,
|
|
utils.OptsAttributesProcessRuns: 40,
|
|
},
|
|
},
|
|
}
|
|
reply = AttrSProcessEventReply{}
|
|
if err := attrS.V1ProcessEvent(context.TODO(), ev, &reply); err != nil {
|
|
t.Errorf("Error: %+v", err)
|
|
}
|
|
if !reflect.DeepEqual(eRply, reply) {
|
|
t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eRply), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1ProcessEvent(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "adrian@itsyscom.com",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
rply := &AttrSProcessEventReply{}
|
|
expected := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_CHANGE_TENANT_FROM_USER",
|
|
Fields: []string{utils.MetaReq + utils.NestingSep + "Account",
|
|
"*tenant"},
|
|
},
|
|
{
|
|
MatchedProfileID: "adrian.itsyscom.com.co.uk:ATTR_MATCH_TENANT",
|
|
Fields: []string{"*req.Password"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "andrei.itsyscom.com",
|
|
"Password": "CGRATES.ORG",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
},
|
|
blocker: false,
|
|
}
|
|
err = alS.V1ProcessEvent(context.Background(), ev, rply)
|
|
if err != nil {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
|
|
}
|
|
if sort.Slice(rply.AlteredFields[0].Fields, func(i, j int) bool {
|
|
return rply.AlteredFields[0].Fields[i] < rply.AlteredFields[0].Fields[j]
|
|
}); !reflect.DeepEqual(expected, rply) {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expected), utils.ToJSON(rply))
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1ProcessEventErrorMetaSum(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
engine.Cache.Clear(nil)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaSum,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "adrian@itsyscom.com",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
rply := &AttrSProcessEventReply{}
|
|
err = alS.V1ProcessEvent(context.Background(), ev, rply)
|
|
expErr := "SERVER_ERROR: NotEnoughParameters"
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributesV1ProcessEventErrorMetaDifference(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaDifference,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "adrian@itsyscom.com",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
rply := &AttrSProcessEventReply{}
|
|
err = alS.V1ProcessEvent(context.Background(), ev, rply)
|
|
expErr := "SERVER_ERROR: NotEnoughParameters"
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributesV1ProcessEventErrorMetaValueExponent(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
engine.Cache.Clear(nil)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaValueExponent,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "adrian@itsyscom.com",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
rply := &AttrSProcessEventReply{}
|
|
err = alS.V1ProcessEvent(context.Background(), ev, rply)
|
|
expErr := "SERVER_ERROR: invalid arguments <[{\"Rules\":\"CGRATES.ORG\",\"Path\":\"CGRATES.ORG\"}]> to *valueExponent"
|
|
if err == nil || err.Error() != expErr {
|
|
t.Errorf("expected %q, received %q", expErr, err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributesattributeProfileForEventNoDBConn(t *testing.T) {
|
|
tmp := engine.Cache
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
dataDB, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(dataDB, cfg, nil)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
alS := &AttributeS{
|
|
cfg: cfg,
|
|
dm: dm,
|
|
fltrS: engine.NewFilterS(cfg, nil, dm),
|
|
}
|
|
|
|
postpaid, err := utils.NewRSRParsers(utils.MetaPostpaid, utils.InfieldSep)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
ap1 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Account:1001"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.RequestType",
|
|
Type: utils.MetaConstant,
|
|
Value: postpaid,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap1, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ap2 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_2",
|
|
FilterIDs: []string{"*string:~*req.Account:1001"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.RequestType",
|
|
Type: utils.MetaConstant,
|
|
Value: postpaid,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
tnt := "cgrates.org"
|
|
evNm := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
utils.AccountField: "1001",
|
|
},
|
|
utils.MetaVars: utils.MapStorage{},
|
|
}
|
|
lastID := ""
|
|
alS.dm = nil
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestAttributesattributeProfileForEventErrNotFound(t *testing.T) {
|
|
tmp := engine.Cache
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
dataDB, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(dataDB, cfg, nil)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
alS := &AttributeS{
|
|
cfg: cfg,
|
|
dm: dm,
|
|
fltrS: engine.NewFilterS(cfg, nil, dm),
|
|
}
|
|
|
|
apNil := &utils.AttributeProfile{}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), apNil, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
tnt := ""
|
|
evNm := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
utils.AccountField: "1001",
|
|
},
|
|
utils.MetaVars: utils.MapStorage{},
|
|
}
|
|
lastID := ""
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestAttributesattributeProfileForEventErrPass(t *testing.T) {
|
|
tmp := engine.Cache
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
dataDB, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(dataDB, cfg, nil)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
alS := &AttributeS{
|
|
cfg: cfg,
|
|
dm: dm,
|
|
fltrS: engine.NewFilterS(cfg, nil, dm),
|
|
}
|
|
|
|
postpaid, err := utils.NewRSRParsers(utils.MetaPostpaid, utils.InfieldSep)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
ap := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_1",
|
|
FilterIDs: []string{"*string:~*req.Account:1001"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.RequestType",
|
|
Type: utils.MetaConstant,
|
|
Value: postpaid,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
tnt := "cgrates.org"
|
|
evNm := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
utils.AccountField: "1001",
|
|
},
|
|
utils.MetaVars: utils.MapStorage{},
|
|
}
|
|
lastID := ""
|
|
|
|
evNm = utils.MapStorage{
|
|
utils.MetaReq: 1,
|
|
utils.MetaVars: utils.MapStorage{},
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeSIPCID(t *testing.T) {
|
|
exp := "12345;1001;1002"
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
if out, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.from", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString); err != nil {
|
|
t.Fatal(err)
|
|
} else if exp != out {
|
|
t.Errorf("Expected %q, Received %q", exp, out)
|
|
}
|
|
|
|
dp = utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1002",
|
|
"from": "1001",
|
|
},
|
|
}
|
|
if out, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.from", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString); err != nil {
|
|
t.Fatal(err)
|
|
} else if exp != out {
|
|
t.Errorf("Expected %q, Received %q", exp, out)
|
|
}
|
|
|
|
exp = "12345;1001;1002;1003"
|
|
dp = utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
"extra": "1003",
|
|
},
|
|
}
|
|
if out, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.extra;~*req.from",
|
|
utils.InfieldSep), 0, utils.EmptyString, utils.EmptyString); err != nil {
|
|
t.Fatal(err)
|
|
} else if exp != out {
|
|
t.Errorf("Expected %q, Received %q", exp, out)
|
|
}
|
|
|
|
dp = utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1002",
|
|
"from": "1001",
|
|
"extra": "1003",
|
|
},
|
|
}
|
|
if out, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.extra;~*req.to;~*req.from",
|
|
utils.InfieldSep), 0, utils.EmptyString, utils.EmptyString); err != nil {
|
|
t.Fatal(err)
|
|
} else if exp != out {
|
|
t.Errorf("Expected %q, Received %q", exp, out)
|
|
}
|
|
|
|
dp = utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
},
|
|
}
|
|
if _, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.extra;~*req.to;~*req.from", utils.
|
|
InfieldSep), 0, utils.EmptyString, utils.EmptyString); err != utils.ErrNotFound {
|
|
t.Errorf("Expected <%+v>, received <%+v>", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeSIPCIDWrongPathErr(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
utils.MetaOpts: 13,
|
|
}
|
|
value := utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.from;~*opts.WrongPath", utils.InfieldSep)
|
|
if _, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, value,
|
|
0, time.UTC.String(), utils.EmptyString); err == nil ||
|
|
err.Error() != utils.ErrWrongPath.Error() {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrWrongPath, err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeSIPCIDNotFoundErr(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
value := utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.from", utils.InfieldSep)
|
|
if _, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, value,
|
|
0, time.UTC.String(), utils.EmptyString); err == nil ||
|
|
err.Error() != utils.ErrNotFound.Error() {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeSIPCIDInvalidArguments(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
value := utils.RSRParsers{}
|
|
experr := `invalid number of arguments <[]> to *sipcid`
|
|
if _, err := ParseAttribute(dp, utils.MetaSIPCID, utils.EmptyString, value,
|
|
0, time.UTC.String(), utils.EmptyString); err == nil ||
|
|
err.Error() != experr {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1ProcessEventMultipleRuns1(t *testing.T) {
|
|
tmp := engine.Cache
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
postpaid := utils.NewRSRParsersMustCompile(utils.MetaPostpaid, utils.InfieldSep)
|
|
pw := utils.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
|
|
|
|
ap1 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR1",
|
|
FilterIDs: []string{"*notexists:~*vars.*processedProfileIDs[<~*vars.*apTenantID>]:"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: pw,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap1, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ap2 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR2",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.RequestType",
|
|
Type: utils.MetaConstant,
|
|
Value: postpaid,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrProcessEventMultipleRuns",
|
|
Event: map[string]any{
|
|
"Password": "passwd",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
utils.OptsAttributesProfileIDs: []string{"ATTR1", "ATTR2"},
|
|
},
|
|
}
|
|
reply := &AttrSProcessEventReply{}
|
|
exp := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR2",
|
|
Fields: []string{"*req.RequestType"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR1",
|
|
Fields: []string{"*req.Password"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR2",
|
|
Fields: []string{"*req.RequestType"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrProcessEventMultipleRuns",
|
|
Event: map[string]any{
|
|
"Password": "CGRateS.org",
|
|
utils.RequestType: utils.MetaPostpaid,
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileIDs: []string{"ATTR1", "ATTR2"},
|
|
utils.OptsAttributesProcessRuns: 4,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := alS.V1ProcessEvent(context.Background(), ev, reply); err != nil {
|
|
t.Error(err)
|
|
} else {
|
|
if !reflect.DeepEqual(reply, exp) {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1ProcessEventMultipleRuns2(t *testing.T) {
|
|
tmp := engine.Cache
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
postpaid := utils.NewRSRParsersMustCompile(utils.MetaPostpaid, utils.InfieldSep)
|
|
pw := utils.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
|
|
paypal := utils.NewRSRParsersMustCompile("cgrates@paypal.com", utils.InfieldSep)
|
|
|
|
ap1 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR1",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: pw,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap1, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ap2 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR2",
|
|
FilterIDs: []string{"*exists:~*vars.*processedProfileIDs[cgrates.org:ATTR1]:"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.RequestType",
|
|
Type: utils.MetaConstant,
|
|
Value: postpaid,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ap3 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR3",
|
|
FilterIDs: []string{"*exists:~*vars.*processedProfileIDs[cgrates.org:ATTR2]:"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.PaypalAccount",
|
|
Type: utils.MetaConstant,
|
|
Value: paypal,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap3, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrProcessEventMultipleRuns",
|
|
Event: map[string]any{},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 3,
|
|
},
|
|
}
|
|
|
|
reply := &AttrSProcessEventReply{}
|
|
exp := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR1",
|
|
Fields: []string{"*req.Password"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR2",
|
|
Fields: []string{"*req.RequestType"},
|
|
},
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR3",
|
|
Fields: []string{"*req.PaypalAccount"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrProcessEventMultipleRuns",
|
|
Event: map[string]any{
|
|
"Password": "CGRateS.org",
|
|
"PaypalAccount": "cgrates@paypal.com",
|
|
utils.RequestType: utils.MetaPostpaid,
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 3,
|
|
},
|
|
},
|
|
}
|
|
if err := alS.V1ProcessEvent(context.Background(), ev, reply); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(reply, exp) {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>",
|
|
utils.ToJSON(exp), utils.ToJSON(reply))
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1GetAttributeForEvent(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "adrian@itsyscom.com",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
},
|
|
}
|
|
rply := &utils.APIAttributeProfile{}
|
|
expected := &utils.APIAttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.ExternalAttribute{
|
|
{
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: "~*req.Account:s/(.*)@(.*)/${1}.${2}/",
|
|
},
|
|
{
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: "~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/",
|
|
},
|
|
{
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: ".co.uk",
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = alS.V1GetAttributeForEvent(context.Background(), ev, rply)
|
|
if err != nil {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
|
|
}
|
|
if !reflect.DeepEqual(expected, rply) {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", utils.ToJSON(expected), utils.ToJSON(rply))
|
|
}
|
|
}
|
|
|
|
func TestAttributesV1GetAttributeForEventErrorBoolOpts(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "adrian@itsyscom.com",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
utils.MetaProfileIgnoreFilters: time.Second,
|
|
},
|
|
}
|
|
rply := &utils.APIAttributeProfile{}
|
|
|
|
err = alS.V1GetAttributeForEvent(context.Background(), ev, rply)
|
|
if err == nil || err.Error() != "cannot convert field: 1s to bool" {
|
|
t.Errorf("\nExpected <cannot convert field: 1s to bool>, \nReceived <%+v>", err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributesV1GetAttributeForEventErrorNil(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
rply := &utils.APIAttributeProfile{}
|
|
|
|
err = alS.V1GetAttributeForEvent(context.Background(), nil, rply)
|
|
if err == nil || err.Error() != "MANDATORY_IE_MISSING: [CGREvent]" {
|
|
t.Errorf("\nExpected <MANDATORY_IE_MISSING: [CGREvent]>, \nReceived <%+v>", err)
|
|
}
|
|
|
|
}
|
|
|
|
func TestAttributesV1GetAttributeForEventErrOptsI(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.FilterSCfg().ResourceSConns = []string{}
|
|
conMng := engine.NewConnManager(cfg)
|
|
db, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(db, cfg, conMng)
|
|
filterS := engine.NewFilterS(cfg, conMng, dm)
|
|
attr := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_CHANGE_TENANT_FROM_USER",
|
|
FilterIDs: []string{"*string:~*req.Account:dan@itsyscom.com|adrian@itsyscom.com"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(.*)@(.*)/${1}.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Account",
|
|
Type: "*variable",
|
|
Value: utils.NewRSRParsersMustCompile("~*req.Account:s/(dan)@(.*)/${1}.${2}/:s/(adrian)@(.*)/andrei.${2}/", utils.InfieldSep),
|
|
},
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*tenant",
|
|
Type: "*composed",
|
|
Value: utils.NewRSRParsersMustCompile(".co.uk", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
err = dm.SetAttributeProfile(context.Background(), attr, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
attr2 := &utils.AttributeProfile{
|
|
Tenant: "adrian.itsyscom.com.co.uk",
|
|
ID: "ATTR_MATCH_TENANT",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
FilterIDs: nil,
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: utils.NewRSRParsersMustCompile("CGRATES.ORG", utils.InfieldSep),
|
|
},
|
|
},
|
|
Blockers: utils.DynamicBlockers{
|
|
{
|
|
Blocker: false,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = dm.SetAttributeProfile(context.Background(), attr2, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "123",
|
|
Event: map[string]any{
|
|
utils.AccountField: "adrian@itsyscom.com",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: 2,
|
|
utils.OptsAttributesProfileIDs: time.Second,
|
|
},
|
|
}
|
|
rply := &utils.APIAttributeProfile{}
|
|
|
|
err = alS.V1GetAttributeForEvent(context.Background(), ev, rply)
|
|
if err == nil || err.Error() != "cannot convert field: 1s to []string" {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "cannot convert field: 1s to []string", err)
|
|
}
|
|
|
|
}
|
|
func TestAttributesProcessEventProfileIgnoreFilters(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
aA := NewAttributeService(dm, filterS, cfg)
|
|
cfg.AttributeSCfg().Opts.ProfileIgnoreFilters = []*config.DynamicBoolOpt{
|
|
config.NewDynamicBoolOpt(nil, "", true, nil),
|
|
}
|
|
acPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AC1",
|
|
FilterIDs: []string{"*string:~*req.Attribute:testAttrValue"},
|
|
}
|
|
if err := dm.SetAttributeProfile(context.Background(), acPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
//should match the attr profile for event because the option is false but the filter matches
|
|
args2 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent",
|
|
Event: map[string]any{
|
|
"Attribute": "testAttrValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileIDs: []string{"AC1"},
|
|
utils.MetaProfileIgnoreFilters: false,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: args2.Event,
|
|
utils.MetaOpts: args2.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
exp2 := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:AC1",
|
|
Fields: []string{},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent",
|
|
Event: map[string]any{
|
|
"Attribute": "testAttrValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileIDs: []string{"AC1"},
|
|
utils.MetaProfileIgnoreFilters: false,
|
|
},
|
|
},
|
|
}
|
|
if rcv2, err := aA.processEvent(context.Background(), args2.Tenant, args2, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(rcv2, exp2) {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp2), utils.ToJSON(rcv2))
|
|
}
|
|
//should match the attr profile for event because the option is true even if the filter doesn't match
|
|
args := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent2",
|
|
Event: map[string]any{
|
|
"Attribute": "testAttrValue2",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileIDs: []string{"AC1"},
|
|
utils.MetaProfileIgnoreFilters: true,
|
|
},
|
|
}
|
|
eNM2 := utils.MapStorage{
|
|
utils.MetaReq: args.Event,
|
|
utils.MetaOpts: args.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
exp := &AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:AC1",
|
|
Fields: []string{},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent2",
|
|
Event: map[string]any{
|
|
"Attribute": "testAttrValue2",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileIDs: []string{"AC1"},
|
|
utils.MetaProfileIgnoreFilters: true,
|
|
},
|
|
},
|
|
}
|
|
if rcv, err := aA.processEvent(context.Background(), args.Tenant, args, eNM2, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM2), utils.EmptyString, make(map[string]int), 0); err != nil {
|
|
t.Error(err)
|
|
} else if !reflect.DeepEqual(rcv, exp) {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
|
|
func TestAttributeServicesProcessEventGetStringSliceOptsError(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
aA := NewAttributeService(dm, filterS, cfg)
|
|
args2 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent",
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileIDs: time.Second,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: args2.Event,
|
|
utils.MetaOpts: args2.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
_, err = aA.processEvent(context.Background(), args2.Tenant, args2, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err == nil || err.Error() != "cannot convert field: 1s to []string" {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "cannot convert field: 1s to []string", err)
|
|
}
|
|
}
|
|
|
|
func TestAttributeServicesProcessEventGetBoolOptsError(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
aA := NewAttributeService(dm, filterS, cfg)
|
|
args2 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent",
|
|
APIOpts: map[string]any{
|
|
utils.MetaProfileIgnoreFilters: time.Second,
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: args2.Event,
|
|
utils.MetaOpts: args2.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
_, err = aA.processEvent(context.Background(), args2.Tenant, args2, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0)
|
|
if err == nil || err.Error() != "cannot convert field: 1s to bool" {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "cannot convert field: 1s to bool", err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeMetaNone(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
if out, err := ParseAttribute(dp, utils.MetaNone, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.from", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString); err != nil {
|
|
t.Fatal(err)
|
|
} else if out != nil {
|
|
t.Errorf("Expected %+v, Received %+v", nil, out)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeMetaUsageDifferenceBadValError(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaUsageDifference, utils.EmptyString, utils.NewRSRParsersMustCompile("", utils.InfieldSep), 0, utils.EmptyString, utils.EmptyString)
|
|
|
|
if err == nil || err.Error() != "invalid arguments <null> to *usageDifference" {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeMetaCCUsageError(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
_, err := ParseAttribute(dp, utils.MetaCCUsage, utils.EmptyString, utils.NewRSRParsersMustCompile("::;~*req.to;~*req.from", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString)
|
|
if err == nil || err.Error() != "invalid requestNumber <::> to *ccUsage" {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesProcessEventSetError(t *testing.T) {
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
aA := NewAttributeService(dm, filterS, cfg)
|
|
acPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "AC1",
|
|
FilterIDs: []string{"*string:~*req.Attribute:testAttrValue"},
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "",
|
|
},
|
|
},
|
|
}
|
|
if err := dm.SetAttributeProfile(context.Background(), acPrf, true); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
args2 := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AcProcessEvent",
|
|
Event: map[string]any{
|
|
"Attribute": "testAttrValue",
|
|
},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileIDs: []string{"AC1"},
|
|
},
|
|
}
|
|
eNM := utils.MapStorage{
|
|
utils.MetaReq: args2.Event,
|
|
utils.MetaOpts: args2.APIOpts,
|
|
utils.MetaVars: utils.MapStorage{
|
|
utils.OptsAttributesProcessRuns: 0,
|
|
},
|
|
}
|
|
|
|
if _, err := aA.processEvent(context.Background(), args2.Tenant, args2, eNM, engine.NewDynamicDP(context.TODO(), nil, nil, nil, nil, nil, "cgrates.org", eNM), utils.EmptyString, make(map[string]int), 0); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
func TestAttributesAttributeServiceV1PrcssEvPrcssRunsGetIntOptsErr(t *testing.T) {
|
|
tmp := engine.Cache
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
pw := utils.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
|
|
|
|
ap1 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR1",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: pw,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap1, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrProcessEventMultipleRuns",
|
|
Event: map[string]any{},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProcessRuns: "errVal",
|
|
},
|
|
}
|
|
|
|
reply := &AttrSProcessEventReply{}
|
|
exrErr := `strconv.Atoi: parsing "errVal": invalid syntax`
|
|
if err := alS.V1ProcessEvent(context.Background(), ev, reply); err == nil || err.Error() != exrErr {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", exrErr, err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesAttributeServiceV1PrcssEvProfRunsGetIntOptsErr(t *testing.T) {
|
|
tmp := engine.Cache
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
cfg.AttributeSCfg().IndexedSelects = false
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
alS := NewAttributeService(dm, filterS, cfg)
|
|
pw := utils.NewRSRParsersMustCompile("CGRateS.org", utils.InfieldSep)
|
|
|
|
ap1 := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR1",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: pw,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
err = alS.dm.SetAttributeProfile(context.Background(), ap1, true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
ev := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "AttrProcessEventMultipleRuns",
|
|
Event: map[string]any{},
|
|
APIOpts: map[string]any{
|
|
utils.OptsAttributesProfileRuns: "errVal",
|
|
},
|
|
}
|
|
|
|
reply := &AttrSProcessEventReply{}
|
|
exrErr := `strconv.Atoi: parsing "errVal": invalid syntax`
|
|
if err := alS.V1ProcessEvent(context.Background(), ev, reply); err == nil || err.Error() != exrErr {
|
|
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", exrErr, err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeMetaGeneric(t *testing.T) {
|
|
exp := "1234510011002"
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
if out, err := ParseAttribute(dp, utils.MetaGeneric, utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.from", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString); err != nil {
|
|
t.Fatal(err)
|
|
} else if exp != out {
|
|
t.Errorf("Expected %q, Received %q", exp, out)
|
|
}
|
|
}
|
|
|
|
func TestAttributesParseAttributeError(t *testing.T) {
|
|
dp := utils.MapStorage{
|
|
utils.MetaReq: utils.MapStorage{
|
|
"cid": "12345",
|
|
"to": "1001",
|
|
"from": "1002",
|
|
},
|
|
}
|
|
if _, err := ParseAttribute(dp, "badType", utils.EmptyString, utils.NewRSRParsersMustCompile("~*req.cid;~*req.to;~*req.from", utils.InfieldSep),
|
|
0, utils.EmptyString, utils.EmptyString); err == nil || err.Error() != "unsupported type: <badType>" {
|
|
t.Errorf("Expected %q, Received %q", "unsupported type: <badType>", err)
|
|
}
|
|
}
|
|
|
|
func TestAttributesProcessEventPasswordAttribute(t *testing.T) {
|
|
tmp := engine.Cache
|
|
tmpC := config.CgrConfig()
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
config.SetCgrConfig(tmpC)
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
filterS := engine.NewFilterS(cfg, nil, dm)
|
|
attrS := NewAttributeService(dm, filterS, cfg)
|
|
|
|
value := utils.NewRSRParsersMustCompile("abcd123", utils.RSRSep)
|
|
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaPassword,
|
|
Value: value,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 10,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
cgrEv := &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "EventHashPw",
|
|
Event: map[string]any{
|
|
"Password": "321dcba",
|
|
},
|
|
}
|
|
|
|
exp := AttrSProcessEventReply{
|
|
AlteredFields: []*FieldsAltered{
|
|
{
|
|
MatchedProfileID: "cgrates.org:ATTR_TEST",
|
|
Fields: []string{"*req.Password"},
|
|
},
|
|
},
|
|
CGREvent: &utils.CGREvent{
|
|
Tenant: "cgrates.org",
|
|
ID: "EventHashPw",
|
|
Event: map[string]any{
|
|
"Password": "abcd123",
|
|
},
|
|
APIOpts: map[string]any{},
|
|
},
|
|
}
|
|
var hashedPw string
|
|
var reply AttrSProcessEventReply
|
|
if err := attrS.V1ProcessEvent(context.Background(), cgrEv, &reply); err != nil {
|
|
t.Fatal(err)
|
|
} else if !reflect.DeepEqual(reply.AlteredFields, exp.AlteredFields) {
|
|
t.Fatalf("expected: <%+v>,\nreceived: <%+v>",
|
|
utils.ToJSON(exp.AlteredFields), utils.ToJSON(reply.AlteredFields))
|
|
} else {
|
|
hashedPw = utils.IfaceAsString(reply.CGREvent.Event["Password"])
|
|
if !utils.VerifyHash(hashedPw, "abcd123") {
|
|
t.Fatalf("expected: <%+v>, \nreceived: <%+v>", "abcd123", hashedPw)
|
|
}
|
|
exp.CGREvent.Event["Password"] = hashedPw
|
|
if !reflect.DeepEqual(reply.CGREvent, exp.CGREvent) {
|
|
t.Fatalf("expected: <%+v>, \nreceived: <%+v>",
|
|
utils.ToJSON(exp.CGREvent), utils.ToJSON(reply.CGREvent))
|
|
}
|
|
}
|
|
|
|
value = utils.NewRSRParsersMustCompile(hashedPw, utils.RSRSep)
|
|
expAttrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
Value: value,
|
|
},
|
|
},
|
|
Weights: make(utils.DynamicWeights, 1),
|
|
}
|
|
expAttrPrf.Weights[0] = &utils.DynamicWeight{
|
|
|
|
Weight: 10,
|
|
}
|
|
if rcvAttrPrf, err := dm.GetAttributeProfile(context.Background(), attrPrf.Tenant, attrPrf.ID, true, true,
|
|
utils.NonTransactional); err != nil {
|
|
t.Fatal(err)
|
|
} else if !reflect.DeepEqual(rcvAttrPrf, expAttrPrf) {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(expAttrPrf), utils.ToJSON(rcvAttrPrf))
|
|
}
|
|
}
|
|
|
|
func TestAttributesSetAttributeProfilePasswordAttr(t *testing.T) {
|
|
tmp := engine.Cache
|
|
tmpC := config.CgrConfig()
|
|
defer func() {
|
|
engine.Cache = tmp
|
|
config.SetCgrConfig(tmpC)
|
|
}()
|
|
|
|
cfg := config.NewDefaultCGRConfig()
|
|
data, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
dm := engine.NewDataManager(data, cfg, nil)
|
|
engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
|
|
|
|
value := utils.NewRSRParsersMustCompile("abcd123", utils.RSRSep)
|
|
attrPrf := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaPassword,
|
|
Value: value,
|
|
},
|
|
},
|
|
Weights: make(utils.DynamicWeights, 1),
|
|
}
|
|
attrPrf.Weights[0] = &utils.DynamicWeight{
|
|
|
|
Weight: 20,
|
|
}
|
|
if err := dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
exp := &utils.AttributeProfile{
|
|
Tenant: "cgrates.org",
|
|
ID: "ATTR_TEST",
|
|
Attributes: []*utils.Attribute{
|
|
{
|
|
Path: "*req.Password",
|
|
Type: utils.MetaConstant,
|
|
},
|
|
},
|
|
Weights: utils.DynamicWeights{
|
|
{
|
|
Weight: 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
if rcv, err := dm.GetAttributeProfile(context.Background(), attrPrf.Tenant, attrPrf.ID, true, true,
|
|
utils.NonTransactional); err != nil {
|
|
t.Error(err)
|
|
} else if hashedPw := rcv.Attributes[0].Value.GetRule(); !utils.VerifyHash(hashedPw, "abcd123") {
|
|
t.Errorf("Received an incorrect password")
|
|
} else {
|
|
rcv.Attributes[0].Value = nil
|
|
if !reflect.DeepEqual(rcv, exp) {
|
|
t.Errorf("expected: <%+v>, \nreceived: <%+v>",
|
|
utils.ToJSON(exp), utils.ToJSON(rcv))
|
|
}
|
|
}
|
|
}
|