diff --git a/actions/accounts_test.go b/actions/accounts_test.go
index 04428d290..9037dcdcf 100644
--- a/actions/accounts_test.go
+++ b/actions/accounts_test.go
@@ -66,7 +66,7 @@ func TestACExecuteAccountsSetBalance(t *testing.T) {
}
actCdrLG.config.ActionSCfg().AccountSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAccounts)}
- expected = "Closed unspilit syntax "
+ expected = "Closed unspilit syntax"
if err := actCdrLG.execute(context.Background(), dataStorage, utils.MetaBalanceLimit); err == nil || err.Error() != expected {
t.Errorf("Expected %+v, received %+v", expected, err)
}
diff --git a/config/rsrparser.go b/config/rsrparser.go
index 1a8543e48..4ba1c7d91 100644
--- a/config/rsrparser.go
+++ b/config/rsrparser.go
@@ -37,7 +37,7 @@ func NewRSRParsers(parsersRules string, rsrSeparator string) (prsrs RSRParsers,
return
}
if count := strings.Count(parsersRules, utils.RSRConstSep); count%2 != 0 { // check if we have matching `
- return nil, fmt.Errorf("Closed unspilit syntax ")
+ return nil, fmt.Errorf("Closed unspilit syntax")
} else if count != 0 {
var splitedRule []string
for idx := strings.IndexByte(parsersRules, utils.RSRConstChar); idx != -1; idx = strings.IndexByte(parsersRules, utils.RSRConstChar) {
diff --git a/console/loader_remove.go b/console/loader_remove.go
deleted file mode 100644
index 38117bc19..000000000
--- a/console/loader_remove.go
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-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
-*/
-
-package console
-
-import (
- "github.com/cgrates/cgrates/loaders"
- "github.com/cgrates/cgrates/utils"
-)
-
-func init() {
- c := &CmdLoaderRemove{
- name: "loader_remove",
- rpcMethod: utils.LoaderSv1Remove,
- rpcParams: &loaders.ArgsProcessFolder{},
- }
- commands[c.Name()] = c
- c.CommandExecuter = &CommandExecuter{c}
-}
-
-type CmdLoaderRemove struct {
- name string
- rpcMethod string
- rpcParams *loaders.ArgsProcessFolder
- *CommandExecuter
-}
-
-func (self *CmdLoaderRemove) Name() string {
- return self.name
-}
-
-func (self *CmdLoaderRemove) RpcMethod() string {
- return self.rpcMethod
-}
-
-func (self *CmdLoaderRemove) RpcParams(reset bool) interface{} {
- if reset || self.rpcParams == nil {
- self.rpcParams = &loaders.ArgsProcessFolder{}
- }
- return self.rpcParams
-}
-
-func (self *CmdLoaderRemove) PostprocessRpcParams() error {
- return nil
-}
-
-func (self *CmdLoaderRemove) RpcResult() interface{} {
- var s string
- return &s
-}
diff --git a/console/loader_load.go b/console/loader_run.go
similarity index 96%
rename from console/loader_load.go
rename to console/loader_run.go
index d8c9f3a96..fc71a5a39 100644
--- a/console/loader_load.go
+++ b/console/loader_run.go
@@ -25,8 +25,8 @@ import (
func init() {
c := &CmdLoaderLoad{
- name: "loader_load",
- rpcMethod: utils.LoaderSv1Load,
+ name: "loader_run",
+ rpcMethod: utils.LoaderSv1Run,
rpcParams: &loaders.ArgsProcessFolder{},
}
commands[c.Name()] = c
diff --git a/engine/model_helpers.go b/engine/model_helpers.go
index fac3d80a2..63272f0e4 100644
--- a/engine/model_helpers.go
+++ b/engine/model_helpers.go
@@ -1322,7 +1322,7 @@ func APItoModelTPCharger(tpCPP *utils.TPChargerProfile) (mdls ChargerMdls) {
return
}
-func APItoChargerProfile(tpCPP *utils.TPChargerProfile, timezone string) (cpp *ChargerProfile, err error) {
+func APItoChargerProfile(tpCPP *utils.TPChargerProfile, timezone string) (cpp *ChargerProfile) {
cpp = &ChargerProfile{
Tenant: tpCPP.Tenant,
ID: tpCPP.ID,
@@ -1337,7 +1337,7 @@ func APItoChargerProfile(tpCPP *utils.TPChargerProfile, timezone string) (cpp *C
for i, attribute := range tpCPP.AttributeIDs {
cpp.AttributeIDs[i] = attribute
}
- return cpp, nil
+ return cpp
}
func ChargerProfileToAPI(chargerPrf *ChargerProfile) (tpCharger *utils.TPChargerProfile) {
@@ -1519,7 +1519,7 @@ func APItoModelTPDispatcherProfile(tpDPP *utils.TPDispatcherProfile) (mdls Dispa
return
}
-func APItoDispatcherProfile(tpDPP *utils.TPDispatcherProfile, timezone string) (dpp *DispatcherProfile, err error) {
+func APItoDispatcherProfile(tpDPP *utils.TPDispatcherProfile, timezone string) (dpp *DispatcherProfile) {
dpp = &DispatcherProfile{
Tenant: tpDPP.Tenant,
ID: tpDPP.ID,
@@ -1560,7 +1560,7 @@ func APItoDispatcherProfile(tpDPP *utils.TPDispatcherProfile, timezone string) (
}
}
- return dpp, nil
+ return dpp
}
func DispatcherProfileToAPI(dpp *DispatcherProfile) (tpDPP *utils.TPDispatcherProfile) {
diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go
index f281a9c65..d0581d263 100644
--- a/engine/model_helpers_test.go
+++ b/engine/model_helpers_test.go
@@ -1334,9 +1334,7 @@ func TestAPItoChargerProfile(t *testing.T) {
AttributeIDs: []string{"ATTR1", "ATTR2"},
Weight: 20,
}
- if rcv, err := APItoChargerProfile(tpCPP, "UTC"); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(expected, rcv) {
+ if rcv := APItoChargerProfile(tpCPP, "UTC"); !reflect.DeepEqual(expected, rcv) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
}
}
@@ -1701,9 +1699,7 @@ func TestAPItoDispatcherProfile(t *testing.T) {
},
},
}
- if rcv, err := APItoDispatcherProfile(tpDPP, "UTC"); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(expected, rcv) {
+ if rcv := APItoDispatcherProfile(tpDPP, "UTC"); !reflect.DeepEqual(expected, rcv) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
}
}
@@ -3392,7 +3388,7 @@ func TestAPItoDispatcherProfileCase2(t *testing.T) {
},
},
}
- result, _ := APItoDispatcherProfile(structTest, "")
+ result := APItoDispatcherProfile(structTest, "")
if !reflect.DeepEqual(result, expStruct) {
t.Errorf("\nExpecting <%+v>>,\n Received <%+v>", utils.ToJSON(expStruct), utils.ToJSON(result))
}
@@ -4008,7 +4004,7 @@ func TestAPItoAttributeProfileError2(t *testing.T) {
}
_, err := APItoAttributeProfile(tpAlsPrf, "UTC")
- expected := "Closed unspilit syntax "
+ expected := "Closed unspilit syntax"
if err == nil || err.Error() != expected {
t.Errorf("\nExpecting <%+v>,\n Received <%+v>", expected, err)
}
diff --git a/engine/tpreader.go b/engine/tpreader.go
index d0b9713f7..0b0142720 100644
--- a/engine/tpreader.go
+++ b/engine/tpreader.go
@@ -486,10 +486,7 @@ func (tpr *TpReader) WriteToDatabase(verbose, disableReverse bool) (err error) {
log.Print("ChargerProfiles:")
}
for _, tpTH := range tpr.chargerProfiles {
- var th *ChargerProfile
- if th, err = APItoChargerProfile(tpTH, tpr.timezone); err != nil {
- return
- }
+ th := APItoChargerProfile(tpTH, tpr.timezone)
if err = tpr.dm.SetChargerProfile(context.TODO(), th, true); err != nil {
return
}
@@ -504,10 +501,7 @@ func (tpr *TpReader) WriteToDatabase(verbose, disableReverse bool) (err error) {
log.Print("DispatcherProfiles:")
}
for _, tpTH := range tpr.dispatcherProfiles {
- var th *DispatcherProfile
- if th, err = APItoDispatcherProfile(tpTH, tpr.timezone); err != nil {
- return
- }
+ th := APItoDispatcherProfile(tpTH, tpr.timezone)
if err = tpr.dm.SetDispatcherProfile(context.TODO(), th, true); err != nil {
return
}
diff --git a/engine/z_loader_it_test.go b/engine/z_loader_it_test.go
index b8b04ad52..ade73535c 100644
--- a/engine/z_loader_it_test.go
+++ b/engine/z_loader_it_test.go
@@ -324,10 +324,7 @@ func testLoaderITWriteToDatabase(t *testing.T) {
if err != nil {
t.Errorf("Failed GetChargerProfile, tenant: %s, id: %s, error: %s ", cpp.Tenant, cpp.ID, err.Error())
}
- cp, err := APItoChargerProfile(cpp, "UTC")
- if err != nil {
- t.Error(err)
- }
+ cp := APItoChargerProfile(cpp, "UTC")
if !reflect.DeepEqual(cp, rcv) {
t.Errorf("Expecting: %v, received: %v", cp, rcv)
}
@@ -338,10 +335,7 @@ func testLoaderITWriteToDatabase(t *testing.T) {
if err != nil {
t.Errorf("Failed GetDispatcherProfile, tenant: %s, id: %s, error: %s ", dpp.Tenant, dpp.ID, err.Error())
}
- dp, err := APItoDispatcherProfile(dpp, "UTC")
- if err != nil {
- t.Error(err)
- }
+ dp := APItoDispatcherProfile(dpp, "UTC")
if !reflect.DeepEqual(dp, rcv) {
t.Errorf("Expecting: %v, received: %v", dp, rcv)
}
diff --git a/loaders/csvreader.go b/loaders/csvreader.go
index 0c948ff15..46173b74f 100644
--- a/loaders/csvreader.go
+++ b/loaders/csvreader.go
@@ -44,14 +44,14 @@ func NewCSVReader(csvType, dPath, fn string, sep rune, nrFlds int) (CSVReader, e
case utils.MetaFileCSV:
return NewFileCSV(path.Join(dPath, fn), sep, nrFlds)
case utils.MetaUrl:
- return NewURLCSV(path.Join(dPath, fn), sep, nrFlds)
+ return NewURLCSV(strings.TrimSuffix(dPath, utils.Slash)+utils.Slash+fn, sep, nrFlds)
case utils.MetaGoogleAPI: // TODO: Implement *gapi
+ return nil, nil
case utils.MetaString:
return NewStringCSV(fn, sep, nrFlds)
default:
return nil, fmt.Errorf("unsupported CSVReader type: <%q>", csvType)
}
- return nil, nil
}
func NewCSVFile(rdr io.ReadCloser, path string, sep rune, nrFlds int) CSVReader {
diff --git a/loaders/csvreader_test.go b/loaders/csvreader_test.go
new file mode 100644
index 000000000..5f32c2c21
--- /dev/null
+++ b/loaders/csvreader_test.go
@@ -0,0 +1,173 @@
+/*
+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
+*/
+
+package loaders
+
+import (
+ "encoding/csv"
+ "fmt"
+ "io"
+ "math/rand"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "path"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "testing"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+func TestNewCSVStringReader(t *testing.T) {
+ data := `cgrates.org,ATTR_VARIABLE,,20,,*req.Category,*variable,~*req.ToR,`
+
+ expErrMsg := `unsupported CSVReader type: <"nonValidType">`
+ if _, err := NewCSVReader("nonValidType", utils.EmptyString, data, utils.CSVSep, -1); err == nil || err.Error() != expErrMsg {
+ t.Errorf("Expeceted: %v, received: %v", expErrMsg, err)
+ }
+ if np, err := NewCSVReader(utils.MetaGoogleAPI, utils.EmptyString, data, utils.CSVSep, -1); err != nil || np != nil { // for coverage (remove when implemented)
+ t.Error("This tipe should not be implemented yet")
+ }
+ csvR, err := NewCSVReader(utils.MetaString, utils.EmptyString, data, utils.CSVSep, -1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cls := io.NopCloser(strings.NewReader(data))
+ exp := &CSVFile{
+ path: data,
+ cls: cls,
+ csvRdr: csv.NewReader(cls),
+ }
+ exp.csvRdr.Comma = utils.CSVSep
+ exp.csvRdr.Comment = utils.CommentChar
+ exp.csvRdr.FieldsPerRecord = -1
+ exp.csvRdr.TrailingComma = true
+
+ if !reflect.DeepEqual(csvR, exp) {
+ t.Errorf("Expeceted: %+v, received: %+v", exp, csvR)
+ }
+ if p := csvR.Path(); p != data {
+ t.Errorf("Expeceted: %+v, received: %+v", data, p)
+ }
+
+ if p, err := csvR.Read(); err != nil {
+ t.Fatal(err)
+ } else if exp := strings.Split(data, ","); !reflect.DeepEqual(p, exp) {
+ t.Errorf("Expeceted: %+v, received: %+v", exp, p)
+ }
+
+ if err := csvR.Close(); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestNewCSVReaderErrors(t *testing.T) {
+ path := "TestNewCSVReaderErrors" + strconv.Itoa(rand.Int()) + utils.CSVSuffix
+ expErrMsg := fmt.Sprintf("open %s: no such file or directory", path)
+ if _, err := NewCSVReader(utils.MetaFileCSV, ".", path, utils.CSVSep, -1); err == nil || err.Error() != expErrMsg {
+ t.Errorf("Expeceted: %v, received: %v", expErrMsg, err)
+ }
+
+ expErrMsg = fmt.Sprintf("parse %q: invalid URI for request", "./"+path)
+ if _, err := NewCSVReader(utils.MetaUrl, ".", path, utils.CSVSep, -1); err == nil || err.Error() != expErrMsg {
+ t.Errorf("Expeceted: %v, received: %v", expErrMsg, err)
+ }
+
+ prePath := "http:/localhost:" + strconv.Itoa(rand.Int())
+ expErrMsg = fmt.Sprintf(`path:"%s/%s" is not reachable`, prePath, path)
+ if _, err := NewCSVReader(utils.MetaUrl, prePath, path, utils.CSVSep, -1); err == nil || err.Error() != expErrMsg {
+ t.Errorf("Expeceted: %q, received: %q", expErrMsg, err.Error())
+ }
+}
+
+func TestNewCSVURLReader(t *testing.T) {
+ data := `cgrates.org,ATTR_VARIABLE,,20,,*req.Category,*variable,~*req.ToR,`
+ mux := http.NewServeMux()
+ mux.Handle("/ok/", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.Write([]byte(data)) }))
+ s := httptest.NewServer(mux)
+ defer s.Close()
+ runtime.Gosched()
+
+ if _, err := NewCSVReader(utils.MetaUrl, s.URL+"/notFound", utils.AttributesCsv, utils.CSVSep, -1); err != utils.ErrNotFound {
+ t.Errorf("Expeceted: %v, received: %v", utils.ErrNotFound, err)
+ }
+
+ csvR, err := NewCSVReader(utils.MetaUrl, s.URL+"/ok", utils.AttributesCsv, utils.CSVSep, -1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expPath := s.URL + "/ok/" + utils.AttributesCsv
+ if p := csvR.Path(); p != expPath {
+ t.Errorf("Expeceted: %+v, received: %+v", data, expPath)
+ }
+
+ if p, err := csvR.Read(); err != nil {
+ t.Fatal(err)
+ } else if exp := strings.Split(data, ","); !reflect.DeepEqual(p, exp) {
+ t.Errorf("Expeceted: %+v, received: %+v", exp, p)
+ }
+
+ if err := csvR.Close(); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestNewCSVFileReader(t *testing.T) {
+ data := `cgrates.org,ATTR_VARIABLE,,20,,*req.Category,*variable,~*req.ToR,`
+ dir, err := os.MkdirTemp(utils.EmptyString, "TestNewCSVFileReader")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ fp := path.Join(dir, utils.AttributesCsv)
+ f, err := os.Create(fp)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err = f.WriteString(data); err != nil {
+ t.Fatal(err)
+ }
+ if err = f.Sync(); err != nil {
+ t.Fatal(err)
+ }
+ if err = f.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ csvR, err := NewCSVReader(utils.MetaFileCSV, dir, utils.AttributesCsv, utils.CSVSep, -1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p := csvR.Path(); p != fp {
+ t.Errorf("Expeceted: %+v, received: %+v", data, fp)
+ }
+
+ if p, err := csvR.Read(); err != nil {
+ t.Fatal(err)
+ } else if exp := strings.Split(data, ","); !reflect.DeepEqual(p, exp) {
+ t.Errorf("Expeceted: %+v, received: %+v", exp, p)
+ }
+
+ if err := csvR.Close(); err != nil {
+ t.Error(err)
+ }
+
+}
diff --git a/loaders/lib_test.go b/loaders/lib_test.go
deleted file mode 100644
index 98f38563a..000000000
--- a/loaders/lib_test.go
+++ /dev/null
@@ -1,926 +0,0 @@
-/*
-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
-*/
-
-package loaders
-
-import (
- "encoding/csv"
- "errors"
- "flag"
- "io"
- "strings"
- "testing"
-
- "github.com/cgrates/birpc"
- "github.com/cgrates/birpc/jsonrpc"
-
- "github.com/cgrates/birpc/context"
- "github.com/cgrates/rpcclient"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
- "github.com/cgrates/cgrates/utils"
-)
-
-var (
- waitRater = flag.Int("wait_rater", 200, "Number of miliseconds to wait for rater to start and cache")
- dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
- encoding = flag.String("rpc", utils.MetaJSON, "what encoding whould be used for rpc comunication")
- dbType = flag.String("dbtype", utils.MetaInternal, "The type of DataBase (Internal/Mongo/mySql)")
-)
-
-var loaderPaths = []string{"/tmp/In", "/tmp/Out", "/tmp/LoaderIn", "/tmp/SubpathWithoutMove",
- "/tmp/SubpathLoaderWithMove", "/tmp/SubpathOut", "/tmp/templateLoaderIn", "/tmp/templateLoaderOut",
- "/tmp/customSepLoaderIn", "/tmp/customSepLoaderOut"}
-
-func newRPCClient(cfg *config.ListenCfg) (c *birpc.Client, err error) {
- switch *encoding {
- case utils.MetaJSON:
- return jsonrpc.Dial(utils.TCP, cfg.RPCJSONListen)
- case utils.MetaGOB:
- return birpc.Dial(utils.TCP, cfg.RPCGOBListen)
- default:
- return nil, errors.New("UNSUPPORTED_RPC")
- }
-}
-
-type testMockCacheConn struct {
- calls map[string]func(_ *context.Context, _, _ interface{}) error
-}
-
-func (s *testMockCacheConn) Call(ctx *context.Context, method string, arg, rply interface{}) error {
- if call, has := s.calls[method]; !has {
- return rpcclient.ErrUnsupporteServiceMethod
- } else {
- return call(ctx, arg, rply)
- }
-}
-
-func TestProcessContentCallsLoadCache(t *testing.T) {
- sMock := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1LoadCache: func(_ *context.Context, _, rply interface{}) error {
- prply, can := rply.(*string)
- if !can {
- t.Errorf("Wrong argument type: %T", rply)
- }
- *prply = utils.OK
- return nil
- },
- utils.CacheSv1Clear: func(_ *context.Context, _, rply interface{}) error {
- prply, can := rply.(*string)
- if !can {
- t.Errorf("Wrong argument type : %T", rply)
- return nil
- }
- *prply = utils.OK
- return nil
- },
- },
- }
- internalCacheSChann := make(chan birpc.ClientConnector, 1)
- internalCacheSChann <- sMock
- data := engine.NewInternalDB(nil, nil, config.CgrConfig().DataDbCfg().Items)
- ldr := &Loader{
- ldrID: "TestProcessContentCallsLoadCache",
- bufLoaderData: make(map[string][]LoaderData),
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChann)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaRateProfiles: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- {Tag: "Weight",
- Path: "Weight",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)},
- },
- }
- ratePrfCsv := `
-#Tenant[0],ID[1],Weight[2]
-cgrates.org,MOCK_RELOAD_ID,20
-`
- rdr := io.NopCloser(strings.NewReader(ratePrfCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaRateProfiles: {
- utils.RatesCsv: &openedCSVFile{
- fileName: utils.RatesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- if err := ldr.processContent(context.Background(), utils.MetaRateProfiles, utils.MetaLoad); err != nil {
- t.Error(err)
- }
-
- // Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(ratePrfCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaRateProfiles: {
- utils.RatesCsv: &openedCSVFile{
- fileName: utils.RatesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.processContent(context.Background(), utils.MetaRateProfiles, utils.MetaLoad); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-}
-
-func TestProcessContentCallsReloadCache(t *testing.T) {
- // Clear cache because connManager sets the internal connection in cache
- engine.Cache.Clear([]string{utils.CacheRPCConnections})
-
- sMock2 := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1ReloadCache: func(_ *context.Context, _, 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(_ *context.Context, _, 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, config.CgrConfig().DataDbCfg().Items)
-
- internalCacheSChan := make(chan birpc.ClientConnector, 1)
- internalCacheSChan <- sMock2
- ldr := &Loader{
- ldrID: "TestProcessContentCalls",
- bufLoaderData: make(map[string][]LoaderData),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChan)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaRateProfiles: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- {Tag: "Weight",
- Path: "Weight",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)},
- },
- }
- ratePrfCsv := `
-#Tenant[0],ID[1],Weight[2]
-cgrates.org,MOCK_RELOAD_ID,20
-`
- rdr := io.NopCloser(strings.NewReader(ratePrfCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaRateProfiles: {
- utils.RatesCsv: &openedCSVFile{
- fileName: utils.RatesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- if err := ldr.processContent(context.Background(), utils.MetaRateProfiles, utils.MetaReload); err != nil {
- t.Error(err)
- }
-
- // Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(ratePrfCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaRateProfiles: {
- utils.RatesCsv: &openedCSVFile{
- fileName: utils.RatesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.processContent(context.Background(), utils.MetaRateProfiles, utils.MetaReload); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-}
-
-func TestProcessContentCallsRemoveItems(t *testing.T) {
- // Clear cache because connManager sets the internal connection in cache
- engine.Cache.Clear([]string{utils.CacheRPCConnections})
-
- sMock := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1RemoveItems: func(_ *context.Context, _, 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(_ *context.Context, _, 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, config.CgrConfig().DataDbCfg().Items)
-
- internalCacheSChan := make(chan birpc.ClientConnector, 1)
- internalCacheSChan <- sMock
- ldr := &Loader{
- ldrID: "TestProcessContentCallsRemoveItems",
- bufLoaderData: make(map[string][]LoaderData),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChan)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaAttributes: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- },
- }
- attributeCsv := `
-#Tenant[0],ID[1]
-cgrates.org,MOCK_RELOAD_ID
-`
- rdr := io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- if err := ldr.processContent(context.Background(), utils.MetaAttributes, utils.MetaRemove); err != nil {
- t.Error(err)
- }
-
- // Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.processContent(context.Background(), utils.MetaAttributes, utils.MetaRemove); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-
- // Calling the method again while caching method is invalid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- expected = "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.processContent(context.Background(), utils.MetaAttributes, "invalid_caching_api"); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-}
-
-func TestProcessContentCallsClear(t *testing.T) {
- // Clear cache because connManager sets the internal connection in cache
- engine.Cache.Clear([]string{utils.CacheRPCConnections})
-
- sMock := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1Clear: func(_ *context.Context, _, 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, config.CgrConfig().DataDbCfg().Items)
-
- internalCacheSChan := make(chan birpc.ClientConnector, 1)
- internalCacheSChan <- sMock
- ldr := &Loader{
- ldrID: "TestProcessContentCallsClear",
- bufLoaderData: make(map[string][]LoaderData),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChan)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaAttributes: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- },
- }
- attributeCsv := `
-#Tenant[0],ID[1]
-cgrates.org,MOCK_RELOAD_ID
-`
- rdr := io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- if err := ldr.processContent(context.Background(), utils.MetaAttributes, utils.MetaClear); err != nil {
- t.Error(err)
- }
-
- //inexisting method(*none) of cache and reinitialized the reader will do nothing
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- if err := ldr.processContent(context.Background(), utils.MetaAttributes, utils.MetaNone); err != nil {
- t.Error(err)
- }
-
- // Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.processContent(context.Background(), utils.MetaAttributes, utils.MetaClear); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-}
-
-func TestRemoveContentCallsReload(t *testing.T) {
- // Clear cache because connManager sets the internal connection in cache
- engine.Cache.Clear([]string{utils.CacheRPCConnections})
-
- sMock := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1ReloadCache: func(_ *context.Context, _, 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(_ *context.Context, _, 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, config.CgrConfig().DataDbCfg().Items)
-
- internalCacheSChan := make(chan birpc.ClientConnector, 1)
- internalCacheSChan <- sMock
- ldr := &Loader{
- ldrID: "TestRemoveContentCallsReload",
- bufLoaderData: make(map[string][]LoaderData),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChan)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaAttributes: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- },
- }
- attributeCsv := `
-#Tenant[0],ID[1]
-cgrates.org,MOCK_RELOAD_2
-`
- rdr := io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- attrPrf := &engine.AttributeProfile{
- Tenant: "cgrates.org",
- ID: "MOCK_RELOAD_2",
- }
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaReload); err != nil {
- t.Error(err)
- }
-
- //Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
-
- //set and remove again from database
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaReload); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-}
-
-func TestRemoveContentCallsLoad(t *testing.T) {
- // Clear cache because connManager sets the internal connection in cache
- engine.Cache.Clear([]string{utils.CacheRPCConnections})
-
- sMock := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1LoadCache: func(_ *context.Context, _, 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(_ *context.Context, _, 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, config.CgrConfig().DataDbCfg().Items)
-
- internalCacheSChan := make(chan birpc.ClientConnector, 1)
- internalCacheSChan <- sMock
- ldr := &Loader{
- ldrID: "TestRemoveContentCallsReload",
- bufLoaderData: make(map[string][]LoaderData),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChan)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaAttributes: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- },
- }
- attributeCsv := `
-#Tenant[0],ID[1]
-cgrates.org,MOCK_RELOAD_3
-`
- rdr := io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- attrPrf := &engine.AttributeProfile{
- Tenant: "cgrates.org",
- ID: "MOCK_RELOAD_3",
- }
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaLoad); err != nil {
- t.Error(err)
- }
-
- //Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
-
- //set and remove again from database
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaLoad); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-}
-
-func TestRemoveContentCallsRemove(t *testing.T) {
- // Clear cache because connManager sets the internal connection in cache
- engine.Cache.Clear([]string{utils.CacheRPCConnections})
-
- sMock := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1RemoveItems: func(_ *context.Context, _, 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(_ *context.Context, _, 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, config.CgrConfig().DataDbCfg().Items)
-
- internalCacheSChan := make(chan birpc.ClientConnector, 1)
- internalCacheSChan <- sMock
- ldr := &Loader{
- ldrID: "TestRemoveContentCallsReload",
- bufLoaderData: make(map[string][]LoaderData),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChan)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaAttributes: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- },
- }
- attributeCsv := `
-#Tenant[0],ID[1]
-cgrates.org,MOCK_RELOAD_4
-`
- rdr := io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- attrPrf := &engine.AttributeProfile{
- Tenant: "cgrates.org",
- ID: "MOCK_RELOAD_4",
- }
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaRemove); err != nil {
- t.Error(err)
- }
-
- //Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
-
- //set and remove again from database
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaRemove); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-
- //inexisting method(*none) of cache and reinitialized the reader will do nothing
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaNone); err != nil {
- t.Error(err)
- }
-}
-
-func TestRemoveContentCallsClear(t *testing.T) {
- // Clear cache because connManager sets the internal connection in cache
- engine.Cache.Clear([]string{utils.CacheRPCConnections})
-
- sMock := &testMockCacheConn{
- calls: map[string]func(_ *context.Context, _, _ interface{}) error{
- utils.CacheSv1Clear: func(_ *context.Context, _, 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, config.CgrConfig().DataDbCfg().Items)
-
- internalCacheSChan := make(chan birpc.ClientConnector, 1)
- internalCacheSChan <- sMock
- ldr := &Loader{
- ldrID: "TestRemoveContentCallsReload",
- bufLoaderData: make(map[string][]LoaderData),
- connMgr: engine.NewConnManager(config.CgrConfig()),
- cacheConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches)},
- dm: engine.NewDataManager(data, config.CgrConfig().CacheCfg(), nil),
- timezone: "UTC",
- }
- ldr.connMgr.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCaches), "", internalCacheSChan)
- ldr.dataTpls = map[string][]*config.FCTemplate{
- utils.MetaAttributes: {
- {Tag: "TenantID",
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {Tag: "ProfileID",
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- },
- }
- attributeCsv := `
-#Tenant[0],ID[1]
-cgrates.org,MOCK_RELOAD_3
-`
- rdr := io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv := csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- attrPrf := &engine.AttributeProfile{
- Tenant: "cgrates.org",
- ID: "MOCK_RELOAD_3",
- }
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaClear); err != nil {
- t.Error(err)
- }
-
- //Calling the method again while cacheConnsID is not valid
- ldr.cacheConns = []string{utils.MetaInternal}
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
-
- //set and remove again from database
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- expected := "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, utils.MetaClear); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-
- // Calling the method again while caching method is invalid
- rdr = io.NopCloser(strings.NewReader(attributeCsv))
- rdrCsv = csv.NewReader(rdr)
- rdrCsv.Comment = '#'
- ldr.rdrs = map[string]map[string]*openedCSVFile{
- utils.MetaAttributes: {
- utils.AttributesCsv: &openedCSVFile{
- fileName: utils.AttributesCsv,
- rdr: rdr,
- csvRdr: rdrCsv,
- },
- },
- }
- if err := ldr.dm.SetAttributeProfile(context.Background(), attrPrf, true); err != nil {
- t.Error(err)
- }
- expected = "UNSUPPORTED_SERVICE_METHOD"
- if err := ldr.removeContent(context.Background(), utils.MetaAttributes, "invalid_caching_api"); err == nil || err.Error() != expected {
- t.Errorf("Expected %+v, received %+v", expected, err)
- }
-}
diff --git a/loaders/libloader.go b/loaders/libloader.go
index 7f3530797..8382c15a1 100644
--- a/loaders/libloader.go
+++ b/loaders/libloader.go
@@ -39,31 +39,8 @@ func newRecord(ctx *context.Context, req utils.DataProvider, tmpls []*config.FCT
cfg: cfg.GetDataProvider(),
cache: cache,
}
- for _, fld := range tmpls {
- // Make sure filters are matching
- if len(fld.Filters) != 0 {
- if pass, err := filterS.Pass(ctx, tnt,
- fld.Filters, r); err != nil {
- return nil, err
- } else if !pass {
- continue // Not passes filters, ignore this CDR
- }
- }
-
- var out interface{}
- if out, err = engine.ParseAttribute(r, utils.FirstNonEmpty(fld.Type, utils.MetaVariable), utils.DynamicDataPrefix+fld.Path, fld.Value,
- cfg.GeneralCfg().RoundingDecimals, utils.FirstNonEmpty(fld.Timezone, cfg.GeneralCfg().DefaultTimezone), fld.Layout, cfg.GeneralCfg().RSRSep); err != nil {
- return
- }
- ps := fld.GetPathSlice()
- if fld.Type == utils.MetaComposed {
- if val, err := r.FieldAsString(ps); err == nil {
- out = utils.IfaceAsString(out) + val
- }
- }
- if err = r.Set(ps, out); err != nil {
- return
- }
+ if err = r.parseTemplates(ctx, tmpls, tnt, filterS, cfg.GeneralCfg().RoundingDecimals, cfg.GeneralCfg().DefaultTimezone, cfg.GeneralCfg().RSRSep); err != nil {
+ return
}
return r.data, nil
}
@@ -76,16 +53,46 @@ type record struct {
tntID *string
}
+func (r *record) parseTemplates(ctx *context.Context, tmpls []*config.FCTemplate, tnt string, filterS *engine.FilterS, rndDec int, dftTmz, rsrSep string) (err error) {
+ for _, fld := range tmpls {
+ // Make sure filters are matching
+ if len(fld.Filters) != 0 {
+ if pass, err := filterS.Pass(ctx, tnt,
+ fld.Filters, r); err != nil {
+ return err
+ } else if !pass {
+ continue // Not passes filters, ignore this CDR
+ }
+ }
+ var out interface{}
+ if out, err = engine.ParseAttribute(r, utils.FirstNonEmpty(fld.Type, utils.MetaVariable), utils.DynamicDataPrefix+fld.Path, fld.Value,
+ rndDec, utils.FirstNonEmpty(fld.Timezone, dftTmz), fld.Layout, rsrSep); err != nil {
+ return
+ }
+ ps := fld.GetPathSlice()
+ if fld.Type == utils.MetaComposed {
+ if val, err := r.FieldAsString(ps); err == nil {
+ out = utils.IfaceAsString(out) + val
+ }
+ }
+ if err = r.Set(ps, out); err != nil {
+ return
+ }
+ }
+ return
+}
+
func (r *record) String() string { return r.req.String() }
func (r *record) FieldAsInterface(path []string) (val interface{}, err error) {
switch path[0] {
- case utils.MetaCache:
- if path[1] == "*id" {
- path[1] = r.tenatID()
+ case utils.MetaUCH:
+ cp := strings.Join(path[1:], utils.NestingSep)
+ if path[1] == utils.MetaTntID {
+ cp = r.tenatID() + strings.TrimPrefix(cp, utils.MetaTntID)
}
var ok bool
- if val, ok = r.cache.Get(strings.Join(path[1:], utils.NestingSep)); !ok || val == nil {
+ if val, ok = r.cache.Get(cp); !ok || val == nil {
err = utils.ErrNotFound
}
return
@@ -108,11 +115,12 @@ func (r *record) FieldAsString(path []string) (str string, err error) {
func (r *record) Set(path []string, val interface{}) (err error) {
switch path[0] {
- case utils.MetaCache:
- if path[1] == "*id" {
- path[1] = r.tenatID()
+ case utils.MetaUCH:
+ cp := strings.Join(path[1:], utils.NestingSep)
+ if path[1] == utils.MetaTntID {
+ cp = r.tenatID() + strings.TrimPrefix(cp, utils.MetaTntID)
}
- r.cache.Set(strings.Join(path[1:], utils.NestingSep), val, nil)
+ r.cache.Set(cp, val, nil)
return
default:
return r.data.Set(path, val)
diff --git a/loaders/libloader_test.go b/loaders/libloader_test.go
index 08899ebe1..f92adc4d3 100644
--- a/loaders/libloader_test.go
+++ b/loaders/libloader_test.go
@@ -23,358 +23,116 @@ import (
"testing"
"github.com/cgrates/birpc/context"
-
- "github.com/cgrates/cgrates/engine"
-
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
+ "github.com/cgrates/ltcache"
)
-func TestDataUpdateFromCSVOneFile(t *testing.T) {
- attrSFlds := []*config.FCTemplate{
- {
- Path: "Tenant",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- {
- Path: "Contexts",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)},
- {
- Path: "FilterIDs",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.3", utils.InfieldSep)},
- {
- Path: "Weight",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.4", utils.InfieldSep)},
- {
- Path: "Path",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.5", utils.InfieldSep)},
- {
- Path: "Initial",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.6", utils.InfieldSep)},
- {
- Path: "Substitute",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.7", utils.InfieldSep)},
- {
- Path: "Append",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*req.8", utils.InfieldSep)},
- }
-
- rows := [][]string{
- {"cgrates.org", "ATTR_1", "*sessions;*cdrs", "*string:Account:1007", "10", "Account", "*any", "1001", "false"},
- {"cgrates.org", "ATTR_1", "", "", "", "Subject", "*any", "1001", "true"},
- }
- lData := make(LoaderData)
- if err := lData.UpdateFromCSV(context.Background(), "Attributes.csv", rows[0], attrSFlds,
- "cgrates.org", nil); err != nil {
- t.Error(err)
- }
- eLData := LoaderData{"Tenant": "cgrates.org",
- "ID": "ATTR_1",
- "Contexts": "*sessions;*cdrs",
- "FilterIDs": "*string:Account:1007",
- "Weight": "10",
- "Path": "Account",
- "Initial": "*any",
- "Substitute": "1001",
- "Append": "false",
- }
- if !reflect.DeepEqual(eLData, lData) {
- t.Errorf("expecting: %+v, received: %+v", eLData, lData)
- }
- lData = make(LoaderData)
- if err := lData.UpdateFromCSV(context.Background(), "Attributes.csv", rows[1], attrSFlds,
- "cgrates.org", nil); err != nil {
- t.Error(err)
- }
- eLData = LoaderData{"Tenant": "cgrates.org",
- "ID": "ATTR_1",
- "Contexts": "",
- "FilterIDs": "",
- "Weight": "",
- "Path": "Subject",
- "Initial": "*any",
- "Substitute": "1001",
- "Append": "true",
- }
- if !reflect.DeepEqual(eLData, lData) {
- t.Errorf("expecting: %+v, received: %+v", eLData, lData)
+func TestTenantIDFromMap(t *testing.T) {
+ exp := utils.NewTenantID("cgrates.org:ATTR1")
+ r := TenantIDFromMap(utils.MapStorage{
+ utils.Tenant: exp.Tenant,
+ utils.ID: exp.ID,
+ })
+ if !reflect.DeepEqual(r, exp) {
+ t.Errorf("Expected %+v, received %+q", exp, r)
}
}
-func TestDataUpdateFromCSVOneFile2(t *testing.T) {
- attrSFlds := []*config.FCTemplate{
- {
- Path: "Tenant",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
- Mandatory: true},
- {
- Path: "ID",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
- Mandatory: true},
- {
- Path: "Contexts",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep)},
- {
- Path: "FilterIDs",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.3", utils.InfieldSep)},
- {
- Path: "Weight",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.4", utils.InfieldSep)},
- {
- Path: "Path",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.5", utils.InfieldSep)},
- {
- Path: "Initial",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.6", utils.InfieldSep)},
- {
- Path: "Substitute",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.7", utils.InfieldSep)},
- {
- Path: "Append",
- Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.8", utils.InfieldSep)},
+func TestRateIDsFromMap(t *testing.T) {
+ expErrMsg := "cannot find RateIDs in map"
+ if _, err := RateIDsFromMap(utils.MapStorage{}); err == nil || err.Error() != expErrMsg {
+ t.Errorf("Expeceted: %v, received: %v", expErrMsg, err)
}
-
- rows := [][]string{
- {"cgrates.org", "ATTR_1", "*sessions;*cdrs", "*string:Account:1007", "10", "Account", "*any", "1001", "false"},
- {"cgrates.org", "ATTR_1", "", "", "", "Subject", "*any", "1001", "true"},
+ exp := []string{"RT1", "RT2"}
+ r, err := RateIDsFromMap(utils.MapStorage{
+ utils.RateIDs: "RT1;RT2",
+ })
+ if err != nil {
+ t.Fatal(err)
}
- lData := make(LoaderData)
- if err := lData.UpdateFromCSV(context.Background(), "Attributes.csv", rows[0], attrSFlds,
- "cgrates.org", nil); err != nil {
- t.Error(err)
- }
- eLData := LoaderData{"Tenant": "cgrates.org",
- "ID": "ATTR_1",
- "Contexts": "*sessions;*cdrs",
- "FilterIDs": "*string:Account:1007",
- "Weight": "10",
- "Path": "Account",
- "Initial": "*any",
- "Substitute": "1001",
- "Append": "false",
- }
- if !reflect.DeepEqual(eLData, lData) {
- t.Errorf("expecting: %+v, received: %+v", eLData, lData)
- }
- lData = make(LoaderData)
- if err := lData.UpdateFromCSV(context.Background(), "Attributes.csv", rows[1], attrSFlds,
- "cgrates.org", nil); err != nil {
- t.Error(err)
- }
- eLData = LoaderData{"Tenant": "cgrates.org",
- "ID": "ATTR_1",
- "Contexts": "",
- "FilterIDs": "",
- "Weight": "",
- "Path": "Subject",
- "Initial": "*any",
- "Substitute": "1001",
- "Append": "true",
- }
- if !reflect.DeepEqual(eLData, lData) {
- t.Errorf("expecting: %+v, received: %+v", eLData, lData)
+ if !reflect.DeepEqual(r, exp) {
+ t.Errorf("Expected %+v, received %+q", exp, r)
}
}
-func TestDataUpdateFromCSVMultiFiles(t *testing.T) {
- attrSFlds := []*config.FCTemplate{
- {
- Path: "Tenant",
- Type: utils.MetaString,
- Value: config.NewRSRParsersMustCompile("cgrates.org", utils.InfieldSep),
- Mandatory: true},
- {
- Path: "ID",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*file(File2.csv).1", utils.InfieldSep),
- Mandatory: true},
- {
- Path: "Contexts",
- Type: utils.MetaString,
- Value: config.NewRSRParsersMustCompile("*any", utils.InfieldSep)},
- {
- Path: "Path",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*file(File1.csv).5", utils.InfieldSep)},
- {
- Path: "Initial",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*file(File1.csv).6", utils.InfieldSep)},
- {
- Path: "Substitute",
- Type: utils.MetaComposed,
- Value: config.NewRSRParsersMustCompile("~*file(File1.csv).7", utils.InfieldSep)},
- {
- Path: "Append",
- Type: utils.MetaString,
- Value: config.NewRSRParsersMustCompile("true", utils.InfieldSep)},
- {
- Path: "Weight",
- Type: utils.MetaString,
- Value: config.NewRSRParsersMustCompile("10", utils.InfieldSep)},
- }
-
- loadRun1 := map[string][]string{
- "File1.csv": {"ignored", "ignored", "ignored", "ignored", "ignored", "Subject", "*any", "1001", "ignored", "ignored"},
- "File2.csv": {"ignored", "ATTR_1"},
- }
- lData := make(LoaderData)
- for fName, record := range loadRun1 {
- if err := lData.UpdateFromCSV(context.Background(), fName, record, attrSFlds,
- "cgrates.org", nil); err != nil {
- t.Error(err)
- }
- }
-
- eLData := LoaderData{"Tenant": "cgrates.org",
- "ID": "ATTR_1",
- "Contexts": "*any",
- "Path": "Subject",
- "Initial": "*any",
- "Substitute": "1001",
- "Append": "true",
- "Weight": "10",
- }
- if !reflect.DeepEqual(eLData, lData) {
- t.Errorf("expecting: %+v, received: %+v", eLData, lData)
- }
-}
-
-func TestGetRateIDsLoaderData(t *testing.T) {
- ldrData := LoaderData{
- "File1.csv": []string{"Subject", "*any", "1001"},
- }
- expected := "cannot find RateIDs in