Files
cgrates/config/config_it_test.go
ionutboangiu 6c41ebe0de Add sanity check to prevent xml reader panic
HierarchyPath parser now returns nil when
the path is empty (instead of a string slice with one
EmptyString element).

If the prefix is set to true, when calling the AsString
method on a nil HierarchyPath, only the separator will
be returned. This avoids a nil expr error coming from
the xmlquery library.

Use the Query and QueryAll functions from the xmlquery
package to be able to handle the errors ourselves and
avoid panics.

Remove config default value for xml_root_path. The field
will remain commented in config_defaults for reference.

Add tests for HierarchyPath.AsString function.

Add comments for XmlProvider and xml_root_path opt.
2023-10-16 13:18:12 +03:00

1376 lines
45 KiB
Go

//go:build integration
// +build integration
/*
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 (
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"reflect"
"testing"
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/rpcclient"
)
var (
cgrTests = []func(t *testing.T){
testNewCgrJsonCfgFromHttp,
testNewCGRConfigFromPath,
testCGRConfigReloadAttributeS,
testCGRConfigReloadChargerSDryRun,
testCGRConfigReloadChargerS,
testCGRConfigReloadThresholdS,
testCGRConfigReloadStatS,
testCGRConfigReloadResourceS,
testCGRConfigReloadSupplierS,
testCGRConfigReloadSchedulerS,
testCGRConfigReloadCDRs,
testCGRConfigReloadRALs,
testCGRConfigReloadSessionS,
testCGRConfigReloadERs,
testCGRConfigReloadDNSAgent,
testCGRConfigReloadFreeswitchAgent,
testCgrCfgV1ReloadConfigSection,
testCGRConfigV1ReloadConfigFromPathInvalidSection,
testV1ReloadConfigFromPathConfigSanity,
testLoadConfigFromHTTPValidURL,
testCGRConfigReloadConfigFromJSONSessionS,
testCGRConfigReloadConfigFromStringSessionS,
testCGRConfigReloadAll,
testHttpHandlerConfigSForNotExistFile,
testHttpHandlerConfigSForFile,
testHttpHandlerConfigSForNotExistFolder,
testHttpHandlerConfigSForFolder,
testHttpHandlerConfigSInvalidPath,
testLoadConfigFromPathInvalidArgument,
testLoadConfigFromPathValidPath,
testLoadConfigFromPathFile,
testLoadConfigFromFolderFileNotFound,
testLoadConfigFromFolderNoConfigFound,
testLoadConfigFromFolderOpenError,
testHandleConfigSFolderError,
testHandleConfigSFilesError,
testHandleConfigSFileErrorWrite,
testHandleConfigSFolderErrorWrite,
}
)
func TestCGRConfig(t *testing.T) {
for _, test := range cgrTests {
t.Run("CGRConfig", test)
}
}
func testNewCgrJsonCfgFromHttp(t *testing.T) {
addr := "https://raw.githubusercontent.com/cgrates/cgrates/master/data/conf/samples/tutmongo/cgrates.json"
expVal := NewDefaultCGRConfig()
err = expVal.loadConfigFromPath(path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo"),
[]func(*CgrJsonCfg) error{expVal.loadFromJSONCfg}, false)
if err != nil {
t.Fatal(err)
}
if _, err = net.DialTimeout(utils.TCP, addr, time.Second); err != nil { // check if site is up
return
}
rply := NewDefaultCGRConfig()
if err = rply.loadConfigFromPath(addr, []func(*CgrJsonCfg) error{rply.loadFromJSONCfg}, false); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expVal, rply) {
t.Errorf("Expected: %s ,received: %s", utils.ToJSON(expVal), utils.ToJSON(rply))
}
}
func testNewCGRConfigFromPath(t *testing.T) {
for key, val := range map[string]string{"LOGGER": "*syslog", "LOG_LEVEL": "6", "ROUND_DEC": "5",
"DB_ENCODING": "*msgpack", "TP_EXPORT_DIR": "/var/spool/cgrates/tpe", "FAILED_POSTS_DIR": "/var/spool/cgrates/failed_posts",
"DF_TENANT": "cgrates.org", "TIMEZONE": "Local"} {
os.Setenv(key, val)
}
addr := "https://raw.githubusercontent.com/cgrates/cgrates/master/data/conf/samples/multifiles/a.json;https://raw.githubusercontent.com/cgrates/cgrates/master/data/conf/samples/multifiles/b/b.json;https://raw.githubusercontent.com/cgrates/cgrates/master/data/conf/samples/multifiles/c.json;https://raw.githubusercontent.com/cgrates/cgrates/master/data/conf/samples/multifiles/d.json"
expVal, err := NewCGRConfigFromPath(path.Join("/usr", "share", "cgrates", "conf", "samples", "multifiles"))
if err != nil {
t.Fatal(err)
}
if _, err = net.DialTimeout(utils.TCP, addr, time.Second); err != nil { // check if site is up
return
}
if rply, err := NewCGRConfigFromPath(addr); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expVal, rply) {
t.Errorf("Expected: %s ,received: %s", utils.ToJSON(expVal), utils.ToJSON(rply))
}
}
func testCGRConfigReloadAttributeS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: ATTRIBUTE_JSN,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &AttributeSCfg{
Enabled: true,
ApierSConns: []string{},
ResourceSConns: []string{},
StatSConns: []string{},
StringIndexedFields: &[]string{utils.MetaReq + utils.NestingSep + utils.AccountField},
PrefixIndexedFields: &[]string{},
SuffixIndexedFields: &[]string{},
IndexedSelects: true,
AnyContext: true,
Opts: &AttributesOpts{
ProcessRuns: 1,
ProfileIDs: []string{},
},
}
if !reflect.DeepEqual(expAttr, cfg.AttributeSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.AttributeSCfg()))
}
}
func testCGRConfigReloadChargerSDryRun(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: ChargerSCfgJson,
DryRun: true,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
ecfg := NewDefaultCGRConfig()
if !reflect.DeepEqual(ecfg.ChargerSCfg(), cfg.ChargerSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(ecfg.ChargerSCfg()), utils.ToJSON(cfg.ChargerSCfg()))
}
}
func testCGRConfigReloadChargerS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: ChargerSCfgJson,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &ChargerSCfg{
Enabled: true,
StringIndexedFields: &[]string{utils.MetaReq + utils.NestingSep + utils.AccountField},
PrefixIndexedFields: &[]string{},
SuffixIndexedFields: &[]string{},
IndexedSelects: true,
AttributeSConns: []string{"*localhost"},
}
if !reflect.DeepEqual(expAttr, cfg.ChargerSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.ChargerSCfg()))
}
}
func testCGRConfigReloadThresholdS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: THRESHOLDS_JSON,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &ThresholdSCfg{
Enabled: true,
StringIndexedFields: &[]string{utils.MetaReq + utils.NestingSep + utils.AccountField},
PrefixIndexedFields: &[]string{},
SuffixIndexedFields: &[]string{},
IndexedSelects: true,
Opts: &ThresholdsOpts{
ProfileIDs: []string{},
},
}
if !reflect.DeepEqual(expAttr, cfg.ThresholdSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.ThresholdSCfg()))
}
}
func testCGRConfigReloadStatS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: STATS_JSON,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &StatSCfg{
Enabled: true,
StringIndexedFields: &[]string{utils.MetaReq + utils.NestingSep + utils.AccountField},
PrefixIndexedFields: &[]string{},
SuffixIndexedFields: &[]string{},
IndexedSelects: true,
ThresholdSConns: []string{utils.MetaLocalHost},
Opts: &StatsOpts{
ProfileIDs: []string{},
},
}
if !reflect.DeepEqual(expAttr, cfg.StatSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.StatSCfg()))
}
}
func testCGRConfigReloadResourceS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: RESOURCES_JSON,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &ResourceSConfig{
Enabled: true,
StringIndexedFields: &[]string{utils.MetaReq + utils.NestingSep + utils.AccountField},
PrefixIndexedFields: &[]string{},
SuffixIndexedFields: &[]string{},
IndexedSelects: true,
ThresholdSConns: []string{utils.MetaLocalHost},
Opts: &ResourcesOpts{
UsageID: utils.EmptyString,
Units: 1,
},
}
if !reflect.DeepEqual(expAttr, cfg.ResourceSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.ResourceSCfg()))
}
}
func testCGRConfigReloadSupplierS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: RouteSJson,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &RouteSCfg{
Enabled: true,
StringIndexedFields: &[]string{"*req.LCRProfile"},
PrefixIndexedFields: &[]string{utils.MetaReq + utils.NestingSep + utils.Destination},
SuffixIndexedFields: &[]string{},
ResourceSConns: []string{},
StatSConns: []string{},
AttributeSConns: []string{},
RALsConns: []string{},
IndexedSelects: true,
DefaultRatio: 1,
Opts: &RoutesOpts{
Context: utils.MetaRoutes,
IgnoreErrors: false,
MaxCost: utils.EmptyString,
},
}
if !reflect.DeepEqual(expAttr, cfg.RouteSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.RouteSCfg()))
}
}
func testCGRConfigV1ReloadConfigFromPathInvalidSection(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
expectedErr := "Invalid section: <InvalidSection>"
var reply string
if err := cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: "InvalidSection",
}, &reply); err == nil || err.Error() != expectedErr {
t.Errorf("Expected %+v. received %+v", expectedErr, err)
}
expectedErr = utils.NewErrMandatoryIeMissing("Path").Error()
if err := cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Section: "InvalidSection",
}, &reply); err == nil || err.Error() != expectedErr {
t.Errorf("Expected %+v. received %+v", expectedErr, err)
}
}
func testV1ReloadConfigFromPathConfigSanity(t *testing.T) {
expectedErr := "<AttributeS> not enabled but requested by <ChargerS> component"
var reply string
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
if err := cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutinternal"),
Section: ChargerSCfgJson}, &reply); err == nil || err.Error() != expectedErr {
t.Errorf("Expected %+v, received %+v", expectedErr, err)
}
}
func testLoadConfigFromHTTPValidURL(t *testing.T) {
cfg := NewDefaultCGRConfig()
url := "https://raw.githubusercontent.com/cgrates/cgrates/master/data/conf/samples/multifiles/a.json"
if err := cfg.loadConfigFromHTTP(url, nil); err != nil {
t.Error(err)
}
}
func testCGRConfigReloadSchedulerS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: SCHEDULER_JSN,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &SchedulerCfg{
Enabled: true,
CDRsConns: []string{utils.MetaLocalHost},
ThreshSConns: []string{},
StatSConns: []string{},
Filters: []string{},
DynaprepaidActionPlans: []string{},
}
if !reflect.DeepEqual(expAttr, cfg.SchedulerCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.SchedulerCfg()))
}
}
func testCGRConfigReloadCDRs(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.RalsCfg().Enabled = true
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: CDRS_JSN,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
rsr, err := NewRSRParsersFromSlice([]string{"~*req.PayPalAccount", "~*req.LCRProfile", "~*req.ResourceID"})
if err != nil {
t.Fatal(err)
}
expAttr := &CdrsCfg{
Enabled: true,
ExtraFields: rsr,
ChargerSConns: []string{utils.MetaLocalHost},
RaterConns: []string{},
AttributeSConns: []string{},
ThresholdSConns: []string{},
StatSConns: []string{},
SMCostRetries: 5,
StoreCdrs: true,
SchedulerConns: []string{},
EEsConns: []string{utils.MetaLocalHost},
}
if !reflect.DeepEqual(expAttr, cfg.CdrsCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.CdrsCfg()))
}
}
func testCGRConfigReloadRALs(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
blMap := cfg.RalsCfg().BalanceRatingSubject
maxComp := cfg.RalsCfg().MaxComputedUsage
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: RALS_JSN,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &RalsCfg{
Enabled: true,
RpSubjectPrefixMatching: false,
RemoveExpired: true,
MaxComputedUsage: maxComp,
BalanceRatingSubject: blMap,
ThresholdSConns: []string{utils.MetaLocalHost},
StatSConns: []string{utils.MetaLocalHost},
MaxIncrements: 1000000,
}
if !reflect.DeepEqual(expAttr, cfg.RalsCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.RalsCfg()))
}
}
func testCGRConfigReloadSessionS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.RalsCfg().Enabled = true
cfg.ChargerSCfg().Enabled = true
cfg.CdrsCfg().Enabled = true
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: SessionSJson,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &SessionSCfg{
Enabled: true,
ListenBijson: "127.0.0.1:2014",
ChargerSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)},
RALsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder)},
ResSConns: []string{utils.MetaLocalHost},
ThreshSConns: []string{},
StatSConns: []string{},
RouteSConns: []string{utils.MetaLocalHost},
AttrSConns: []string{utils.MetaLocalHost},
CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)},
ReplicationConns: []string{},
SessionIndexes: utils.StringSet{},
ClientProtocol: 1,
TerminateAttempts: 5,
AlterableFields: utils.NewStringSet([]string{}),
STIRCfg: &STIRcfg{
AllowedAttest: utils.NewStringSet([]string{utils.MetaAny}),
PayloadMaxduration: -1,
DefaultAttest: "A",
},
SchedulerConns: []string{},
DefaultUsage: map[string]time.Duration{
utils.MetaAny: 3 * time.Hour,
utils.MetaVoice: 3 * time.Hour,
utils.MetaData: 1048576,
utils.MetaSMS: 1,
},
}
if !reflect.DeepEqual(expAttr, cfg.SessionSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.SessionSCfg()))
}
}
func testCGRConfigReloadERs(t *testing.T) {
for _, dir := range []string{"/tmp/ers/in", "/tmp/ers/out"} {
if err := os.RemoveAll(dir); err != nil {
t.Fatal("Error removing folder: ", dir, err)
}
if err := os.MkdirAll(dir, 0755); err != nil {
t.Fatal("Error creating folder: ", dir, err)
}
}
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.SessionSCfg().Enabled = true
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "ers_example"),
Section: ERsJson,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
flags := utils.FlagsWithParamsFromSlice([]string{"*dryrun"})
flagsDefault := utils.FlagsWithParamsFromSlice([]string{})
content := []*FCTemplate{
{Tag: utils.ToR, Path: utils.MetaCgreq + utils.NestingSep + utils.ToR, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.2", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.OriginID, Path: utils.MetaCgreq + utils.NestingSep + utils.OriginID, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.3", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.RequestType, Path: utils.MetaCgreq + utils.NestingSep + utils.RequestType, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.4", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.Tenant, Path: utils.MetaCgreq + utils.NestingSep + utils.Tenant, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.6", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.Category, Path: utils.MetaCgreq + utils.NestingSep + utils.Category, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.7", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.AccountField, Path: utils.MetaCgreq + utils.NestingSep + utils.AccountField, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.8", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.Subject, Path: utils.MetaCgreq + utils.NestingSep + utils.Subject, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.9", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.Destination, Path: utils.MetaCgreq + utils.NestingSep + utils.Destination, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.10", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.SetupTime, Path: utils.MetaCgreq + utils.NestingSep + utils.SetupTime, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.11", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.AnswerTime, Path: utils.MetaCgreq + utils.NestingSep + utils.AnswerTime, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.12", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
{Tag: utils.Usage, Path: utils.MetaCgreq + utils.NestingSep + utils.Usage, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.13", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
}
for _, v := range content {
v.ComputePath()
}
expAttr := &ERsCfg{
Enabled: true,
SessionSConns: []string{utils.MetaLocalHost},
Readers: []*EventReaderCfg{
{
ID: utils.MetaDefault,
Type: utils.MetaNone,
RunDelay: 0,
ConcurrentReqs: 1024,
SourcePath: "/var/spool/cgrates/ers/in",
ProcessedPath: "/var/spool/cgrates/ers/out",
Filters: []string{},
Flags: flagsDefault,
Fields: content,
CacheDumpFields: []*FCTemplate{},
PartialCommitFields: []*FCTemplate{},
Opts: &EventReaderOpts{
CSV: &CSVROpts{
FieldSeparator: utils.StringPointer(utils.FieldsSep),
HeaderDefineChar: utils.StringPointer(utils.InInFieldSep),
RowLength: utils.IntPointer(0),
},
AMQP: &AMQPROpts{},
AWS: &AWSROpts{},
SQL: &SQLROpts{},
Kafka: &KafkaROpts{},
PartialOrderField: utils.StringPointer("~*req.AnswerTime"),
PartialCacheAction: utils.StringPointer(utils.MetaNone),
NATS: &NATSROpts{
Subject: utils.StringPointer("cgrates_cdrs"),
},
},
},
{
ID: "file_reader1",
Type: utils.MetaFileCSV,
RunDelay: -1,
ConcurrentReqs: 1024,
SourcePath: "/tmp/ers/in",
ProcessedPath: "/tmp/ers/out",
Filters: []string{},
Flags: flags,
Fields: content,
CacheDumpFields: []*FCTemplate{},
PartialCommitFields: []*FCTemplate{},
Opts: &EventReaderOpts{
CSV: &CSVROpts{
FieldSeparator: utils.StringPointer(utils.FieldsSep),
HeaderDefineChar: utils.StringPointer(utils.InInFieldSep),
RowLength: utils.IntPointer(0),
},
AMQP: &AMQPROpts{},
AWS: &AWSROpts{},
Kafka: &KafkaROpts{},
SQL: &SQLROpts{},
PartialOrderField: utils.StringPointer("~*req.AnswerTime"),
PartialCacheAction: utils.StringPointer(utils.MetaNone),
NATS: &NATSROpts{
Subject: utils.StringPointer("cgrates_cdrs"),
},
},
},
},
PartialCacheTTL: time.Second,
}
if !reflect.DeepEqual(expAttr, cfg.ERsCfg()) {
t.Errorf("Expected %s,\n received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.ERsCfg()))
}
}
func testCGRConfigReloadDNSAgent(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.SessionSCfg().Enabled = true
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "dnsagent_reload"),
Section: DNSAgentJson,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &DNSAgentCfg{
Enabled: true,
Listeners: []Listener{
{
Address: ":2053",
Network: "udp",
},
{
Address: ":2054",
Network: "tcp",
},
},
SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)},
// Timezone string
// RequestProcessors []*RequestProcessor
}
if !reflect.DeepEqual(expAttr, cfg.DNSAgentCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.DNSAgentCfg()))
}
}
func testCGRConfigReloadFreeswitchAgent(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.SessionSCfg().Enabled = true
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "freeswitch_reload"),
Section: FreeSWITCHAgentJSN,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &FsAgentCfg{
Enabled: true,
SessionSConns: []string{utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS)},
SubscribePark: true,
ExtraFields: RSRParsers{},
MaxWaitConnection: 2 * time.Second,
EventSocketConns: []*FsConnCfg{
{
Address: "1.2.3.4:8021",
Password: "ClueCon",
Reconnects: 5,
Alias: "1.2.3.4:8021",
},
},
}
if !reflect.DeepEqual(expAttr, cfg.FsAgentCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.FsAgentCfg()))
}
}
func testCgrCfgV1ReloadConfigSection(t *testing.T) {
for _, dir := range []string{"/tmp/ers/in", "/tmp/ers/out"} {
if err := os.RemoveAll(dir); err != nil {
t.Fatal("Error removing folder: ", dir, err)
}
if err := os.MkdirAll(dir, 0755); err != nil {
t.Fatal("Error creating folder: ", dir, err)
}
}
content := []any{
map[string]any{
"path": "*cgreq.ToR",
"mandatory": true,
"tag": "ToR",
"type": "*variable",
"value": "~*req.2",
},
map[string]any{
"path": "*cgreq.OriginID",
"mandatory": true,
"tag": "OriginID",
"type": "*variable",
"value": "~*req.3",
},
map[string]any{
"path": "*cgreq.RequestType",
"mandatory": true,
"tag": "RequestType",
"type": "*variable",
"value": "~*req.4",
},
map[string]any{
"path": "*cgreq.Tenant",
"mandatory": true,
"tag": "Tenant",
"type": "*variable",
"value": "~*req.6",
},
map[string]any{
"path": "*cgreq.Category",
"mandatory": true,
"tag": "Category",
"type": "*variable",
"value": "~*req.7",
},
map[string]any{
"path": "*cgreq.Account",
"mandatory": true,
"tag": "Account",
"type": "*variable",
"value": "~*req.8",
},
map[string]any{
"path": "*cgreq.Subject",
"mandatory": true,
"tag": "Subject",
"type": "*variable",
"value": "~*req.9",
},
map[string]any{
"path": "*cgreq.Destination",
"mandatory": true,
"tag": "Destination",
"type": "*variable",
"value": "~*req.10",
},
map[string]any{
"path": "*cgreq.SetupTime",
"mandatory": true,
"tag": "SetupTime",
"type": "*variable",
"value": "~*req.11",
},
map[string]any{
"path": "*cgreq.AnswerTime",
"mandatory": true,
"tag": "AnswerTime",
"type": "*variable",
"value": "~*req.12",
},
map[string]any{
"path": "*cgreq.Usage",
"mandatory": true,
"tag": "Usage",
"type": "*variable",
"value": "~*req.13",
},
}
expected := map[string]any{
"enabled": true,
"partial_cache_ttl": "1s",
"readers": []any{
map[string]any{
"id": utils.MetaDefault,
"cache_dump_fields": []any{},
"concurrent_requests": 1024,
"fields": content,
"filters": []string{},
"flags": []string{},
"run_delay": "0",
"source_path": "/var/spool/cgrates/ers/in",
"processed_path": "/var/spool/cgrates/ers/out",
"tenant": "",
"timezone": "",
"type": utils.MetaNone,
"opts": map[string]any{
"csvFieldSeparator": ",",
"csvHeaderDefineChar": ":",
"csvRowLength": 0.,
"partialOrderField": "~*req.AnswerTime",
"partialCacheAction": utils.MetaNone,
"natsSubject": "cgrates_cdrs",
},
"partial_commit_fields": []any{},
},
map[string]any{
"cache_dump_fields": []any{},
"concurrent_requests": 1024,
"filters": []string{},
"flags": []string{"*dryrun"},
"id": "file_reader1",
"processed_path": "/tmp/ers/out",
"run_delay": "-1",
"source_path": "/tmp/ers/in",
"tenant": "",
"timezone": "",
"type": "*file_csv",
"fields": content,
"opts": map[string]any{
"csvFieldSeparator": ",",
"csvHeaderDefineChar": ":",
"csvRowLength": 0.,
"partialOrderField": "~*req.AnswerTime",
"partialCacheAction": utils.MetaNone,
"natsSubject": "cgrates_cdrs",
},
"partial_commit_fields": []any{},
},
},
"sessions_conns": []string{
utils.MetaLocalHost,
},
}
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
var reply string
var rcv map[string]any
if err := cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: "/usr/share/cgrates/conf/samples/ers_example",
Section: ERsJson,
}, &reply); err != nil {
t.Fatal(err)
} else if reply != utils.OK {
t.Errorf("Expected: %s \n,received: %s", utils.OK, reply)
}
expected = map[string]any{
ERsJson: expected,
}
if err := cfg.V1GetConfig(context.Background(), &SectionWithAPIOpts{Section: ERsJson}, &rcv); err != nil {
t.Error(err)
} else if utils.ToJSON(expected) != utils.ToJSON(rcv) {
t.Errorf("Expected: %+v, \n received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
}
for _, dir := range []string{"/tmp/ers/in", "/tmp/ers/out"} {
if err := os.RemoveAll(dir); err != nil {
t.Fatal("Error removing folder: ", dir, err)
}
}
}
func testCGRConfigReloadConfigFromJSONSessionS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.RalsCfg().Enabled = true
cfg.ChargerSCfg().Enabled = true
cfg.CdrsCfg().Enabled = true
var reply string
if err = cfg.V1SetConfig(context.Background(),
&SetConfigArgs{
Config: map[string]any{
"sessions": map[string]any{
"enabled": true,
"resources_conns": []string{"*localhost"},
"routes_conns": []string{"*localhost"},
"attributes_conns": []string{"*localhost"},
"rals_conns": []string{"*internal"},
"cdrs_conns": []string{"*internal"},
"chargers_conns": []string{"*internal"},
},
},
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &SessionSCfg{
Enabled: true,
ListenBijson: "127.0.0.1:2014",
ChargerSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)},
RALsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder)},
ResSConns: []string{utils.MetaLocalHost},
ThreshSConns: []string{},
StatSConns: []string{},
RouteSConns: []string{utils.MetaLocalHost},
AttrSConns: []string{utils.MetaLocalHost},
CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)},
ReplicationConns: []string{},
SessionIndexes: utils.StringSet{},
ClientProtocol: 1,
TerminateAttempts: 5,
AlterableFields: utils.NewStringSet([]string{}),
STIRCfg: &STIRcfg{
AllowedAttest: utils.NewStringSet([]string{utils.MetaAny}),
PayloadMaxduration: -1,
DefaultAttest: "A",
},
SchedulerConns: []string{},
DefaultUsage: map[string]time.Duration{
utils.MetaAny: 3 * time.Hour,
utils.MetaVoice: 3 * time.Hour,
utils.MetaData: 1048576,
utils.MetaSMS: 1,
},
}
if !reflect.DeepEqual(expAttr, cfg.SessionSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.SessionSCfg()))
}
}
func testCGRConfigReloadConfigFromStringSessionS(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.RalsCfg().Enabled = true
cfg.ChargerSCfg().Enabled = true
cfg.CdrsCfg().Enabled = true
var reply string
if err = cfg.V1SetConfigFromJSON(context.Background(),
&SetConfigFromJSONArgs{
Config: `{
"sessions":{
"enabled": true,
"resources_conns": ["*localhost"],
"routes_conns": ["*localhost"],
"attributes_conns": ["*localhost"],
"rals_conns": ["*internal"],
"cdrs_conns": ["*internal"],
"chargers_conns": ["*localhost"]
}
}`}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &SessionSCfg{
Enabled: true,
ListenBijson: "127.0.0.1:2014",
ChargerSConns: []string{utils.MetaLocalHost},
RALsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder)},
ResSConns: []string{utils.MetaLocalHost},
ThreshSConns: []string{},
StatSConns: []string{},
RouteSConns: []string{utils.MetaLocalHost},
AttrSConns: []string{utils.MetaLocalHost},
CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)},
ReplicationConns: []string{},
SessionIndexes: utils.StringSet{},
ClientProtocol: 1,
TerminateAttempts: 5,
AlterableFields: utils.NewStringSet([]string{}),
STIRCfg: &STIRcfg{
AllowedAttest: utils.NewStringSet([]string{utils.MetaAny}),
PayloadMaxduration: -1,
DefaultAttest: "A",
},
SchedulerConns: []string{},
DefaultUsage: map[string]time.Duration{
utils.MetaAny: 3 * time.Hour,
utils.MetaVoice: 3 * time.Hour,
utils.MetaData: 1048576,
utils.MetaSMS: 1,
},
}
if !reflect.DeepEqual(expAttr, cfg.SessionSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.SessionSCfg()))
}
var rcv string
expected := `{"sessions":{"alterable_fields":[],"attributes_conns":["*localhost"],"cdrs_conns":["*internal"],"channel_sync_interval":"0","chargers_conns":["*localhost"],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":true,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":["*internal"],"replication_conns":[],"resources_conns":["*localhost"],"routes_conns":["*localhost"],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]}}`
if err := cfg.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: SessionSJson}, &rcv); err != nil {
t.Error(err)
} else if expected != rcv {
t.Errorf("Expected: %+q, \n received: %s", expected, rcv)
}
}
func testCGRConfigReloadAll(t *testing.T) {
cfg := NewDefaultCGRConfig()
for _, section := range sortedCfgSections {
cfg.rldChans[section] = make(chan struct{}, 1)
}
cfg.RalsCfg().Enabled = true
cfg.ChargerSCfg().Enabled = true
cfg.CdrsCfg().Enabled = true
var reply string
if err = cfg.V1ReloadConfig(context.Background(),
&ReloadArgs{
Path: path.Join("/usr", "share", "cgrates", "conf", "samples", "tutmongo2"),
Section: utils.MetaAll,
}, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Expected OK received: %s", reply)
}
expAttr := &SessionSCfg{
Enabled: true,
ListenBijson: "127.0.0.1:2014",
ChargerSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)},
RALsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder)},
ResSConns: []string{utils.MetaLocalHost},
ThreshSConns: []string{},
StatSConns: []string{},
RouteSConns: []string{utils.MetaLocalHost},
AttrSConns: []string{utils.MetaLocalHost},
CDRsConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)},
ReplicationConns: []string{},
SessionIndexes: utils.StringSet{},
ClientProtocol: 1,
TerminateAttempts: 5,
AlterableFields: utils.NewStringSet([]string{}),
STIRCfg: &STIRcfg{
AllowedAttest: utils.NewStringSet([]string{utils.MetaAny}),
PayloadMaxduration: -1,
DefaultAttest: "A",
},
SchedulerConns: []string{},
DefaultUsage: map[string]time.Duration{
utils.MetaAny: 3 * time.Hour,
utils.MetaVoice: 3 * time.Hour,
utils.MetaData: 1048576,
utils.MetaSMS: 1,
},
}
if !reflect.DeepEqual(expAttr, cfg.SessionSCfg()) {
t.Errorf("Expected %s , received: %s ", utils.ToJSON(expAttr), utils.ToJSON(cfg.SessionSCfg()))
}
}
func testHttpHandlerConfigSForNotExistFile(t *testing.T) {
cgrCfg.configSCfg.RootDir = "/usr/share/cgrates/"
req := httptest.NewRequest("GET", "http://127.0.0.1/conf/samples/NotExists/cgrates.json", nil)
w := httptest.NewRecorder()
HandlerConfigS(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
if resp.Status != "404 Not Found" {
t.Errorf("Expected %+v , received: %+v ", "200 OK", resp.Status)
}
httpBodyMsgError := "stat /usr/share/cgrates/conf/samples/NotExists/cgrates.json: no such file or directory"
if httpBodyMsgError != string(body) {
t.Errorf("Expected %s , received: %s ", httpBodyMsgError, string(body))
}
}
func testHandleConfigSFolderError(t *testing.T) {
flPath := "/usr/share/cgrates/conf/samples/NotExists/cgrates.json"
w := httptest.NewRecorder()
handleConfigSFolder(flPath, w)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
expected := "path:\"/usr/share/cgrates/conf/samples/NotExists/cgrates.json\" is not reachable"
if expected != string(body) {
t.Errorf("Expected %s , received: %s ", expected, string(body))
}
}
func testHttpHandlerConfigSInvalidPath(t *testing.T) {
cgrCfg.configSCfg.RootDir = "/usr/share/\x00/"
req := httptest.NewRequest("GET", "http://127.0.0.1/conf/samples/tutmysql/cgrates.json", nil)
w := httptest.NewRecorder()
HandlerConfigS(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
if resp.Status != "500 Internal Server Error" {
t.Errorf("Expected:%+v, received:%+v", "200 OK", resp.Status)
}
httpBodyMsgError := "stat /usr/share/\x00/conf/samples/tutmysql/cgrates.json: invalid argument"
if httpBodyMsgError != string(body) {
t.Errorf("Received:%q, expected:%q", string(body), httpBodyMsgError)
}
}
func testHttpHandlerConfigSForFile(t *testing.T) {
cgrCfg.configSCfg.RootDir = "/usr/share/cgrates/"
req := httptest.NewRequest("GET", "http://127.0.0.1/conf/samples/tutmysql/cgrates.json", nil)
w := httptest.NewRecorder()
HandlerConfigS(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
if resp.Status != "200 OK" {
t.Errorf("Expected %+v , received: %+v ", "200 OK", resp.Status)
}
if dat, err := os.ReadFile("/usr/share/cgrates/conf/samples/tutmysql/cgrates.json"); err != nil {
t.Error(err)
} else if string(dat) != string(body) {
t.Errorf("Expected %s , received: %s ", string(dat), string(body))
}
}
func testHttpHandlerConfigSForNotExistFolder(t *testing.T) {
cgrCfg.configSCfg.RootDir = "/usr/share/cgrates/"
req := httptest.NewRequest("GET", "http://127.0.0.1/conf/samples/NotExists/", nil)
w := httptest.NewRecorder()
HandlerConfigS(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
if resp.Status != "404 Not Found" {
t.Errorf("Expected %+v , received: %+v ", "200 OK", resp.Status)
}
httpBodyMsgError := "stat /usr/share/cgrates/conf/samples/NotExists: no such file or directory"
if httpBodyMsgError != string(body) {
t.Errorf("Expected %s , received: %s ", httpBodyMsgError, string(body))
}
}
func testHttpHandlerConfigSForFolder(t *testing.T) {
cgrCfg.configSCfg.RootDir = "/usr/share/cgrates/"
req := httptest.NewRequest("GET", "http://127.0.0.1/conf/samples/diamagent_internal/", nil)
w := httptest.NewRecorder()
HandlerConfigS(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
if resp.Status != "200 OK" {
t.Errorf("Expected %+v , received: %+v ", "200 OK", resp.Status)
}
cfg, err := NewCGRConfigFromPath("/usr/share/cgrates/conf/samples/diamagent_internal/")
if err != nil {
t.Error(err)
}
mp := cfg.AsMapInterface(cfg.generalCfg.RSRSep)
str := utils.ToJSON(mp)
// we compare the length of the string because flags is a map and we receive it in different order
if len(str) != len(string(body)) {
t.Errorf("Expected %s ,\n\n received: %s ", str, string(body))
}
}
func testLoadConfigFromFolderFileNotFound(t *testing.T) {
cfg := NewDefaultCGRConfig()
expected := "file </usr/share/cgrates/conf/samples/docker/cgrates.json>:NOT_FOUND:ENV_VAR:DOCKER_IP"
if err = cfg.loadConfigFromFolder("/usr/share/cgrates/conf/samples/",
[]func(jsonCfg *CgrJsonCfg) error{cfg.loadFromJSONCfg},
false); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
}
func testLoadConfigFromFolderOpenError(t *testing.T) {
newDir := "/tmp/testLoadConfigFromFolderOpenError"
if err = os.MkdirAll(newDir, 0755); err != nil {
t.Fatal(err)
}
cfg := NewDefaultCGRConfig()
expected := "open /tmp/testLoadConfigFromFolderOpenError/notes.json: no such file or directory"
if err = cfg.loadConfigFromFile(path.Join(newDir, "notes.json"),
[]func(jsonCfg *CgrJsonCfg) error{cfg.loadFromJSONCfg},
false); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
if err = os.RemoveAll(newDir); err != nil {
t.Fatal(err)
}
}
func testLoadConfigFromFolderNoConfigFound(t *testing.T) {
newDir := "/tmp/[]"
if err = os.MkdirAll(newDir, 0755); err != nil {
t.Fatal(err)
}
cfg := NewDefaultCGRConfig()
if err = cfg.loadConfigFromFolder(newDir,
[]func(jsonCfg *CgrJsonCfg) error{cfg.loadFromJSONCfg},
false); err == nil || err != filepath.ErrBadPattern {
t.Errorf("Expected %+v, received %+v", filepath.ErrBadPattern, err)
}
if err = os.RemoveAll(newDir); err != nil {
t.Fatal(err)
}
}
func testLoadConfigFromPathInvalidArgument(t *testing.T) {
cfg := NewDefaultCGRConfig()
expected := "stat /\x00: invalid argument"
if err = cfg.loadConfigFromPath("/\x00",
[]func(jsonCfg *CgrJsonCfg) error{cfg.loadFromJSONCfg},
false); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
}
func testLoadConfigFromPathValidPath(t *testing.T) {
newDir := "/tmp/testLoadConfigFromPathValidPath"
if err = os.MkdirAll(newDir, 0755); err != nil {
t.Fatal(err)
}
cfg := NewDefaultCGRConfig()
expected := "No config file found on path /tmp/testLoadConfigFromPathValidPath"
if err = cfg.loadConfigFromPath(newDir,
[]func(jsonCfg *CgrJsonCfg) error{cfg.loadFromJSONCfg},
false); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
if err = os.RemoveAll(newDir); err != nil {
t.Fatal(err)
}
}
func testLoadConfigFromPathFile(t *testing.T) {
newDir := "/tmp/testLoadConfigFromPathFile"
if err = os.MkdirAll(newDir, 0755); err != nil {
t.Fatal(err)
}
cfg := NewDefaultCGRConfig()
expected := "No config file found on path /tmp/testLoadConfigFromPathFile"
if err = cfg.loadConfigFromPath(newDir,
[]func(jsonCfg *CgrJsonCfg) error{cfg.loadFromJSONCfg},
false); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
if err = os.RemoveAll(newDir); err != nil {
t.Fatal(err)
}
}
func testHandleConfigSFilesError(t *testing.T) {
flPath := "/usr/share/cgrates/conf/samples/NotExists/cgrates.json"
w := httptest.NewRecorder()
handleConfigSFile(flPath, w)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
expected := "open /usr/share/cgrates/conf/samples/NotExists/cgrates.json: no such file or directory"
if expected != string(body) {
t.Errorf("Expected %s , received: %s ", expected, string(body))
}
}
func testHandleConfigSFileErrorWrite(t *testing.T) {
flPath := "/tmp/testHandleConfigSFilesErrorWrite"
if err := os.MkdirAll(flPath, 0777); err != nil {
t.Fatal(err)
}
newFile, err := os.Create(path.Join(flPath, "random.json"))
if err != nil {
t.Error(err)
}
newFile.Write([]byte(`{}`))
newFile.Close()
w := new(responseTest)
handleConfigSFile(path.Join(flPath, "random.json"), w)
if err = os.Remove(path.Join(flPath, "random.json")); err != nil {
t.Fatal(err)
}
if err = os.RemoveAll(flPath); err != nil {
t.Fatal(err)
}
}
func testHandleConfigSFolderErrorWrite(t *testing.T) {
flPath := "/tmp/testHandleConfigSFilesErrorWrite"
if err := os.MkdirAll(flPath, 0777); err != nil {
t.Fatal(err)
}
newFile, err := os.Create(path.Join(flPath, "random.json"))
if err != nil {
t.Error(err)
}
newFile.Write([]byte(`{}`))
newFile.Close()
w := new(responseTest)
handleConfigSFolder(flPath, w)
if err = os.Remove(path.Join(flPath, "random.json")); err != nil {
t.Fatal(err)
}
if err = os.RemoveAll(flPath); err != nil {
t.Fatal(err)
}
}
type responseTest struct{}
func (responseTest) Header() http.Header {
return nil
}
func (responseTest) Write(p []byte) (int, error) {
return 0, fmt.Errorf("Invalid section")
}
func (responseTest) WriteHeader(statusCode int) {}