diff --git a/loaders/lib_test.go b/loaders/lib_test.go
index 16aaf4aa6..b154f8dda 100644
--- a/loaders/lib_test.go
+++ b/loaders/lib_test.go
@@ -19,12 +19,19 @@ along with this program. If not, see
package loaders
import (
+ "encoding/csv"
"errors"
"flag"
+ "io/ioutil"
"net/rpc"
"net/rpc/jsonrpc"
+ "strings"
+ "testing"
+
+ "github.com/cgrates/rpcclient"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -49,3 +56,91 @@ func newRPCClient(cfg *config.ListenCfg) (c *rpc.Client, err error) {
return nil, errors.New("UNSUPPORTED_RPC")
}
}
+
+type testMockCacheConn struct {
+ calls map[string]func(arg interface{}, rply interface{}) error
+}
+
+func (s *testMockCacheConn) Call(method string, arg interface{}, rply interface{}) error {
+ if call, has := s.calls[method]; !has {
+ return rpcclient.ErrUnsupporteServiceMethod
+ } else {
+ return call(arg, rply)
+ }
+}
+
+func TestProcessContentCalls(t *testing.T) {
+ sMock := &testMockCacheConn{
+ calls: map[string]func(arg interface{}, rply interface{}) error{
+ utils.CacheSv1ReloadCache: func(arg interface{}, rply interface{}) error {
+ prply, can := rply.(*string)
+ if !can {
+ t.Errorf("Wrong argument type : %T", rply)
+ return nil
+ }
+ *prply = utils.OK
+ return nil
+ },
+ utils.CacheSv1Clear: func(arg interface{}, rply interface{}) error {
+ prply, can := rply.(*string)
+ if !can {
+ t.Errorf("Wrong argument type : %T", rply)
+ return nil
+ }
+ *prply = utils.OK
+ return nil
+ },
+ },
+ }
+ data := engine.NewInternalDB(nil, nil, true)
+
+ internalCacheSChan := make(chan rpcclient.ClientConnector, 1)
+ internalCacheSChan <- sMock
+ ldr := &Loader{
+ ldrID: "TestProcessContentCalls",
+ bufLoaderData: make(map[string][]LoaderData),
+ connMgr: engine.NewConnManager(config.CgrConfig(), map[string]chan rpcclient.ClientConnector{
+ utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches): internalCacheSChan,
+ }),
+ dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
+ cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
+ timezone: "UTC",
+ }
+ ldr.dataTpls = map[string][]*config.FCTemplate{
+ utils.MetaRateProfiles: {
+ {Tag: "TenantID",
+ Path: "Tenant",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.0", utils.INFIELD_SEP),
+ Mandatory: true},
+ {Tag: "ProfileID",
+ Path: "ID",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.1", utils.INFIELD_SEP),
+ Mandatory: true},
+ {Tag: "Weight",
+ Path: "Weight",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.2", utils.INFIELD_SEP)},
+ },
+ }
+ thresholdsCsv := `
+#Tenant[0],ID[1],Weight[2]
+cgrates.org,MOCK_RELOAD_ID,20
+`
+ rdr := ioutil.NopCloser(strings.NewReader(thresholdsCsv))
+ rdrCsv := csv.NewReader(rdr)
+ rdrCsv.Comment = '#'
+ ldr.rdrs = map[string]map[string]*openedCSVFile{
+ utils.MetaRateProfiles: {
+ utils.RateProfilesCsv: &openedCSVFile{
+ fileName: utils.RateProfilesCsv,
+ rdr: rdr,
+ csvRdr: rdrCsv,
+ },
+ },
+ }
+ if err := ldr.processContent(utils.MetaRateProfiles, utils.MetaReload); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/loaders/loader_it_test.go b/loaders/loader_it_test.go
index d8b0c7d28..b0bf6def0 100644
--- a/loaders/loader_it_test.go
+++ b/loaders/loader_it_test.go
@@ -20,12 +20,14 @@ along with this program. If not, see
package loaders
import (
+ "encoding/csv"
"io/ioutil"
"net/rpc"
"os"
"path"
"reflect"
"sort"
+ "strings"
"testing"
"time"
@@ -48,6 +50,9 @@ var (
testLoaderStartEngine,
testLoaderRPCConn,
testLoaderPopulateData,
+ testLoadFromFilesCsvActionProfile,
+ testLoadFromFilesCsvActionProfileOpenError,
+ testLoadFromFilesCsvActionProfileLockFolderError,
testLoaderLoadAttributes,
testLoaderVerifyOutDir,
testLoaderCheckAttributes,
@@ -399,3 +404,150 @@ func testLoaderVerifyOutDirForCustomSep(t *testing.T) {
t.Errorf("Expecting: %q, received: %q", customAttributes, string(outContent1))
}
}
+
+func testLoadFromFilesCsvActionProfile(t *testing.T) {
+ flPath := "/tmp/TestLoadFromFilesCsvActionProfile"
+ if err := os.MkdirAll(flPath, 0777); err != nil {
+ t.Error(err)
+ }
+ newFile, err := os.Create(path.Join(flPath, "ActionProfiles.csv"))
+ if err != nil {
+ t.Error(err)
+ }
+ newFile.Write([]byte(`
+#Tenant[0],ID[1]
+cgrates.org,SET_ACTPROFILE_3
+`))
+ content, err := ioutil.ReadFile(path.Join(flPath, "ActionProfiles.csv"))
+ if err != nil {
+ t.Error(err)
+ }
+ newFile.Close()
+
+ data := engine.NewInternalDB(nil, nil, true)
+ ldr := &Loader{
+ ldrID: "TestRemoveActionProfileContent",
+ bufLoaderData: make(map[string][]LoaderData),
+ dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
+ tpInDir: flPath,
+ tpOutDir: utils.EmptyString,
+ lockFilename: "ActionProfiles.csv",
+ fieldSep: ",",
+ timezone: "UTC",
+ }
+ ldr.dataTpls = map[string][]*config.FCTemplate{
+ utils.MetaActionProfiles: {
+ {Tag: "TenantID",
+ Path: "Tenant",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.0", utils.INFIELD_SEP),
+ Mandatory: true},
+ {Tag: "ProfileID",
+ Path: "ID",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.1", utils.INFIELD_SEP),
+ Mandatory: true},
+ },
+ }
+
+ rdr := ioutil.NopCloser(strings.NewReader(string(content)))
+ csvRdr := csv.NewReader(rdr)
+ csvRdr.Comment = '#'
+ ldr.rdrs = map[string]map[string]*openedCSVFile{
+ utils.MetaActionProfiles: {
+ utils.ActionProfilesCsv: &openedCSVFile{
+ fileName: utils.ActionProfilesCsv,
+ rdr: rdr,
+ csvRdr: csvRdr,
+ },
+ },
+ }
+ if err := ldr.ProcessFolder(utils.EmptyString, utils.MetaStore, true); err != nil {
+ t.Error(err)
+ }
+ expACtPrf := &engine.ActionProfile{
+ Tenant: "cgrates.org",
+ ID: "SET_ACTPROFILE_3",
+ FilterIDs: []string{},
+ Targets: map[string]utils.StringSet{},
+ Actions: []*engine.APAction{},
+ }
+ if rcv, err := ldr.dm.GetActionProfile(expACtPrf.Tenant, expACtPrf.ID,
+ true, true, utils.NonTransactional); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(expACtPrf, rcv) {
+ t.Errorf("Expected %+v, received %+v", utils.ToJSON(expACtPrf), utils.ToJSON(rcv))
+ }
+
+ //checking the error by adding a caching method
+ ldr.connMgr = engine.NewConnManager(config.NewDefaultCGRConfig(), nil)
+ ldr.cacheConns = []string{utils.MetaInternal}
+ rdr = ioutil.NopCloser(strings.NewReader(string(content)))
+ csvRdr = csv.NewReader(rdr)
+ csvRdr.Comment = '#'
+ ldr.rdrs = map[string]map[string]*openedCSVFile{
+ utils.MetaActionProfiles: {
+ utils.ActionProfilesCsv: &openedCSVFile{
+ fileName: utils.ActionProfilesCsv,
+ rdr: rdr,
+ csvRdr: csvRdr,
+ },
+ },
+ }
+ expected := "UNSUPPORTED_SERVICE_METHOD"
+ if err := ldr.ProcessFolder(utils.MetaReload, utils.MetaStore, true); err == nil || err.Error() != expected {
+ t.Error(err)
+ }
+
+ if err = os.RemoveAll(flPath); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testLoadFromFilesCsvActionProfileOpenError(t *testing.T) {
+ data := engine.NewInternalDB(nil, nil, true)
+ ldr := &Loader{
+ ldrID: "TestRemoveActionProfileContent",
+ bufLoaderData: make(map[string][]LoaderData),
+ dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
+ tpInDir: "/tmp/testLoadFromFilesCsvActionProfileOpenError",
+ timezone: "UTC",
+ }
+ ldr.rdrs = map[string]map[string]*openedCSVFile{
+ utils.MetaActionProfiles: {
+ utils.ActionProfilesCsv: &openedCSVFile{
+ fileName: utils.ActionProfilesCsv,
+ },
+ },
+ }
+ expectedErr := "open /tmp/testLoadFromFilesCsvActionProfileOpenError/ActionProfiles.csv: not a directory"
+ if err := ldr.ProcessFolder(utils.EmptyString, utils.MetaStore, true); err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+v, received %+v", expectedErr, err)
+ }
+
+ //if stopOnError is on true, the error is avoided,but instead will get a logger.warning message
+ if err := ldr.ProcessFolder(utils.EmptyString, utils.MetaStore, false); err != nil {
+ t.Error(err)
+ }
+}
+
+func testLoadFromFilesCsvActionProfileLockFolderError(t *testing.T) {
+ data := engine.NewInternalDB(nil, nil, true)
+ ldr := &Loader{
+ ldrID: "TestRemoveActionProfileContent",
+ bufLoaderData: make(map[string][]LoaderData),
+ dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
+ timezone: "UTC",
+ }
+ ldr.rdrs = map[string]map[string]*openedCSVFile{
+ utils.MetaActionProfiles: {
+ utils.ActionProfilesCsv: &openedCSVFile{
+ fileName: utils.ActionProfilesCsv,
+ },
+ },
+ }
+ expectedErr := "open : no such file or directory"
+ if err := ldr.ProcessFolder(utils.EmptyString, utils.MetaStore, true); err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+v, received %+v", expectedErr, err)
+ }
+}
diff --git a/loaders/loader_test.go b/loaders/loader_test.go
index b4acf3755..521f8b011 100644
--- a/loaders/loader_test.go
+++ b/loaders/loader_test.go
@@ -4088,3 +4088,107 @@ cgrates.org,REM_ACTPROFILE_1
t.Error(err)
}
}
+
+func TestRemoveContentError1(t *testing.T) {
+ //use actionProfile to generate an error by giving a wrong csv
+ data := engine.NewInternalDB(nil, nil, true)
+ ldr := &Loader{
+ ldrID: "TestRemoveActionProfileContent",
+ bufLoaderData: make(map[string][]LoaderData),
+ dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
+ timezone: "UTC",
+ }
+ ldr.dataTpls = map[string][]*config.FCTemplate{
+ utils.MetaActionProfiles: {
+ {Tag: "TenantID",
+ Path: "Tenant",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.0", utils.INFIELD_SEP),
+ Mandatory: true},
+ {Tag: "ProfileID",
+ Path: "ID",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.1", utils.INFIELD_SEP),
+ Mandatory: true},
+ },
+ }
+ //wrong start at the beginning of csv
+ actPrfCsv := `
+//Tenant[0]
+cgrates.org,REM_ACTPROFILE_s
+`
+ rdr := ioutil.NopCloser(strings.NewReader(actPrfCsv))
+ csvRdr := csv.NewReader(rdr)
+ csvRdr.Comment = '#'
+ ldr.rdrs = map[string]map[string]*openedCSVFile{
+ utils.MetaActionProfiles: {
+ utils.ActionProfilesCsv: &openedCSVFile{
+ fileName: utils.ActionProfilesCsv,
+ rdr: rdr,
+ csvRdr: csvRdr,
+ },
+ },
+ }
+ actRtPrf := &engine.ActionProfile{
+ Tenant: "cgrates.org",
+ ID: "REM_ACTPROFILE_s",
+ }
+ expectedErr := "NOT_FOUND"
+ if err := ldr.dm.SetActionProfile(actRtPrf, true); err != nil {
+ t.Error(err)
+ } else if err := ldr.removeContent(utils.MetaActionProfiles, utils.EmptyString); err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+v, received %+v", expectedErr, err)
+ }
+}
+
+func TestRemoveContentError2(t *testing.T) {
+ //use actionProfile to generate an error by giving a wrong csv
+ data := engine.NewInternalDB(nil, nil, true)
+ ldr := &Loader{
+ ldrID: "TestRemoveActionProfileContent",
+ bufLoaderData: make(map[string][]LoaderData),
+ dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
+ timezone: "UTC",
+ }
+ ldr.dataTpls = map[string][]*config.FCTemplate{
+ utils.MetaActionProfiles: {
+ {Tag: "TenantID",
+ Path: "Tenant",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.0", utils.INFIELD_SEP),
+ Mandatory: true},
+ {Tag: "ProfileID",
+ Path: "ID",
+ Type: utils.META_COMPOSED,
+ Value: config.NewRSRParsersMustCompile("~*req.1", utils.INFIELD_SEP),
+ Mandatory: true},
+ },
+ }
+ //wrong start at the beginning of csv
+ actPrfCsv := `
+Tenant[0],ID[1]
+cgrates.org,REM_ACTPROFILE_s
+`
+ rdr := ioutil.NopCloser(strings.NewReader(actPrfCsv))
+ csvRdr := csv.NewReader(rdr)
+ csvRdr.Comment = '#'
+ ldr.rdrs = map[string]map[string]*openedCSVFile{
+ utils.MetaActionProfiles: {
+ utils.ActionProfilesCsv: &openedCSVFile{
+ fileName: utils.ActionProfilesCsv,
+ rdr: rdr,
+ csvRdr: csvRdr,
+ },
+ },
+ }
+ actRtPrf := &engine.ActionProfile{
+ Tenant: "cgrates.org",
+ ID: "REM_ACTPROFILE_s",
+ }
+ expectedErr := "NOT_FOUND"
+ if err := ldr.dm.SetActionProfile(actRtPrf, true); err != nil {
+ t.Error(err)
+ } else if err := ldr.removeContent(utils.MetaActionProfiles, utils.EmptyString); err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+v, received %+v", expectedErr, err)
+ }
+}