Files
cgrates/config/fctemplate_test.go
2023-05-31 10:23:12 +02:00

523 lines
17 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 config
import (
"reflect"
"testing"
"time"
"github.com/cgrates/cgrates/utils"
)
func TestNewFCTemplateFromFCTemplateJsonCfg(t *testing.T) {
jsonCfg := &FcTemplateJsonCfg{
Tag: utils.StringPointer("Tenant"),
Type: utils.StringPointer("*composed"),
Path: utils.StringPointer("Tenant"),
Filters: &[]string{"Filter1", "Filter2"},
Value: utils.StringPointer("cgrates.org"),
}
expected := &FCTemplate{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
Layout: time.RFC3339,
}
expected.ComputePath()
if rcv, err := NewFCTemplateFromFCTemplateJSONCfg(jsonCfg, utils.InfieldSep); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expected, rcv) {
t.Errorf("expected: %s ,received: %s", utils.ToJSON(expected), utils.ToJSON(rcv))
}
}
func TestFCTemplateInflateTemplate(t *testing.T) {
fcTemplate := []*FCTemplate{
{
Type: utils.MetaTemplate,
Value: NewRSRParsersMustCompile("1sa{*duration}", utils.InfieldSep),
},
}
expected := "time: unknown unit \"sa\" in duration \"1sa\""
jsonCfg := NewDefaultCGRConfig()
if _, err := InflateTemplates(fcTemplate, jsonCfg.templates); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
}
func TestFCTemplatePathItems(t *testing.T) {
fcTemplate := FCTemplate{
Path: "*req.Account[1].Balance[*monetary].Value",
}
expected := []string{"*req", "Account", "1", "Balance", "*monetary", "Value"}
fcTemplate.ComputePath()
if !reflect.DeepEqual(expected, fcTemplate.GetPathSlice()) {
t.Errorf("Expected %+v, received %+v", utils.ToJSON(expected), utils.ToJSON(fcTemplate))
}
}
func TestFCTemplatesFromFCTemplatesJsonCfg(t *testing.T) {
jsnCfgs := []*FcTemplateJsonCfg{
{
Tag: utils.StringPointer("Tenant"),
Type: utils.StringPointer("*composed"),
Path: utils.StringPointer("Tenant"),
Filters: &[]string{"Filter1", "Filter2"},
Value: utils.StringPointer("cgrates.org"),
},
{
Tag: utils.StringPointer("RunID"),
Type: utils.StringPointer("*composed"),
Path: utils.StringPointer("RunID"),
Filters: &[]string{"Filter1_1", "Filter2_2"},
Value: utils.StringPointer("SampleValue"),
},
}
expected := []*FCTemplate{
{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
Layout: time.RFC3339,
},
{
Tag: "RunID",
Type: "*composed",
Path: "RunID",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("SampleValue", utils.InfieldSep),
Layout: time.RFC3339,
},
}
for _, v := range expected {
v.ComputePath()
}
if rcv, err := FCTemplatesFromFCTemplatesJSONCfg(jsnCfgs, utils.InfieldSep); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expected, rcv) {
t.Errorf("expected: %s ,received: %s", utils.ToJSON(expected), utils.ToJSON(rcv))
}
}
func TestFCTemplateInflate1(t *testing.T) {
fcTmp1 := []*FCTemplate{
{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
},
{
Tag: "RunID",
Type: "*composed",
Path: "RunID",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("SampleValue", utils.InfieldSep),
},
{
Tag: "TmpMap",
Type: "*template",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("TmpMap", utils.InfieldSep),
},
}
fcTmpMp := map[string][]*FCTemplate{
"TmpMap": {
{
Tag: "Elem1",
Type: "*composed",
Path: "Elem1",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("Elem1", utils.InfieldSep),
},
{
Tag: "Elem2",
Type: "*composed",
Path: "Elem2",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("Elem2", utils.InfieldSep),
},
},
"TmpMap2": {
{
Tag: "Elem2.1",
Type: "*composed",
Path: "Elem2.1",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("Elem2.1", utils.InfieldSep),
},
{
Tag: "Elem2.2",
Type: "*composed",
Path: "Elem2.2",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("Elem2.2", utils.InfieldSep),
},
},
}
expFC := []*FCTemplate{
{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
},
{
Tag: "RunID",
Type: "*composed",
Path: "RunID",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("SampleValue", utils.InfieldSep),
},
{
Tag: "Elem1",
Type: "*composed",
Path: "Elem1",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("Elem1", utils.InfieldSep),
},
{
Tag: "Elem2",
Type: "*composed",
Path: "Elem2",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("Elem2", utils.InfieldSep),
},
}
if rcv, err := InflateTemplates(fcTmp1, fcTmpMp); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expFC, rcv) {
t.Errorf("expected: %s\n ,received: %s", utils.ToJSON(expFC), utils.ToJSON(rcv))
}
}
func TestFCTemplateInflate2(t *testing.T) {
fcTmp1 := []*FCTemplate{
{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
},
{
Tag: "RunID",
Type: "*composed",
Path: "RunID",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("SampleValue", utils.InfieldSep),
},
{
Tag: "TmpMap3",
Type: "*template",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("TmpMap3", utils.InfieldSep),
},
}
fcTmpMp := map[string][]*FCTemplate{
"TmpMap": {
{
Tag: "Elem1",
Type: "*composed",
Path: "Elem1",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("Elem1", utils.InfieldSep),
},
{
Tag: "Elem2",
Type: "*composed",
Path: "Elem2",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("Elem2", utils.InfieldSep),
},
},
"TmpMap2": {
{
Tag: "Elem2.1",
Type: "*composed",
Path: "Elem2.1",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("Elem2.1", utils.InfieldSep),
},
{
Tag: "Elem2.2",
Type: "*composed",
Path: "Elem2.2",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("Elem2.2", utils.InfieldSep),
},
},
}
if _, err := InflateTemplates(fcTmp1, fcTmpMp); err.Error() != "no template with id: <TmpMap3>" {
t.Error(err)
}
}
func TestFCTemplateInflate3(t *testing.T) {
fcTmp1 := []*FCTemplate{
{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
},
{
Tag: "RunID",
Type: "*composed",
Path: "RunID",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("SampleValue", utils.InfieldSep),
},
{
Tag: "TmpMap",
Type: "*template",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("TmpMap", utils.InfieldSep),
},
}
fcTmpMp := map[string][]*FCTemplate{
"TmpMap": {},
"TmpMap2": {
{
Tag: "Elem2.1",
Type: "*composed",
Path: "Elem2.1",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("Elem2.1", utils.InfieldSep),
},
{
Tag: "Elem2.2",
Type: "*composed",
Path: "Elem2.2",
Filters: []string{"Filter1_1", "Filter2_2"},
Value: NewRSRParsersMustCompile("Elem2.2", utils.InfieldSep),
},
},
}
for _, v := range fcTmp1 {
v.ComputePath()
}
for _, tmpl := range fcTmpMp {
for _, v := range tmpl {
v.ComputePath()
}
}
if _, err := InflateTemplates(fcTmp1, fcTmpMp); err == nil ||
err.Error() != "empty template with id: <TmpMap>" {
t.Error(err)
}
}
func TestFCTemplateClone(t *testing.T) {
smpl := &FCTemplate{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
RoundingDecimals: utils.IntPointer(2),
}
smpl.ComputePath()
cloned := smpl.Clone()
if !reflect.DeepEqual(cloned, smpl) {
t.Errorf("expected: %s ,received: %s", utils.ToJSON(smpl), utils.ToJSON(cloned))
}
initialSmpl := &FCTemplate{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
RoundingDecimals: utils.IntPointer(2),
}
initialSmpl.ComputePath()
smpl.Filters = []string{"SingleFilter"}
smpl.Value = NewRSRParsersMustCompile("cgrates.com", utils.InfieldSep)
if !reflect.DeepEqual(cloned, initialSmpl) {
t.Errorf("expected: %s ,received: %s", utils.ToJSON(initialSmpl), utils.ToJSON(cloned))
}
}
func TestFCTemplateAsMapInterface(t *testing.T) {
cfgJSONStr := `{
"templates": {
"custom_template": [
{
"tag": "Tenant",
"type": "*composed",
"path": "Tenant",
"filters" : ["val1","val2"],
"value": "cgrates.org",
"width": 10,
"strip": "strp",
"padding": "pdding",
"mandatory": true,
"attribute_id": "random.val",
"new_branch": true,
"timezone": "Local",
"blocker": true,
"layout": "",
"cost_shift_digits": 10,
"rounding_decimals": 1,
"mask_destinationd_id": "randomVal",
"mask_length": 10,
},
],
}
}`
eMap := map[string]any{
"custom_template": []map[string]any{
{
utils.TagCfg: "Tenant",
utils.TypeCfg: "*composed",
utils.PathCfg: "Tenant",
utils.FiltersCfg: []string{"val1", "val2"},
utils.ValueCfg: "cgrates.org",
utils.WidthCfg: 10,
utils.StripCfg: "strp",
utils.PaddingCfg: "pdding",
utils.MandatoryCfg: true,
utils.AttributeIDCfg: "random.val",
utils.NewBranchCfg: true,
utils.TimezoneCfg: "Local",
utils.BlockerCfg: true,
utils.LayoutCfg: "",
utils.CostShiftDigitsCfg: 10,
utils.RoundingDecimalsCfg: 1,
utils.MaskDestIDCfg: "randomVal",
utils.MaskLenCfg: 10,
},
},
}
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
t.Error(err)
} else if rcv := cgrCfg.templates.AsMapInterface(cgrCfg.generalCfg.RSRSep); !reflect.DeepEqual(eMap["custom_template"], rcv["custom_template"]) {
t.Errorf("Expected %+v \n, recieved %+v", utils.ToJSON(eMap["custom_template"]), utils.ToJSON(rcv["custom_template"]))
}
}
func TestFCTemplateAsMapInterface1(t *testing.T) {
cfgJSONStr := `{
"templates": {
"*err": [
{"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable",
"value": "~*req.Session-Id", "mandatory": true},
{"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable",
"value": "~*vars.OriginHost", "mandatory": true},
{"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable",
"value": "~*vars.OriginRealm", "mandatory": true},
],
"*asr": [
{"tag": "SessionId", "path": "*diamreq.Session-Id", "type": "*variable",
"value": "~*req.Session-Id", "mandatory": true},
{"tag": "OriginHost", "path": "*diamreq.Origin-Host", "type": "*variable",
"value": "~*req.Destination-Host", "mandatory": true},
{"tag": "OriginRealm", "path": "*diamreq.Origin-Realm", "type": "*variable",
"value": "~*req.Destination-Realm", "mandatory": true},
{"tag": "DestinationRealm", "path": "*diamreq.Destination-Realm", "type": "*variable",
"value": "~*req.Origin-Realm", "mandatory": true},
{"tag": "DestinationHost", "path": "*diamreq.Destination-Host", "type": "*variable",
"value": "~*req.Origin-Host", "mandatory": true},
{"tag": "AuthApplicationId", "path": "*diamreq.Auth-Application-Id", "type": "*variable",
"value": "~*vars.*appid", "mandatory": true},
],
}
}`
eMap := map[string]any{
utils.MetaErr: []map[string]any{
{utils.TagCfg: "SessionId", utils.PathCfg: "*rep.Session-Id", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*req.Session-Id", utils.MandatoryCfg: true},
{utils.TagCfg: "OriginHost", utils.PathCfg: "*rep.Origin-Host", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*vars.OriginHost", utils.MandatoryCfg: true},
{utils.TagCfg: "OriginRealm", utils.PathCfg: "*rep.Origin-Realm", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*vars.OriginRealm", utils.MandatoryCfg: true},
},
utils.MetaASR: []map[string]any{
{utils.TagCfg: "SessionId", utils.PathCfg: "*diamreq.Session-Id", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*req.Session-Id", utils.MandatoryCfg: true},
{utils.TagCfg: "OriginHost", utils.PathCfg: "*diamreq.Origin-Host", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*req.Destination-Host", utils.MandatoryCfg: true},
{utils.TagCfg: "OriginRealm", utils.PathCfg: "*diamreq.Origin-Realm", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*req.Destination-Realm", utils.MandatoryCfg: true},
{utils.TagCfg: "DestinationRealm", utils.PathCfg: "*diamreq.Destination-Realm", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*req.Origin-Realm", utils.MandatoryCfg: true},
{utils.TagCfg: "DestinationHost", utils.PathCfg: "*diamreq.Destination-Host", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*req.Origin-Host", utils.MandatoryCfg: true},
{utils.TagCfg: "AuthApplicationId", utils.PathCfg: "*diamreq.Auth-Application-Id", utils.TypeCfg: "*variable",
utils.ValueCfg: "~*vars.*appid", utils.MandatoryCfg: true},
},
}
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
t.Error(err)
} else {
rcv := cgrCfg.templates.AsMapInterface(cgrCfg.generalCfg.RSRSep)
if !reflect.DeepEqual(eMap[utils.MetaErr], rcv[utils.MetaErr]) {
t.Errorf("Expected %+v \n, recieved %+v", utils.ToJSON(eMap[utils.MetaErr]), utils.ToJSON(rcv[utils.MetaErr]))
} else if !reflect.DeepEqual(eMap[utils.MetaASR], rcv[utils.MetaASR]) {
t.Errorf("Expected %+v \n, recieved %+v", utils.ToJSON(eMap[utils.MetaASR]), utils.ToJSON(rcv[utils.MetaASR]))
}
}
}
func TestFCTemplatesClone(t *testing.T) {
smpl := FcTemplates{
utils.MetaErr: {{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
RoundingDecimals: utils.IntPointer(2),
}},
}
smpl[utils.MetaErr][0].ComputePath()
cloned := smpl.Clone()
if !reflect.DeepEqual(cloned, smpl) {
t.Errorf("expected: %s ,received: %s", utils.ToJSON(smpl), utils.ToJSON(cloned))
}
initialSmpl := FcTemplates{
utils.MetaErr: {{
Tag: "Tenant",
Type: "*composed",
Path: "Tenant",
Filters: []string{"Filter1", "Filter2"},
Value: NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
RoundingDecimals: utils.IntPointer(2),
}},
}
initialSmpl[utils.MetaErr][0].ComputePath()
smpl[utils.MetaErr] = nil
if !reflect.DeepEqual(cloned, initialSmpl) {
t.Errorf("expected: %s ,received: %s", utils.ToJSON(initialSmpl), utils.ToJSON(cloned))
}
smpl = nil
cloned = smpl.Clone()
if !reflect.DeepEqual(cloned, smpl) {
t.Errorf("expected: %s ,received: %s", utils.ToJSON(smpl), utils.ToJSON(cloned))
}
}