diff --git a/ers/ers_it_test.go b/ers/ers_it_test.go
index 7d7a19804..929beea6a 100644
--- a/ers/ers_it_test.go
+++ b/ers/ers_it_test.go
@@ -20,8 +20,12 @@ along with this program. If not, see
package ers
import (
+ "bytes"
"errors"
+ "log"
+ "os"
"reflect"
+ "strings"
"testing"
"time"
@@ -758,3 +762,165 @@ func TestERsProcessEvent11(t *testing.T) {
t.Fatalf("\nExpecting <%+v>,\n Received <%+v>", "RALS_ERROR", err)
}
}
+
+func TestErsOnEvictedMetaDumpToFileOK(t *testing.T) {
+ dirPath := "/tmp/TestErsOnEvictedMetaDumpToFile"
+ err := os.Mkdir(dirPath, 0755)
+ if err != nil {
+ t.Error(err)
+ }
+ defer os.RemoveAll(dirPath)
+
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaDumpToFile,
+ utils.PartialPathOpt: dirPath,
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ data := engine.NewInternalDB(nil, nil, true)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrS := engine.NewFilterS(cfg, nil, dm)
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ filterS: fltrS,
+ }
+ erS.onEvicted("ID", value)
+
+ // rcv, err := os.ReadFile(filepath.Join(dirPath, "ID.*.*"))
+ // if err != nil {
+ // t.Error(err)
+ // }
+ // fmt.Println(rcv)
+}
+
+func TestErsOnEvictedMetaDumpToFileCSVWriteErr(t *testing.T) {
+ utils.Logger.SetLogLevel(3)
+ utils.Logger.SetSyslog(nil)
+
+ var buf bytes.Buffer
+ log.SetOutput(&buf)
+ defer func() {
+ log.SetOutput(os.Stderr)
+ }()
+
+ dirPath := "/tmp/TestErsOnEvictedMetaDumpToFile"
+ err := os.Mkdir(dirPath, 0755)
+ if err != nil {
+ t.Error(err)
+ }
+ defer os.RemoveAll(dirPath)
+
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaDumpToFile,
+ utils.PartialPathOpt: dirPath,
+ utils.PartialCSVFieldSepartorOpt: "\"",
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ data := engine.NewInternalDB(nil, nil, true)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrS := engine.NewFilterS(cfg, nil, dm)
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ filterS: fltrS,
+ }
+
+ erS.onEvicted("ID", value)
+
+ rcvLog := buf.String()[20:]
+ if !strings.Contains(rcvLog, "error: csv: invalid field or comment delimiter") {
+ t.Errorf("expected: <%s> to be included in log message: <%s>",
+ "error: csv: invalid field or comment delimiter", rcvLog)
+ }
+ utils.Logger.SetLogLevel(0)
+}
+
+func TestErsOnEvictedMetaDumpToFileCreateErr(t *testing.T) {
+ utils.Logger.SetLogLevel(3)
+ utils.Logger.SetSyslog(nil)
+
+ var buf bytes.Buffer
+ log.SetOutput(&buf)
+ defer func() {
+ log.SetOutput(os.Stderr)
+ }()
+
+ dirPath := "/tmp/TestErsOnEvictedMetaDumpToFile"
+ err := os.Mkdir(dirPath, 0755)
+ if err != nil {
+ t.Error(err)
+ }
+ defer os.RemoveAll(dirPath)
+
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaDumpToFile,
+ utils.PartialPathOpt: dirPath + "/non-existent",
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ data := engine.NewInternalDB(nil, nil, true)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrS := engine.NewFilterS(cfg, nil, dm)
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ filterS: fltrS,
+ }
+
+ erS.onEvicted("ID", value)
+
+ rcvLog := buf.String()[20:]
+ if !strings.Contains(rcvLog, "CGRateS <> [ERROR] Failed creating /tmp/TestErsOnEvictedMetaDumpToFile/non-existent/ID.") &&
+ !strings.Contains(rcvLog, "error: open /tmp/TestErsOnEvictedMetaDumpToFile/non-existent/ID.") {
+ t.Errorf("expected: <%s> and <%s> to be included in log message: <%s>",
+ "CGRateS <> [ERROR] Failed creating /tmp/TestErsOnEvictedMetaDumpToFile/non-existent/ID.",
+ "error: open /tmp/TestErsOnEvictedMetaDumpToFile/non-existent/ID.",
+ rcvLog)
+ }
+
+ utils.Logger.SetLogLevel(0)
+}
diff --git a/ers/ers_test.go b/ers/ers_test.go
index ccd321563..836a16f4f 100644
--- a/ers/ers_test.go
+++ b/ers/ers_test.go
@@ -19,10 +19,16 @@ along with this program. If not, see
package ers
import (
+ "bytes"
+ "log"
+ "os"
"reflect"
+ "strings"
"testing"
+ "time"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -60,3 +66,270 @@ func TestERsProcessPartialEvent(t *testing.T) {
}
}
}
+
+func TestErsOnEvictedNilValue(t *testing.T) {
+ cfg := config.NewDefaultCGRConfig()
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ }
+ erS.onEvicted("id", nil)
+
+ // Verification TBA
+}
+
+func TestErsOnEvictedMetaPostCDROK(t *testing.T) {
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ ProcessedPath: "/tmp",
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaPostCDR,
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ }
+ erS.onEvicted("id", value)
+
+ if len(erS.rdrEvents) != 1 {
+ t.Fatal("Expected channel to contain a value")
+ }
+ select {
+ case data := <-erS.rdrEvents:
+ if !reflect.DeepEqual(data.rdrCfg, value.rdrCfg) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ utils.ToJSON(value.rdrCfg), utils.ToJSON(data.rdrCfg))
+ }
+ if !reflect.DeepEqual(data.cgrEvent, value.events[0]) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ utils.ToJSON(value.events[0]), utils.ToJSON(data.cgrEvent))
+ }
+ case <-time.After(40 * time.Millisecond):
+ t.Error("Time limit exceeded")
+ }
+}
+
+func TestErsOnEvictedMetaPostCDRMergeErr(t *testing.T) {
+ utils.Logger.SetLogLevel(4)
+ utils.Logger.SetSyslog(nil)
+
+ var buf bytes.Buffer
+ log.SetOutput(&buf)
+ defer func() {
+ log.SetOutput(os.Stderr)
+ }()
+
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AnswerTime: time.Date(2021, 6, 1, 12, 0, 0, 0, time.UTC),
+ utils.AccountField: "1001",
+ utils.Destination: "1002",
+ },
+ },
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AnswerTime: time.Date(2021, 6, 1, 13, 0, 0, 0, time.UTC),
+ utils.AccountField: "1001",
+ utils.Destination: "1003",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ ProcessedPath: "/tmp",
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaPostCDR,
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ data := engine.NewInternalDB(nil, nil, true)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrS := engine.NewFilterS(cfg, nil, dm)
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ filterS: fltrS,
+ }
+ expLog := `[WARNING] failed posting expired parial events <[{"Tenant":"cgrates.org","ID":"EventErsOnEvicted","Time":null,"Event":{"Account":"1001","AnswerTime":"2021-06-01T13:00:00Z","Destination":"1003"},"APIOpts":null},{"Tenant":"cgrates.org","ID":"EventErsOnEvicted","Time":null,"Event":{"Account":"1001","AnswerTime":"2021-06-01T12:00:00Z","Destination":"1002"},"APIOpts":null}]> due error `
+ erS.onEvicted("id", value)
+ rcvLog := buf.String()[20:]
+ if !strings.Contains(rcvLog, expLog) {
+ t.Errorf("expected: <%+v> to be included in <%+v>", expLog, rcvLog)
+ }
+
+ utils.Logger.SetLogLevel(0)
+}
+
+func TestErsOnEvictedMetaDumpToFileSetFieldsErr(t *testing.T) {
+ utils.Logger.SetLogLevel(4)
+ utils.Logger.SetSyslog(nil)
+
+ var buf bytes.Buffer
+ log.SetOutput(&buf)
+ defer func() {
+ log.SetOutput(os.Stderr)
+ }()
+
+ dirPath := "/tmp/TestErsOnEvictedMetaDumpToFile"
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaDumpToFile,
+ utils.PartialPathOpt: dirPath,
+ },
+ CacheDumpFields: []*config.FCTemplate{
+ {
+ Tag: "cacheDump",
+ },
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ data := engine.NewInternalDB(nil, nil, true)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrS := engine.NewFilterS(cfg, nil, dm)
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ filterS: fltrS,
+ }
+ expLog := `[WARNING] Converting CDR with CGRID: to record , ignoring due to error: >
+`
+ erS.onEvicted("ID", value)
+
+ rcvLog := buf.String()[20:]
+ if !strings.Contains(rcvLog, expLog) {
+ t.Errorf("expected <%+v> to be included in: <%+v>", expLog, rcvLog)
+ }
+
+ utils.Logger.SetLogLevel(0)
+}
+
+func TestErsOnEvictedMetaDumpToFileMergeErr(t *testing.T) {
+ utils.Logger.SetLogLevel(4)
+ utils.Logger.SetSyslog(nil)
+
+ var buf bytes.Buffer
+ log.SetOutput(&buf)
+ defer func() {
+ log.SetOutput(os.Stderr)
+ }()
+
+ dirPath := "/tmp/TestErsOnEvictedMetaDumpToFile"
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AnswerTime: time.Date(2021, 6, 1, 12, 0, 0, 0, time.UTC),
+ utils.AccountField: "1001",
+ utils.Destination: "1002",
+ },
+ },
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AnswerTime: time.Date(2021, 6, 1, 13, 0, 0, 0, time.UTC),
+ utils.AccountField: "1001",
+ utils.Destination: "1003",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaDumpToFile,
+ utils.PartialPathOpt: dirPath,
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ data := engine.NewInternalDB(nil, nil, true)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrS := engine.NewFilterS(cfg, nil, dm)
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ filterS: fltrS,
+ }
+
+ expLog := `[WARNING] failed posting expired parial events <[{"Tenant":"cgrates.org","ID":"EventErsOnEvicted","Time":null,"Event":{"Account":"1001","AnswerTime":"2021-06-01T13:00:00Z","Destination":"1003"},"APIOpts":null},{"Tenant":"cgrates.org","ID":"EventErsOnEvicted","Time":null,"Event":{"Account":"1001","AnswerTime":"2021-06-01T12:00:00Z","Destination":"1002"},"APIOpts":null}]> due error
+`
+ erS.onEvicted("ID", value)
+
+ rcvLog := buf.String()[20:]
+ if !strings.Contains(rcvLog, expLog) {
+ t.Errorf("expected <%+v> to be included in: <%+v>", expLog, rcvLog)
+ }
+
+ utils.Logger.SetLogLevel(0)
+}
+
+func TestErsOnEvictedMetaDumpToFileEmptyPath(t *testing.T) {
+ value := &erEvents{
+ events: []*utils.CGREvent{
+ {
+ Tenant: "cgrates.org",
+ ID: "EventErsOnEvicted",
+ Event: map[string]interface{}{
+ utils.AccountField: "1001",
+ },
+ },
+ },
+ rdrCfg: &config.EventReaderCfg{
+ ID: "ER1",
+ Type: utils.MetaNone,
+ Opts: map[string]interface{}{
+ utils.PartialCacheActionOpt: utils.MetaDumpToFile,
+ },
+ },
+ }
+ cfg := config.NewDefaultCGRConfig()
+ data := engine.NewInternalDB(nil, nil, true)
+ dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
+ fltrS := engine.NewFilterS(cfg, nil, dm)
+ erS := &ERService{
+ cfg: cfg,
+ rdrEvents: make(chan *erEvent, 1),
+ filterS: fltrS,
+ }
+ erS.onEvicted("ID", value)
+
+ // Verification TBA
+}