/*
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 sessions

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"reflect"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/cgrates/birpc"
	"github.com/cgrates/birpc/context"
	"github.com/cgrates/cgrates/config"
	"github.com/cgrates/cgrates/engine"
	"github.com/cgrates/cgrates/utils"
	"github.com/cgrates/rpcclient"
)

func TestSetSTerminator(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().SessionTTL = time.Second
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	ss := new(Session)

	opts := engine.MapEvent{
		utils.OptsDebitInterval: "0s",
	}

	terminator := &sTerminator{
		ttl: cfg.SessionSCfg().SessionTTL,
	}
	sessions.setSTerminator(ss, opts)
	ss.sTerminator.timer = nil
	ss.sTerminator.endChan = nil
	if !reflect.DeepEqual(terminator, ss.sTerminator) {
		t.Errorf("Expected %+v, received %+v", terminator, ss.sTerminator)
	}

	opts = engine.MapEvent{
		utils.OptsSessionsTTL:          "1s",
		utils.OptsSessionsTTLMaxDelay:  "1s",
		utils.OptsSessionsTTLLastUsed:  "2s",
		utils.OptsSessionsTTLLastUsage: "0s",
		utils.OptsSessionsTTLUsage:     "5s",
	}
	ss.sTerminator = &sTerminator{
		timer: time.NewTimer(cfg.SessionSCfg().SessionTTL),
	}

	terminator = &sTerminator{
		ttl:          0,
		ttlLastUsed:  utils.DurationPointer(2 * time.Second),
		ttlUsage:     utils.DurationPointer(5 * time.Second),
		ttlLastUsage: utils.DurationPointer(0),
	}
	sessions.setSTerminator(ss, opts)
	ss.sTerminator.timer = nil
	ss.sTerminator.endChan = nil
	ss.sTerminator.ttl = 0
	if !reflect.DeepEqual(terminator, ss.sTerminator) {
		t.Errorf("Expected %+v, received %+v", terminator, ss.sTerminator)
	}

	ss.OptsStart = engine.MapEvent{
		utils.OptsSessionsTTL:          "1s",
		utils.OptsSessionsTTLMaxDelay:  "1s",
		utils.OptsSessionsTTLLastUsed:  "2s",
		utils.OptsSessionsTTLLastUsage: "0s",
		utils.OptsSessionsTTLUsage:     "5s",
	}
	ss.sTerminator = &sTerminator{
		timer: time.NewTimer(cfg.SessionSCfg().SessionTTL),
	}
	opts = engine.MapEvent{}
	sessions.setSTerminator(ss, opts)
	ss.sTerminator.timer = nil
	ss.sTerminator.endChan = nil
	ss.sTerminator.ttl = 0
	if !reflect.DeepEqual(terminator, ss.sTerminator) {
		t.Errorf("Expected %+v, received %+v", terminator, ss.sTerminator)
	}
}

func TestSetSTerminatorError(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().SessionTTL = time.Second
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	ss := &Session{}

	utils.Logger, err = utils.Newlogger(utils.MetaStdLog, utils.EmptyString)
	if err != nil {
		t.Error(err)
	}
	utils.Logger.SetLogLevel(7)

	buff := new(bytes.Buffer)
	log.SetOutput(buff)

	//Cannot set a terminate when ttl is 0
	ss.OptsStart = engine.MapEvent{
		utils.OptsSessionsTTL: "0s",
	}
	opts := engine.MapEvent{}
	sessions.setSTerminator(ss, opts)

	//Invalid format types for time duration
	ss.OptsStart = engine.MapEvent{
		utils.OptsSessionsTTL: "invalid_time_format",
	}
	sessions.setSTerminator(ss, opts)
	expected := "cannot extract <*sessionsTTL> for session:<>, from it's options: <{}>, err: <time: invalid duration \"invalid_time_format\">"
	if rcv := buff.String(); !strings.Contains(rcv, expected) {
		t.Errorf("Expected %+v, received %+v", expected, rcv)
	}

	buff = new(bytes.Buffer)
	log.SetOutput(buff)

	ss.OptsStart = engine.MapEvent{
		utils.OptsSessionsTTL:         "1s",
		utils.OptsSessionsTTLMaxDelay: "invalid_time_format",
	}
	sessions.setSTerminator(ss, opts)
	expected = "cannot extract <*sessionsTTLMaxDelay> for session:<>, from it's options: <{}>, err: <time: invalid duration \"invalid_time_format\">"
	if rcv := buff.String(); !strings.Contains(rcv, expected) {
		t.Errorf("Expected %+v, received %+v", expected, rcv)
	}

	buff = new(bytes.Buffer)
	log.SetOutput(buff)

	ss.OptsStart = engine.MapEvent{
		utils.OptsSessionsTTL:         "1s",
		utils.OptsSessionsTTLMaxDelay: "2s",
		utils.OptsSessionsTTLLastUsed: "invalid_time_format",
	}
	sessions.setSTerminator(ss, opts)
	expected = "cannot extract <*sessionsTTLLastUsed> for session:<>, from it's options: <{}>, err: <time: invalid duration \"invalid_time_format\">"
	if rcv := buff.String(); !strings.Contains(rcv, expected) {
		t.Errorf("Expected %+v, received %+v", expected, rcv)
	}

	buff = new(bytes.Buffer)
	log.SetOutput(buff)

	ss.OptsStart = engine.MapEvent{
		utils.OptsSessionsTTL:          "1s",
		utils.OptsSessionsTTLMaxDelay:  "2s",
		utils.OptsSessionsTTLLastUsed:  "1s",
		utils.OptsSessionsTTLLastUsage: "invalid_time_format",
	}
	sessions.setSTerminator(ss, opts)
	expected = "cannot extract <*sessionsTTLLastUsage> for session:<>, from it's options: <{}>, err: <time: invalid duration \"invalid_time_format\">"
	if rcv := buff.String(); !strings.Contains(rcv, expected) {
		t.Errorf("Expected %+v, received %+v", expected, rcv)
	}

	buff = new(bytes.Buffer)
	log.SetOutput(buff)

	cfg.SessionSCfg().SessionTTLMaxDelay = utils.DurationPointer(time.Second)
	sessions = NewSessionS(cfg, dm, nil)
	ss.OptsStart = engine.MapEvent{
		utils.OptsSessionsTTLLastUsed:  "1s",
		utils.OptsSessionsTTLLastUsage: "5s",
		utils.OptsSessionsTTLUsage:     "invalid_time_format",
	}
	sessions.setSTerminator(ss, opts)
	expected = "cannot extract <*sessionsTTLUsage> for session:<>, from it's options: <{}>, err: <time: invalid duration \"invalid_time_format\">"
	if rcv := buff.String(); !strings.Contains(rcv, expected) {
		t.Errorf("Expected %+v, received %+v", expected, rcv)
	}

	log.SetOutput(os.Stderr)
}

func TestSetSTerminatorAutomaticTermination(t *testing.T) {
	log.SetOutput(io.Discard)
	ss := &Session{}

	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	sessionTTL := 3 * time.Millisecond
	opts := engine.MapEvent{
		utils.OptsSessionsTTL:          sessionTTL.String(),
		utils.OptsSessionsTTLLastUsage: "0s",
	}

	tStart := time.Now()
	sessions.setSTerminator(ss, opts)
	ss.lk.RLock()
	done := ss.sTerminator.endChan
	ss.lk.RUnlock()
	select {
	case <-time.After(5 * time.Millisecond):
		t.Fatal("timeout waiting for terminator loop to end")
	case <-done:
		loopDur := time.Since(tStart)
		want := 3 * time.Millisecond
		if diff := loopDur - want; diff < 0 || diff > time.Millisecond {
			t.Errorf("sTerminator loop duration = %v, want at least %v (diff %v, margin 1ms)", loopDur, want, diff)
		}
	}
}

func TestSetSTerminatorManualTermination(t *testing.T) {
	log.SetOutput(io.Discard)
	ss := &Session{}

	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	opts := engine.MapEvent{
		utils.OptsSessionsTTL: "1s",
	}

	sessions.setSTerminator(ss, opts)
	ss.sTerminator.endChan <- struct{}{}
}

func TestForceSTerminatorManualTermination(t *testing.T) {
	log.SetOutput(io.Discard)
	ss := &Session{
		CGRID:         "CGRID",
		Tenant:        "cgrates.org",
		ResourceID:    "resourceID",
		ClientConnID:  "ClientConnID",
		EventStart:    engine.NewMapEvent(nil),
		DebitInterval: 18,
		SRuns: []*SRun{
			{Event: engine.NewMapEvent(nil),
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     2,
				TotalUsage:    3,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	expected := "MANDATORY_IE_MISSING: [connIDs]"
	if err := sessions.forceSTerminate(ss, time.Second, nil, nil, nil,
		map[string]any{utils.DisconnectCause: utils.ForcedDisconnect}); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, receive %+v", expected, err)
	}
}

func TestForceSTerminatorPostCDRs(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().CDRsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs): nil,
	})
	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPostpaid,
				},
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     2,
				TotalUsage:    3,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	expected := "INTERNALLY_DISCONNECTED"
	if err := sessions.forceSTerminate(ss, time.Second, nil, nil, nil,
		map[string]any{utils.DisconnectCause: utils.ForcedDisconnect}); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, receiveD %+v", expected, err)
	}
}

func TestForceSTerminatorReleaseSession(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): nil,
	})
	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		ResourceID: "resourceID",
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPostpaid,
				},
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     2,
				TotalUsage:    3,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		OptsStart:  engine.MapEvent{},
		Chargeable: true,
	}

	expected := "MANDATORY_IE_MISSING: [connIDs]"
	if err := sessions.forceSTerminate(ss, time.Second, nil, nil, nil,
		map[string]any{utils.DisconnectCause: utils.ForcedDisconnect}); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, receiveD %+v", expected, err)
	}
}

type testMockClientConn struct {
	*testRPCClientConnection
}

func (sT *testMockClientConn) Call(ctx *context.Context, method string, arg any, rply any) error {
	return utils.ErrNoActiveSession
}

func TestForceSTerminatorClientCall(t *testing.T) {
	log.SetOutput(io.Discard)
	sTestMock := &testMockClientConn{}

	cfg := config.NewDefaultCGRConfig()
	cfg.GeneralCfg().NodeID = "ClientConnID"
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): nil,
	})
	sessions := NewSessionS(cfg, dm, connMgr)
	sessions.RegisterIntBiJConn(sTestMock, utils.EmptyString)

	ss := &Session{
		CGRID:        "CGRID",
		Tenant:       "cgrates.org",
		EventStart:   engine.NewMapEvent(nil),
		ResourceID:   "resourceID",
		ClientConnID: "ClientConnID",
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPostpaid,
				},
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     2,
				TotalUsage:    3,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	expected := "MANDATORY_IE_MISSING: [connIDs]"
	if err := sessions.forceSTerminate(ss, time.Second, nil, nil, nil,
		map[string]any{utils.DisconnectCause: utils.ForcedDisconnect}); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
	time.Sleep(10 * time.Millisecond)
}

func TestDebitSession(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPostpaid,
				},
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     2,
				TotalUsage:    3,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	//RunIdx cannot be higher than the length of sessions runs
	expectedErr := "sRunIdx out of range"
	if _, err := sessions.debitSession(ss, 2, 0,
		utils.DurationPointer(time.Second)); err == nil || err.Error() != expectedErr {
		t.Errorf("Expected %+v, received %+v", expectedErr, err)
	}

	//debitReserve must be higher than 0
	if maxDur, err := sessions.debitSession(ss, 0, 0,
		utils.DurationPointer(0)); err != nil {
		t.Error(err)
	} else if maxDur != 0 {
		t.Errorf("Expected %+v, received %+v", 0, maxDur)
	}

	expectedErr = "MANDATORY_IE_MISSING: [connIDs]"
	if _, err := sessions.debitSession(ss, 0, 0,
		utils.DurationPointer(5*time.Second)); err == nil || err.Error() != expectedErr {
		t.Errorf("Expected %+v, received %+v", expectedErr, err)
	}
}

// mocking for
type testMockClients struct {
	calls map[string]func(args any, reply any) error
}

func (sT *testMockClients) Call(ctx *context.Context, method string, arg any, rply any) error {
	if call, has := sT.calls[method]; !has {
		return rpcclient.ErrUnsupporteServiceMethod
	} else {
		return call(arg, rply)
	}
}

func TestDebitSessionResponderMaxDebit(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				callCost := new(engine.CallCost)
				callCost.Timespans = []*engine.TimeSpan{
					{
						TimeStart: time.Date(2020, 07, 21, 5, 0, 0, 0, time.UTC),
						TimeEnd:   time.Date(2020, 07, 21, 10, 0, 0, 0, time.UTC),
					},
				}
				*(reply.(*engine.CallCost)) = *callCost
				return nil
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): sMock,
	})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPostpaid,
				},
				CD: &engine.CallDescriptor{
					Category:  "test",
					LoopIndex: 12,
				},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: time.Minute,
				LastUsage:     time.Minute,
				TotalUsage:    3 * time.Minute,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	if maxDur, err := sessions.debitSession(ss, 0, 5*time.Second,
		utils.DurationPointer(time.Second)); err != nil {
		t.Error(err)
	} else if maxDur != 5*time.Second {
		t.Errorf("Expected %+v, received %+v", time.Minute, maxDur)
	}

	ss.SRuns[0].EventCost = nil
	if _, err := sessions.debitSession(ss, 0, 5*time.Minute,
		utils.DurationPointer(time.Minute)); err != nil {
		t.Error(err)
	}

	if _, err := sessions.debitSession(ss, 0, 10*time.Hour,
		utils.DurationPointer(time.Hour)); err != nil {
		t.Error(err)
	}
}

func TestDebitSessionResponderMaxDebitError(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	sMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				return utils.ErrAccountNotFound
			},
			utils.SchedulerSv1ExecuteActionPlans: func(args any, reply any) error {
				return nil
			},
		},
	}

	internalRpcChan := make(chan birpc.ClientConnector, 1)
	internalRpcChan <- sMock
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	cfg.SessionSCfg().SchedulerConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):      internalRpcChan,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler): internalRpcChan})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaDynaprepaid,
				},
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     time.Minute,
				TotalUsage:    3 * time.Minute,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	if maxDur, err := sessions.debitSession(ss, 0, 5*time.Minute,
		utils.DurationPointer(time.Second)); err == nil || err != utils.ErrAccountNotFound {
		t.Errorf("Expected %+v, received %+v", utils.ErrAccountNotFound, err)
	} else if maxDur != 0 {
		t.Errorf("Expected %+v, received %+v", 0, maxDur)
	}

	engine.Cache.Clear(nil)
	sMock.calls[utils.SchedulerSv1ExecuteActionPlans] = func(args any, reply any) error {
		return utils.ErrNotImplemented
	}
	newInternalRpcChan := make(chan birpc.ClientConnector, 1)
	newInternalRpcChan <- sMock
	connMgr = engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):      internalRpcChan,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler): internalRpcChan})
	dm = engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions = NewSessionS(cfg, dm, connMgr)

	if maxDur, err := sessions.debitSession(ss, 0, 5*time.Minute,
		utils.DurationPointer(time.Second)); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	} else if maxDur != 0 {
		t.Errorf("Expected %+v, received %+v", 0, maxDur)
	}
}

func TestInitSessionDebitLoops(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	ss := &Session{
		CGRID:         "CGRID",
		Tenant:        "cgrates.org",
		EventStart:    engine.NewMapEvent(nil),
		DebitInterval: time.Minute,
		debitStop:     make(chan struct{}, 1),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPrepaid,
				},
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     time.Minute,
				TotalUsage:    3 * time.Minute,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	sessions.initSessionDebitLoops(ss)

	ss.debitStop = nil
	sessions.initSessionDebitLoops(ss)
}

type testMockClientConnDiscSess struct {
	*testRPCClientConnection
}

func (sT *testMockClientConnDiscSess) Call(ctx *context.Context, method string, arg any, rply any) error {
	return nil
}

func TestDebitLoopSessionErrorDebiting(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	cfg.GeneralCfg().NodeID = "ClientConnIdtest"
	cfg.SessionSCfg().TerminateAttempts = 1
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	cfg.SessionSCfg().SchedulerConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	ss := &Session{
		CGRID:         "CGRID",
		Tenant:        "cgrates.org",
		ClientConnID:  "ClientConnIdtest",
		EventStart:    engine.NewMapEvent(nil),
		DebitInterval: time.Minute,
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaDynaprepaid,
				},
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     time.Minute,
				TotalUsage:    3 * time.Minute,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	// session already closed
	_, err = sessions.debitLoopSession(ss, 0, time.Hour)
	if err != nil {
		t.Error(err)
	}

	ss.debitStop = make(chan struct{})
	engine.Cache.Clear(nil)
	sMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				return utils.ErrAccountNotFound
			},
			utils.SchedulerSv1ExecuteActionPlans: func(args any, reply any) error {
				return utils.ErrUnauthorizedDestination
			},
		},
	}
	internalRpcChan := make(chan birpc.ClientConnector, 1)
	internalRpcChan <- sMock
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):      internalRpcChan,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaScheduler): internalRpcChan})
	dm = engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions = NewSessionS(cfg, dm, connMgr)

	sTestMock := &testMockClientConnDiscSess{}
	sessions.RegisterIntBiJConn(sTestMock, utils.EmptyString)

	if _, err = sessions.debitLoopSession(ss, 0, time.Hour); err != nil {
		t.Error(err)
	}
}

func TestDebitLoopSession(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				callCost := new(engine.CallCost)
				callCost.Timespans = []*engine.TimeSpan{
					{
						TimeStart: time.Date(2020, 07, 21, 5, 0, 0, 0, time.UTC),
						TimeEnd:   time.Date(2020, 07, 21, 10, 0, 0, 0, time.UTC),
					},
				}
				*(reply.(*engine.CallCost)) = *callCost
				return nil
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): sMock,
	})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		debitStop:  make(chan struct{}),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPrepaid,
				},
				CD: &engine.CallDescriptor{
					Category:  "test",
					LoopIndex: 12,
				},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: time.Minute,
				LastUsage:     10 * time.Second,
				TotalUsage:    3 * time.Minute,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}
	go func() {
		time.Sleep(30 * time.Millisecond)
		ss.stopDebitLoops()
	}()
	if _, err := sessions.debitLoopSession(ss, 0, 10*time.Millisecond); err != nil {
		t.Error(err)
	}
}

func TestDebitLoopSessionFrcDiscLowerDbtInterval(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				callCost := new(engine.CallCost)
				callCost.Timespans = []*engine.TimeSpan{
					{
						TimeStart: time.Date(2020, 07, 21, 5, 0, 0, 0, time.UTC),
						TimeEnd:   time.Date(2020, 07, 21, 10, 0, 0, 0, time.UTC),
					},
				}
				*(reply.(*engine.CallCost)) = *callCost
				return nil
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): sMock,
	})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		debitStop:  make(chan struct{}),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPostpaid,
				},
				CD: &engine.CallDescriptor{
					Category:  "test",
					LoopIndex: 12,
				},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: time.Minute,
				LastUsage:     10 * time.Second,
				TotalUsage:    3 * time.Minute,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}
	close(ss.debitStop)
	if _, err := sessions.debitLoopSession(ss, 0, time.Second); err != nil {
		t.Error(err)
	}
}

/*
func TestDebitLoopSessionLowBalance(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				return nil
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	cfg.SessionSCfg().MinDurLowBalance = 1 * time.Second
	data := engine.NewInternalDB(nil, nil, true,cfg.DataDbCfg().Items)
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): sMock,
	})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:      "CGRID",
		Tenant:     "cgrates.org",
		EventStart: engine.NewMapEvent(nil),
		debitStop:  make(chan struct{}),
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.RequestType: utils.MetaPostpaid,
				},
				CD: &engine.CallDescriptor{
					Category:  "test",
					LoopIndex: 12,
				},
				EventCost:     nil, //without an EventCost
				ExtraDuration: 30 * time.Millisecond,
				LastUsage:     10 * time.Second,
				TotalUsage:    3 * time.Minute,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		chargeable: true,
	}

	sessions.cgrCfg.SessionSCfg().MinDurLowBalance = 10 * time.Second
	// will disconnect faster, MinDurLowBalance higher than the debit interval
	//go func() {
	if _, err := sessions.debitLoopSession(ss, 0, 50*time.Millisecond); err != nil {
		t.Error(err)
	}
	//}()
	//time.Sleep(1 * time.Second)
}
*/

func TestDebitLoopSessionWarningSessions(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				return nil
			},
			utils.ResourceSv1ReleaseResources: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	cfg.SessionSCfg().MinDurLowBalance = 1 * time.Second
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):      sMock,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): sMock})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:         "CGRID",
		Tenant:        "cgrates.org",
		ResourceID:    "resourceID",
		ClientConnID:  "ClientConnID",
		debitStop:     make(chan struct{}),
		EventStart:    engine.NewMapEvent(nil),
		DebitInterval: 18,
		OptsStart:     engine.MapEvent{},
		SRuns: []*SRun{
			{Event: engine.NewMapEvent(nil),
				CD:            &engine.CallDescriptor{Category: "test"},
				EventCost:     &engine.EventCost{CGRID: "testCGRID"},
				ExtraDuration: 1,
				LastUsage:     2,
				TotalUsage:    3,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	// will disconnect faster, MinDurLowBalance higher than the debit interval
	expected := "UNSUPPORTED_SERVICE_METHOD"
	if _, err := sessions.debitLoopSession(ss, 0, 2*time.Second); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
}

func TestDebitLoopSessionDisconnectSession(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderMaxDebit: func(args any, reply any) error {
				return nil
			},
			utils.ResourceSv1ReleaseResources: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.GeneralCfg().NodeID = "ClientConnID"
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	cfg.SessionSCfg().MinDurLowBalance = 1 * time.Second
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):      sMock,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): sMock})

	sessions := NewSessionS(cfg, dm, connMgr)

	sTestMock := &testMockClientConnDiscSess{}
	sessions.RegisterIntBiJConn(sTestMock, utils.EmptyString)

	ss := &Session{
		CGRID:         "CGRID",
		Tenant:        "cgrates.org",
		ResourceID:    "resourceID",
		ClientConnID:  "ClientConnID",
		debitStop:     make(chan struct{}),
		EventStart:    engine.NewMapEvent(nil),
		DebitInterval: 18,
		SRuns: []*SRun{
			{
				Event: engine.NewMapEvent(nil),
				CD:    &engine.CallDescriptor{},
				EventCost: &engine.EventCost{
					Usage: utils.DurationPointer(5 * time.Hour),
					Timings: engine.ChargedTimings{
						utils.MetaPause: &engine.ChargedTiming{},
					},
					RatingFilters: engine.RatingFilters{
						utils.MetaPause: engine.RatingMatchedFilters{},
					},
					Rating: engine.Rating{
						utils.MetaPause: &engine.RatingUnit{},
					},
					Rates: engine.ChargedRates{
						utils.MetaPause: engine.RateGroups{},
					},
					Charges: []*engine.ChargingInterval{
						{
							Increments: []*engine.ChargingIncrement{
								{},
							},
						},
					},
					Accounting: engine.Accounting{
						utils.MetaPause: &engine.BalanceCharge{},
					},
				},
				ExtraDuration: 1,
				LastUsage:     2,
				TotalUsage:    3,
				NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
			},
		},
		Chargeable: true,
	}

	// will disconnect faster
	if _, err := sessions.debitLoopSession(ss, 0, 2*time.Second); err != nil {
		t.Error(err)
	}
	ss.Chargeable = false

	//force disconnect
	go func() {
		if _, err := sessions.debitLoopSession(ss, 0, 2*time.Second); err != nil {
			t.Error(err)
		}
	}()
	ss.debitStop <- struct{}{}
}

func TestStoreSCost(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.CDRsV1StoreSessionCost: func(args any, reply any) error {
				return utils.ErrExists
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().CDRsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs): sMock})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:  "CGRID",
		Tenant: "cgrates.org",
		SRuns: []*SRun{
			{
				Event: engine.NewMapEvent(nil),
				CD: &engine.CallDescriptor{
					TimeStart: time.Date(2020, 07, 21, 10, 0, 0, 0, time.UTC),
					TimeEnd:   time.Date(2020, 07, 21, 12, 0, 0, 0, time.UTC),
				},
				EventCost: &engine.EventCost{
					Usage:          utils.DurationPointer(5 * time.Hour),
					Charges:        []*engine.ChargingInterval{},
					AccountSummary: &engine.AccountSummary{},
				},
			},
		},
		Chargeable: true,
	}

	expected := "cannot find last active ChargingInterval"
	if err := sessions.storeSCost(ss, 0); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
}

func TestRefundSession(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderRefundIncrements: func(args any, reply any) error {
				if args.(*engine.CallDescriptorWithAPIOpts).APIOpts != nil {
					return utils.ErrNotImplemented
				}
				acnt := &engine.Account{
					ID: "cgrates_test",
				}
				*reply.(*engine.Account) = *acnt
				return nil
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): sMock})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:  "CGRID",
		Tenant: "cgrates.org",
		SRuns: []*SRun{
			{
				Event: engine.NewMapEvent(nil),
				CD: &engine.CallDescriptor{
					TimeStart: time.Date(2020, 07, 21, 11, 0, 0, 0, time.UTC),
					TimeEnd:   time.Date(2020, 07, 21, 11, 0, 30, 0, time.UTC),
				},
			},
		},
		Chargeable: true,
	}

	expectedErr := "no event cost"
	//event Cost is empty
	if err := sessions.refundSession(ss, 0, 0); err == nil || err.Error() != expectedErr {
		t.Error(err)
	}

	//index run cannot be higher than the runs in sessions
	expectedErr = "sRunIdx out of range"
	if err := sessions.refundSession(ss, 1, 0); err == nil || err.Error() != expectedErr {
		t.Error(err)
	}

	ss.SRuns[0].EventCost = &engine.EventCost{
		AccountSummary: &engine.AccountSummary{},
		Usage:          utils.DurationPointer(30 * time.Second),
		Charges: []*engine.ChargingInterval{
			{
				RatingID: "21a5ab9",
				Increments: []*engine.ChargingIncrement{
					{
						Usage:          time.Duration(1 * time.Second),
						Cost:           0.005,
						AccountingID:   "44d6c02",
						CompressFactor: 30,
					},
				},
				CompressFactor: 1,
			},
		},
		Rating: map[string]*engine.RatingUnit{
			"21a5ab9": {},
		},
		Accounting: map[string]*engine.BalanceCharge{
			"44d6c02": {},
		},
	}

	//new EventCost will be empty
	if err := sessions.refundSession(ss, 0, 0); err != nil {
		t.Error(err)
	}

	expectedErr = "failed detecting last active ChargingInterval"
	if err := sessions.refundSession(ss, 0, 5*time.Minute); err == nil || err.Error() != expectedErr {
		t.Errorf("Expected %+v, received %+v", expectedErr, err)
	}

	if err := sessions.refundSession(ss, 0, time.Second); err != nil {
		t.Error(err)
	}

	//mocking an error for calling
	ss.OptsStart = engine.MapEvent{}
	if err := sessions.refundSession(ss, 0, 2); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	}

	//are are no increments to refund
	ss.OptsStart = nil
	ss.SRuns[0].EventCost.Charges[0].Increments[0] = &engine.ChargingIncrement{}
	ss.SRuns[0].CD.TimeStart = time.Date(2020, 07, 21, 11, 0, 30, 0, time.UTC)
	ss.SRuns[0].CD.TimeEnd = time.Date(2020, 07, 21, 11, 0, 30, 0, time.UTC)
	ss.SRuns[0].EventCost.Usage = utils.DurationPointer(2)
	if err := sessions.refundSession(ss, 0, 2); err != nil {
		t.Error(err)
	}
}

func TestRoundCost(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderRefundRounding: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): sMock})

	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		CGRID:  "CGRID",
		Tenant: "cgrates.org",
		SRuns: []*SRun{
			{
				EventCost: &engine.EventCost{
					AccountSummary: &engine.AccountSummary{},
					Usage:          utils.DurationPointer(30 * time.Second),
					Charges: []*engine.ChargingInterval{
						{
							RatingID: "21a5ab9",
							Increments: []*engine.ChargingIncrement{
								{
									Usage:          time.Duration(1 * time.Second),
									Cost:           0.005,
									AccountingID:   "44d6c02",
									CompressFactor: 30,
								},
								{
									Usage:          time.Duration(1 * time.Second),
									Cost:           0.010,
									AccountingID:   "7hslkif",
									CompressFactor: 50,
								},
							},
							CompressFactor: 1,
						},
					},
					Rating: map[string]*engine.RatingUnit{
						"21a5ab9":          {},
						utils.MetaRounding: {},
					},
					Accounting: map[string]*engine.BalanceCharge{
						"44d6c02": {
							RatingID: utils.MetaRounding,
						},
						"7hslkif": {
							RatingID: utils.MetaRounding,
						},
					},
				},
			},
		},
		Chargeable: true,
	}

	//mocking an error API Call
	if err := sessions.roundCost(ss, 0); err != utils.ErrNotImplemented || err == nil {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	}
}

func TestDisconnectSession(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	ss := &Session{
		ClientConnID: "test",
		EventStart:   make(map[string]any),
		SRuns: []*SRun{
			{
				TotalUsage: time.Minute,
			},
		},
		Chargeable: true,
	}

	sTestMock := &testMockClientConn{}
	sessions.RegisterIntBiJConn(sTestMock, utils.EmptyString)
	sessions.biJIDs["test"] = &biJClient{
		conn: sTestMock,
	}

	if err := sessions.disconnectSession(ss, utils.EmptyString); err == nil || err != utils.ErrNoActiveSession {
		t.Errorf("Expected %+v, received %+v", utils.ErrNoActiveSession, err)
	}

	sTestMock1 := &mockConnWarnDisconnect1{}
	sessions.RegisterIntBiJConn(sTestMock1, utils.EmptyString)
	sessions.biJIDs["test"] = &biJClient{
		conn: sTestMock1,
	}
	if err := sessions.disconnectSession(ss, utils.EmptyString); err != nil {
		t.Error(err)
	}
}

func TestReplicateSessions(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.SessionSv1SetPassiveSession: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}

	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator): sMock})

	sessions := NewSessionS(cfg, dm, connMgr)

	sessions.replicateSessions("test_session", false,
		[]string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)})
}

func TestNewSession(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				if args.(*utils.CGREvent).ID == utils.EmptyString {
					return utils.ErrNotImplemented
				}
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
		},
	}
	sMock := make(chan birpc.ClientConnector, 1)
	sMock <- testMock1
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): sMock})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)

	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEv := &utils.CGREvent{
		Tenant: "cgrates.org",
		ID:     "TEST_ID",
		Event: map[string]any{
			utils.Destination: "10",
		},
	}

	expectedErr := "ChargerS is disabled"
	if _, err := sessions.newSession(cgrEv, "resourceID", "clientConnID",
		time.Second, false, false); err == nil || err.Error() != expectedErr {
		t.Errorf("Expected %+v, received %+v", expectedErr, err)
	}

	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}

	expectedSess := &Session{
		CGRID:        "da39a3ee5e6b4b0d3255bfef95601890afd80709",
		Tenant:       "cgrates.org",
		ResourceID:   "resourceID",
		ClientConnID: "clientConnID",
		EventStart: map[string]any{
			utils.CGRID:       "da39a3ee5e6b4b0d3255bfef95601890afd80709",
			utils.Destination: "10",
		},
		DebitInterval: time.Second,
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.Destination: "10",
				},
				CD: &engine.CallDescriptor{
					CgrID:       "da39a3ee5e6b4b0d3255bfef95601890afd80709",
					Tenant:      "cgrates.org",
					Category:    "call",
					Destination: "10",
					ExtraFields: map[string]string{},
				},
			},
		},
		Chargeable: true,
	}
	if rcv, err := sessions.newSession(cgrEv, "resourceID", "clientConnID",
		time.Second, false, false); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(rcv, expectedSess) {
		t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expectedSess), utils.ToJSON(rcv))
	}

	//error in mocking the call from connMgr
	cgrEv.ID = utils.EmptyString
	if _, err := sessions.newSession(cgrEv, "resourceID", "clientConnID",
		time.Second, false, false); err == nil || err.Error() != utils.NewErrChargerS(utils.ErrNotImplemented).Error() {
		t.Errorf("Expected %+v, received %+v", utils.NewErrChargerS(utils.ErrNotImplemented), err)
	}

	sessions.aSessions = map[string]*Session{
		"da39a3ee5e6b4b0d3255bfef95601890afd80709": {},
	}
	//sessions already exists
	if _, err := sessions.newSession(cgrEv, "resourceID", "clientConnID",
		time.Second, false, false); err == nil || err.Error() != utils.ErrExists.Error() {
		t.Errorf("Expected %+v, received %+v", utils.ErrExists, err)
	}
}

func TestProcessChargerS(t *testing.T) {
	log.SetOutput(io.Discard)
	tmpCache := engine.Cache

	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheEventCharges].Limit = -1
	sMock := make(chan birpc.ClientConnector, 1)
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): sMock})
	idb, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(idb, cfg.CacheCfg(), connMgr)
	engine.Cache = engine.NewCacheS(cfg, dm, nil)
	engine.Cache.Clear(nil)
	testMock1 := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				return utils.ErrExists
			},
			utils.CacheSv1ReplicateSet: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	sMock <- testMock1

	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEv := &utils.CGREvent{
		Tenant: "cgrates.org",
		ID:     "TEST_ID",
		Event: map[string]any{
			utils.Destination: "10",
		},
	}

	expected := "CHARGERS_ERROR:MANDATORY_IE_MISSING: [connIDs]"
	if _, err := sessions.processChargerS(cgrEv); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	if _, err := sessions.processChargerS(cgrEv); err != nil {
		t.Error(err)
	}

	engine.Cache.Clear(nil)
	cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.CacheCfg().Partitions[utils.CacheEventCharges] = &config.CacheParamCfg{
		Replicate: true,
	}
	cacheS := engine.NewCacheS(cfg, nil, nil)
	engine.Cache = cacheS
	connMgr = engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator): sMock})
	engine.SetConnManager(connMgr)

	if _, err := sessions.processChargerS(cgrEv); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	}

	engine.Cache = tmpCache
}

func TestTransitSState(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)

	sessions := NewSessionS(cfg, dm, nil)

	rcv := sessions.transitSState("test", true)
	if rcv != nil {
		t.Error("Expected to be nil")
	}

	sessions.pSessions = map[string]*Session{
		"test": {
			CGRID: "TEST_CGRID",
		},
	}

	rcv = sessions.getActivateSession("test")
	expected := &Session{
		CGRID:     "TEST_CGRID",
		UpdatedAt: rcv.UpdatedAt,
	}
	if !reflect.DeepEqual(rcv, expected) {
		t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
	}
}

func TestRelocateSession(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)

	sessions := NewSessionS(cfg, dm, nil)

	if rcv := sessions.relocateSession(utils.EmptyString, "222", "127.0.0.1"); rcv != nil {
		t.Errorf("Expected to be nil")
	}

	sessions.cgrCfg.SessionSCfg().SessionIndexes = map[string]struct{}{}
	sessions.aSessions = map[string]*Session{
		"0d0fe8779b54c88f121e26c5d83abee5935127e5": {
			CGRID:      "TEST_CGRID",
			EventStart: map[string]any{},
			SRuns: []*SRun{
				{
					Event: map[string]any{},
				},
			},
		},
	}
	rcv := sessions.relocateSession("111", "222", "127.0.0.1")
	expected := &Session{
		CGRID: "dfa2adaa5ab49349777c1ab3bcf3455df0259880",
		EventStart: map[string]any{
			utils.CGRID:    "dfa2adaa5ab49349777c1ab3bcf3455df0259880",
			utils.OriginID: "222",
		},
		SRuns: []*SRun{
			{
				Event: map[string]any{
					utils.CGRID:    "dfa2adaa5ab49349777c1ab3bcf3455df0259880",
					utils.OriginID: "222",
				},
			},
		},
		UpdatedAt: rcv.UpdatedAt,
	}
	if !reflect.DeepEqual(rcv, expected) {
		t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
	}

	sessions.pSessions = map[string]*Session{
		"0d0fe8779b54c88f121e26c5d83abee5935127e5": nil,
	}

	rcv = sessions.relocateSession("111", "222", utils.EmptyString)
	if rcv != nil {
		t.Errorf("Expected to be nil")
	}
}

func TestGetRelocateSession(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)

	sessions := NewSessionS(cfg, dm, nil)

	rcv := sessions.getRelocateSession("test", "111", "222", "127.0.0.1")
	if rcv != nil {
		t.Errorf("Expected to be nil")
	}

	sessions.pSessions = map[string]*Session{
		"test": {
			CGRID: "TEST_CGRID",
		},
	}

	rcv = sessions.getRelocateSession("test", utils.EmptyString, "222", "127.0.0.1")
	expected := &Session{
		CGRID:     "TEST_CGRID",
		UpdatedAt: rcv.UpdatedAt,
	}
	if !reflect.DeepEqual(rcv, expected) {
		t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
	}
}

func TestLibsessionsSetMockErrors(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	sTestMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.CacheSv1ReplicateSet: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- sTestMock
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.CacheCfg().Partitions[utils.CacheSTIR] = &config.CacheParamCfg{
		Replicate: true,
	}
	cacheS := engine.NewCacheS(cfg, nil, nil)
	engine.Cache = cacheS
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator): chanInternal})
	engine.SetConnManager(connMgr)

	procIndt, err := NewProcessedIdentity("eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly93d3cuZXhhbXBsZS5vcmcvY2VydC5jZXIifQ.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMDAyIl19LCJpYXQiOjE1ODcwMTk4MjIsIm9yaWciOnsidG4iOiIxMDAxIn0sIm9yaWdpZCI6IjEyMzQ1NiJ9.4ybtWmgqdkNyJLS9Iv3PuJV8ZxR7yZ_NEBhCpKCEu2WBiTchqwoqoWpI17Q_ALm38tbnpay32t95ZY_LhSgwJg;info=<https://www.example.org/cert.cer>;ppt=shaken")
	if err != nil {
		t.Error(err)
	}
	if err := procIndt.VerifySignature(cfg.GeneralCfg().ReplyTimeout); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	}

	procIndt.Header.X5u = "https://raw.githubusercontent.com/cgrates/cgrates/master/data/stir/stir_pubkey.pem"
	if err := procIndt.VerifySignature(cfg.GeneralCfg().ReplyTimeout); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	}

	if _, err := NewSTIRIdentity(procIndt.Header, procIndt.Payload, "https://raw.githubusercontent.com/cgrates/cgrates/master/data/stir/stir_privatekey.pem",
		-1); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	}

	if _, err := NewSTIRIdentity(procIndt.Header, procIndt.Payload, "https://raw.githubusercontent.com/cgrates/cgrates/master/data/stir/stir_privatekey.pe",
		-1); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotImplemented, err)
	}

	engine.Cache = tmp
}

type testMockClientSyncSessions struct {
	*testRPCClientConnection
}

func (sT *testMockClientSyncSessions) Call(ctx *context.Context, method string, arg any, rply any) error {
	queriedSessionIDs := []*SessionID{
		{
			OriginID:   "ORIGIN_ID",
			OriginHost: "ORIGIN_HOST",
		},
	}
	*rply.(*[]*SessionID) = queriedSessionIDs
	time.Sleep(20 * time.Nanosecond)
	return utils.ErrNoActiveSession
}

func TestSyncSessions(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache
	engine.Cache.Clear(nil)

	sTestMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResourceSv1ReleaseResources: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
			utils.CacheSv1ReplicateSet: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- sTestMock
	cfg := config.NewDefaultCGRConfig()
	//cfg.GeneralCfg().ReplyTimeout = 1
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.CacheCfg().Partitions[utils.CacheClosedSessions] = &config.CacheParamCfg{
		Replicate: true,
	}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): chanInternal})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	sTestMock1 := &testMockClientSyncSessions{}
	sessions.RegisterIntBiJConn(sTestMock1, utils.EmptyString)

	sessions.aSessions = map[string]*Session{
		"SESS1": {
			CGRID: "TEST_CGRID",
		},
	}

	sessions.syncSessions()

	sessions.cgrCfg.GeneralCfg().ReplyTimeout = 1
	cacheS := engine.NewCacheS(cfg, nil, nil)
	engine.Cache = cacheS
	connMgr = engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator): chanInternal})
	engine.SetConnManager(connMgr)
	sessions.aSessions = map[string]*Session{
		"ORIGIN_ID": {},
	}

	var reply string
	if err := sessions.BiRPCv1SyncSessions(context.Background(), nil, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Errorf("Expected to be OK")
	}

	engine.Cache = tmp

	//There are no sessions to be removed
	sessions.terminateSyncSessions([]string{"no_sesssion"})
}

func TestAuthEvent(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)

	sTestMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderGetMaxSessionTime: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
							},
						}},
				}

				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- sTestMock
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEv := &utils.CGREvent{
		Tenant: "cgrates.org",
		ID:     "TEST_ID",
		Event: map[string]any{
			utils.Destination: "10",
			utils.Usage:       "invalid_time",
		},
	}

	expected := "time: invalid duration \"invalid_time\""
	if _, err := sessions.authEvent(cgrEv, true); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	delete(cgrEv.Event, utils.Usage)
	expected = "ChargerS is disabled"
	if _, err := sessions.authEvent(cgrEv, true); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	expectedTime := map[string]time.Duration{
		utils.EmptyString: 3 * time.Hour,
	}
	if usage, err := sessions.authEvent(cgrEv, true); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(usage, expectedTime) {
		t.Errorf("Expected %+v, received %+v", utils.ToJSON(expectedTime), utils.ToJSON(usage))
	}

}

func TestAuthEventMockCall(t *testing.T) {
	log.SetOutput(io.Discard)
	//mocking the GetMaxSession for checking the error
	engine.Cache.Clear(nil)
	sTestMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderGetMaxSessionTime: func(args any, reply any) error {
				usage := args.(*engine.CallDescriptorWithAPIOpts).APIOpts[utils.Usage]
				if usage != 10 {
					return utils.ErrNoMoreData
				}
				*reply.(*time.Duration) = 4 * time.Hour
				return nil
			},
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
								utils.RequestType: utils.MetaPrepaid,
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- sTestMock
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal})
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEv := &utils.CGREvent{
		Tenant: "cgrates.org",
		ID:     "TEST_ID",
		Event: map[string]any{
			utils.Destination: "10",
		},
		APIOpts: map[string]any{
			utils.Usage: 10,
		},
	}

	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	expectedTime := map[string]time.Duration{
		utils.EmptyString: 3 * time.Hour,
	}
	if usage, err := sessions.authEvent(cgrEv, true); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(usage, expectedTime) {
		t.Errorf("Expected %+v, received %+v", expectedTime, usage)
	}

	cgrEv.APIOpts = map[string]any{
		utils.Usage: 20,
	}
	expected := "RALS_ERROR:NO_MORE_DATA"
	if _, err := sessions.authEvent(cgrEv, true); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
}

func TestChargeEvent(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	sTestMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.CacheSv1ReplicateSet: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
								utils.RequestType: utils.MetaPostpaid,
							},
						}},
				}
				if args.(*utils.CGREvent).Tenant != "cgrates.org" {
					chrgrs[0].CGREvent.Event[utils.RequestType] = utils.MetaPrepaid
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
			utils.ResponderMaxDebit: func(args any, reply any) error {
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- sTestMock
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.CacheCfg().Partitions[utils.CacheClosedSessions] = &config.CacheParamCfg{
		Replicate: true,
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal,
	})
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEv := &utils.CGREvent{
		Tenant: "cgrates.org",
		ID:     "TEST_ID",
		Event: map[string]any{
			utils.Usage:       10,
			utils.RequestType: utils.MetaPostpaid,
		},
	}

	//disabled chargers
	expected := "ChargerS is disabled"
	if _, err := sessions.chargeEvent(cgrEv, true); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	cacheS := engine.NewCacheS(cfg, nil, nil)
	engine.Cache = cacheS
	connMgr = engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator): chanInternal})
	engine.SetConnManager(connMgr)

	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}

	if usage, err := sessions.chargeEvent(cgrEv, false); err != nil {
		t.Error(err)
	} else if usage != 10*time.Nanosecond {
		t.Errorf("Expected %+v, received %+v", 10*time.Nanosecond, usage)
	}

	engine.Cache.Clear(nil)
	cgrEv.Tenant = "CHANGED_TENANT"
	cgrEv.Event[utils.RequestType] = utils.MetaPrepaid
	expected = "RALS_ERROR:MANDATORY_IE_MISSING: [connIDs]"
	if _, err := sessions.chargeEvent(cgrEv, false); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	//testing initSession with if it is message
	if _, err := sessions.initSession(cgrEv, utils.EmptyString, utils.EmptyString, time.Second,
		false, true); err != nil {
		t.Error(err)
	}

	engine.Cache = tmp
}

func TestUpdateSession(t *testing.T) {
	log.SetOutput(io.Discard)
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	updatedEv := map[string]any{
		utils.Usage:       time.Second,
		utils.Destination: 10,
	}
	ss := &Session{
		EventStart: map[string]any{},
		SRuns: []*SRun{
			{
				Event: map[string]any{},
				CD: &engine.CallDescriptor{
					RunID: "RUNID_TEST",
				},
			},
		},
	}

	if _, err := sessions.updateSession(ss, updatedEv, nil, false); err != nil {
		t.Error(err)
	}

	updatedEv[utils.Usage] = "invalid_format"
	expectedErr := "time: invalid duration \"invalid_format\""
	if _, err := sessions.updateSession(ss, updatedEv, nil, false); err == nil || err.Error() != expectedErr {
		t.Errorf("Expected %+v, received %+v", expectedErr, err)
	}

	delete(updatedEv, utils.Usage)
	ss.SRuns[0].Event[utils.RequestType] = utils.MetaNone
	if _, err := sessions.updateSession(ss, updatedEv, nil, false); err != nil {
		t.Error(err)
	}
}

func TestEndSession(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	sTestMock := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResponderDebit: func(args any, reply any) error {
				return nil
			},
			utils.ResponderRefundRounding: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
			utils.CDRsV1StoreSessionCost: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- sTestMock
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	cfg.SessionSCfg().CDRsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs): chanInternal,
	})
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	ss := &Session{
		EventStart: map[string]any{},
		SRuns: []*SRun{
			{
				TotalUsage: 50 * time.Minute,
				Event:      map[string]any{},
				EventCost: &engine.EventCost{
					Usage:          utils.DurationPointer(30 * time.Minute),
					AccountSummary: &engine.AccountSummary{},
					Accounting: map[string]*engine.BalanceCharge{
						utils.MetaRounding: {
							AccountID: "ACCOUNTING_ID_TEST",
							RatingID:  "RATING_ID_TEST",
						},
						"ID_TEST2": {
							AccountID: "ACCOUNTING_ID_TEST2",
							RatingID:  utils.MetaRounding,
						},
					},
					Charges: []*engine.ChargingInterval{
						{
							RatingID: "RATING_ID",
							Increments: []*engine.ChargingIncrement{
								{
									Usage:        20 * time.Minute,
									Cost:         0.50,
									AccountingID: utils.MetaRounding,
								},
								{
									Usage:        15 * time.Minute,
									Cost:         0.466,
									AccountingID: "ID_TEST2",
								},
							},
						},
					},
					Rating: map[string]*engine.RatingUnit{
						"RATING_ID_TEST": {
							RatesID:          utils.EmptyString,
							TimingID:         utils.EmptyString,
							RoundingDecimals: 2,
						},
						utils.MetaRounding: {
							RatesID:  utils.EmptyString,
							TimingID: utils.EmptyString,
						},
						"RATING_ID": {
							RatingFiltersID:  utils.EmptyString,
							RoundingDecimals: 5,
						},
					},
				},
				CD: &engine.CallDescriptor{
					LoopIndex: 1,
				},
			},
		},
		Chargeable: true,
	}

	activationTime := time.Date(2020, 21, 07, 10, 0, 0, 0, time.UTC)
	expected := "cannot find last active ChargingInterval"
	if err := sessions.endSession(ss, utils.DurationPointer(20*time.Minute), utils.DurationPointer(time.Second),
		utils.TimePointer(activationTime), false); err == nil || err.Error() != expected {
		t.Error(err)
	}

	engine.Cache.Clear(nil)
	//totalUsage will be empty
	sessions.cgrCfg.SessionSCfg().StoreSCosts = true
	if err := sessions.endSession(ss, nil, utils.DurationPointer(time.Hour),
		utils.TimePointer(activationTime), false); err != nil {
		t.Error(err)
	}
}

func TestBiRPCv1GetActivePassiveSessions(t *testing.T) {
	log.SetOutput(io.Discard)
	clnt := &testMockClients{}

	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().SessionIndexes = utils.StringSet{
		"ToR": {},
	}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	ctx := context.WithClient(context.Background(), clnt)
	var reply []*ExternalSession
	if err := sessions.BiRPCv1GetActiveSessions(ctx, nil, &reply); err == nil || err != utils.ErrNotFound {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err)
	}

	sEv := engine.NewMapEvent(map[string]any{
		utils.EventName:       "TEST_EVENT",
		utils.ToR:             "*voice",
		utils.OriginID:        "12345",
		utils.AccountField:    "account1",
		utils.Subject:         "subject1",
		utils.Destination:     "+4986517174963",
		utils.Category:        "call",
		utils.Tenant:          "cgrates.org",
		utils.RequestType:     "*prepaid",
		utils.SetupTime:       "2015-11-09T14:21:24Z",
		utils.AnswerTime:      "2015-11-09T14:22:02Z",
		utils.Usage:           "1m23s",
		utils.LastUsed:        "21s",
		utils.PDD:             "300ms",
		utils.Route:           "supplier1",
		utils.DisconnectCause: "NORMAL_DISCONNECT",
		utils.OriginHost:      "127.0.0.1",
		"Extra1":              "Value1",
		"Extra2":              5,
		"Extra3":              "",
	})
	sr2 := sEv.Clone()
	// Index first session
	session := &Session{
		CGRID:      GetSetCGRID(sEv),
		EventStart: sEv,
		SRuns: []*SRun{
			{
				Event: sEv,
				CD: &engine.CallDescriptor{
					RunID: "RunID",
				},
			},
			{
				Event: sr2,
				CD: &engine.CallDescriptor{
					RunID: "RunID2",
				},
			},
		},
		Chargeable: true,
	}
	sr2[utils.ToR] = utils.MetaSMS
	sr2[utils.Subject] = "subject2"
	sr2[utils.CGRID] = GetSetCGRID(sEv)
	sessions.registerSession(session, false)

	st, err := utils.IfaceAsTime("2015-11-09T14:21:24Z", "")
	if err != nil {
		t.Fatal(err)
	}
	at, err := utils.IfaceAsTime("2015-11-09T14:22:02Z", "")
	if err != nil {
		t.Fatal(err)
	}
	eses1 := &ExternalSession{
		CGRID:       "cade401f46f046311ed7f62df3dfbb84adb98aad",
		ToR:         "*voice",
		OriginID:    "12345",
		OriginHost:  "127.0.0.1",
		Source:      "SessionS_TEST_EVENT",
		RequestType: "*prepaid",
		Category:    "call",
		Account:     "account1",
		Subject:     "subject1",
		Destination: "+4986517174963",
		SetupTime:   st,
		AnswerTime:  at,
		ExtraFields: map[string]string{
			"DisconnectCause": "NORMAL_DISCONNECT",
			"EventName":       "TEST_EVENT",
			"Extra1":          "Value1",
			"Extra2":          "5",
			"Extra3":          "",
			"LastUsed":        "21s",
			"PDD":             "300ms",
			utils.Route:       "supplier1",
		},
		NodeID: sessions.cgrCfg.GeneralCfg().NodeID,
	}

	expSess := []*ExternalSession{
		eses1,
	}

	args := &utils.SessionFilter{Filters: []string{fmt.Sprintf("*string:~*req.ToR:%s|%s", utils.MetaVoice, utils.MetaData)}}
	if err := sessions.BiRPCv1GetActiveSessions(ctx, args, &reply); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(expSess, reply) {
		t.Errorf("Expected %s , received: %s", utils.ToJSON(expSess), utils.ToJSON(reply))
	}

	var newReply1 int
	//nil args, but it will be an empty SessionFilter
	if err := sessions.BiRPCv1GetActiveSessionsCount(ctx, nil, &newReply1); err != nil {
		t.Error(err)
	} else if newReply1 != 2 {
		t.Errorf("Expected %+v, received: %+v", 2, newReply1)
	}

	if err := sessions.BiRPCv1GetActiveSessionsCount(ctx, args, &newReply1); err != nil {
		t.Error(err)
	} else if newReply1 != 1 {
		t.Errorf("Expected %+v, received: %+v", 1, newReply1)
	}

	//Passive session
	reply = []*ExternalSession{}
	if err := sessions.BiRPCv1GetPassiveSessions(ctx, nil, &reply); err == nil || err != utils.ErrNotFound {
		t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err)
	}

	sessions.pSessions = map[string]*Session{
		utils.EmptyString: {
			SRuns: []*SRun{
				{
					EventCost: &engine.EventCost{},
				},
			},
		},
	}
	//empty filters
	sessions.cgrCfg.GeneralCfg().NodeID = "TEST_ID"
	args = &utils.SessionFilter{}
	expSess = []*ExternalSession{
		{
			Source:      "SessionS_",
			NodeID:      "TEST_ID",
			ExtraFields: map[string]string{},
		},
	}
	if err := sessions.BiRPCv1GetPassiveSessions(ctx, args, &reply); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(reply, expSess) {
		t.Errorf("Expected %+v\n, received: %+v", utils.ToJSON(expSess), utils.ToJSON(reply))
	}

	if err := sessions.BiRPCv1GetPassiveSessionsCount(ctx, nil, &newReply1); err != nil {
		t.Error(err)
	}
}

func TestBiRPCv1SetPassiveSession(t *testing.T) {
	log.SetOutput(io.Discard)
	clnt := &testMockClients{}

	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	var reply string
	ss := &Session{
		Tenant: "cgrates.org",
		SRuns:  []*SRun{},
	}
	expected := "MANDATORY_IE_MISSING: [CGRID]"
	ctx := context.WithClient(context.Background(), clnt)
	if err := sessions.BiRPCv1SetPassiveSession(ctx, ss, &reply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v\n, received: %+v", expected, err)
	} else if reply != utils.EmptyString {
		t.Errorf("Expected %+v\n, received: %+v", utils.EmptyString, err)
	}

	ss.CGRID = "CGR_ID"
	if err := sessions.BiRPCv1SetPassiveSession(ctx, ss, &reply); err == nil || err != utils.ErrNotFound {
		t.Errorf("Expected %+v\n, received: %+v", utils.ErrNotFound, err)
	} else if reply != utils.EmptyString {
		t.Errorf("Expected %+v\n, received: %+v", utils.EmptyString, err)
	}

	sessions.pSessions = map[string]*Session{
		"CGR_ID": ss,
	}
	if err := sessions.BiRPCv1SetPassiveSession(ctx, ss, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Errorf("Expected %+v\n, received: %+v", utils.OK, err)
	}

	sessions.aSessions = map[string]*Session{
		"CGR_ID": ss,
	}
	ss.EventStart = engine.MapEvent{}
	if err := sessions.BiRPCv1SetPassiveSession(ctx, ss, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Errorf("Expected %+v\n, received: %+v", utils.OK, err)
	}
}

func TestBiRPCv1ReplicateSessions(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.SessionSv1SetPassiveSession: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		"conn1": chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	args := ArgsReplicateSessions{
		CGRID:   "CGRID_TEST",
		Passive: false,
		ConnIDs: []string{},
	}

	ctx := context.WithClient(context.Background(), clnt)
	var reply string
	if err := sessions.BiRPCv1ReplicateSessions(ctx, args, &reply); err != nil {
		t.Error(err)
	}

	args.ConnIDs = []string{"conn1"}
	if err := sessions.BiRPCv1ReplicateSessions(ctx, args, &reply); err != nil {
		t.Error(err)
	}
}

func TestBiRPCv1AuthorizeEvent(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				cgrEv := engine.AttrSProcessEventReply{
					CGREvent: &utils.CGREvent{
						ID:     "TestID",
						Tenant: "cgrates.org",
						Event:  map[string]any{},
					},
				}
				*reply.(*engine.AttrSProcessEventReply) = cgrEv
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "TestID",
		Event: map[string]any{
			utils.Usage: "10s",
		},
	}
	args := NewV1AuthorizeArgs(false, []string{},
		false, []string{}, false, []string{}, false, false,
		false, false, false, nil, utils.Paginator{}, false, "")

	rply := &V1AuthorizeReply{
		Attributes:    &engine.AttrSProcessEventReply{},
		RouteProfiles: engine.SortedRoutesList{},
		StatQueueIDs:  &[]string{},
		ThresholdIDs:  &[]string{},
	}

	expected := "MANDATORY_IE_MISSING: [CGREvent]"
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	args.CGREvent = cgrEvent
	//RPC caching
	sessions.cgrCfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = -1
	expected = "MANDATORY_IE_MISSING: [Subsystems]"

	caches := engine.NewCacheS(cfg, dm, nil)
	value := &utils.CachedRPCResponse{
		Result: &V1AuthorizeReply{
			ResourceAllocation: utils.StringPointer("ROUTE_LEASTCOST_1"),
		},
	}
	engine.Cache = caches
	caches.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1AuthorizeEvent, args.CGREvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err != nil {
		t.Error(err)
	}
	engine.Cache = tmp

	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	//Get Attributes
	sessions.cgrCfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 0
	args = NewV1AuthorizeArgs(true, []string{},
		false, []string{}, false, []string{}, false, false,
		true, false, false, cgrEvent, utils.Paginator{}, false, "")
	args.CGREvent.ID = "TestID"
	args.CGREvent.Tenant = "cgrates.org"
	expected = "ATTRIBUTES_ERROR:NOT_CONNECTED: AttributeS"

	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	expected = "NOT_CONNECTED: RouteS"
	sessions.cgrCfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
}

func TestBiRPCv1AuthorizeEvent2(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				cghrgs := []*engine.ChrgSProcessEventReply{
					{
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TestID",
							Event: map[string]any{
								utils.Usage: "10s",
							},
						},
					},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = cghrgs
				return nil
			},
			utils.ResourceSv1AuthorizeResources: func(args any, reply any) error {
				if args.(*utils.CGREvent).Tenant == "new_tenant" {
					return utils.ErrNotImplemented
				}
				return nil
			},
			utils.RouteSv1GetRoutes: func(args any, reply any) error {
				*reply.(*engine.SortedRoutesList) = engine.SortedRoutesList{{
					Routes: []*engine.SortedRoute{
						{
							RouteID: "RouteID",
						},
					},
				}}
				return nil
			},
			utils.ThresholdSv1ProcessEvent: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 0
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources):  chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		Tenant: "cgrates.org",
		Event: map[string]any{
			utils.Usage: "10s",
		},
		APIOpts: map[string]any{},
	}
	args := NewV1AuthorizeArgs(false, []string{},
		false, []string{}, false, []string{}, false, true,
		false, false, false, cgrEvent, utils.Paginator{}, false, "")

	rply := &V1AuthorizeReply{
		Attributes:    &engine.AttrSProcessEventReply{},
		RouteProfiles: engine.SortedRoutesList{},
		StatQueueIDs:  &[]string{},
		ThresholdIDs:  &[]string{},
	}

	//GetMaxUsage
	expected := "ChargerS is disabled"
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	args.CGREvent.ID = "TestID"
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err != nil {
		t.Error(err)
	}

	//AuthorizeResources
	args = NewV1AuthorizeArgs(false, []string{},
		false, []string{}, false, []string{}, true, false,
		false, false, false, cgrEvent, utils.Paginator{}, false, "")
	expected = "NOT_CONNECTED: ResourceS"
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	sessions.cgrCfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err != nil {
		t.Error(err)
	}

	args.CGREvent.Tenant = "new_tenant"
	expected = "RESOURCES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	//GetRoutes
	args = NewV1AuthorizeArgs(false, []string{},
		false, []string{}, false, []string{}, false, false,
		true, false, false, cgrEvent, utils.Paginator{}, false, "")
	expected = "NOT_CONNECTED: RouteS"
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	sessions.cgrCfg.SessionSCfg().RouteSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes)}
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err != nil {
		t.Error(err)
	}

	//ProcessThresholds
	args = NewV1AuthorizeArgs(false, []string{},
		true, []string{"TestID"}, false, []string{}, false, false,
		true, false, false, cgrEvent, utils.Paginator{}, false, "")
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err != utils.ErrPartiallyExecuted {
		t.Errorf("Expected %+v, received %+v", utils.ErrPartiallyExecuted, err)
	}

	//ProcessStats
	args = NewV1AuthorizeArgs(false, []string{},
		false, []string{}, true, []string{"TestID"}, false, false,
		true, false, false, cgrEvent, utils.Paginator{}, false, "")
	if err := sessions.BiRPCv1AuthorizeEvent(context.Background(), args, rply); err == nil || err != utils.ErrPartiallyExecuted {
		t.Errorf("Expected %+v, received %+v", utils.ErrPartiallyExecuted, err)
	}
}

func TestBiRPCv1AuthorizeEventWithDigest(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				cgrEv := engine.AttrSProcessEventReply{
					CGREvent: &utils.CGREvent{
						ID:      "TestID",
						Tenant:  "cgrates.org",
						Event:   map[string]any{},
						APIOpts: map[string]any{},
					},
				}
				*reply.(*engine.AttrSProcessEventReply) = cgrEv
				return nil
			},
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				cghrgs := []*engine.ChrgSProcessEventReply{
					{
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TestID",
							Event: map[string]any{
								utils.Usage: "10s",
							},
							APIOpts: map[string]any{},
						},
					},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = cghrgs
				return nil
			},
			utils.ResourceSv1AuthorizeResources: func(args any, reply any) error {
				if args.(*utils.CGREvent).Tenant == "new_tenant" {
					return utils.ErrNotImplemented
				}
				return nil
			},
			utils.RouteSv1GetRoutes: func(args any, reply any) error {
				*reply.(*engine.SortedRoutesList) = engine.SortedRoutesList{{
					Routes: []*engine.SortedRoute{
						{
							RouteID: "RouteID",
						},
					},
				}}
				return nil
			},
			utils.ThresholdSv1ProcessEvent: func(args any, reply any) error {
				return nil
			},
			utils.StatSv1ProcessEvent: func(args any, reply any) error {
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	cfg.SessionSCfg().RouteSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes)}
	cfg.SessionSCfg().ThreshSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
	cfg.SessionSCfg().StatSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)}
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 0
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources):  chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats):      chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		Tenant: "cgrates.org",
		Event: map[string]any{
			utils.Usage: "10s",
		},
		APIOpts: map[string]any{},
	}
	args := NewV1AuthorizeArgs(true, []string{},
		true, []string{}, true, []string{}, true, true,
		true, false, false, cgrEvent, utils.Paginator{}, false, "")

	authReply := new(V1AuthorizeReplyWithDigest)
	expectedRply := &V1AuthorizeReplyWithDigest{
		AttributesDigest:   utils.StringPointer(utils.EmptyString),
		ResourceAllocation: utils.StringPointer(utils.EmptyString),
		RoutesDigest:       utils.StringPointer("RouteID"),
		MaxUsage:           10800,
		Thresholds:         utils.StringPointer(utils.EmptyString),
		StatQueues:         utils.StringPointer(utils.EmptyString),
	}
	if err := sessions.BiRPCv1AuthorizeEventWithDigest(context.Background(), args, authReply); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(authReply, expectedRply) {
		t.Errorf("Expected %+v, received %+v", utils.ToJSON(expectedRply), utils.ToJSON(authReply))
	}

	sessions.cgrCfg.SessionSCfg().ChargerSConns = nil
	expected := "ChargerS is disabled"
	if err := sessions.BiRPCv1AuthorizeEventWithDigest(context.Background(), args, authReply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
}

func TestBiRPCv1InitiateSession1(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				cghrgs := []*engine.ChrgSProcessEventReply{
					{
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TestID",
							Event: map[string]any{
								utils.Usage: "10s",
							},
							APIOpts: map[string]any{},
						},
					},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = cghrgs
				return nil
			},
			utils.ResourceSv1AuthorizeResources: func(args any, reply any) error {
				if args.(*utils.CGREvent).Tenant == "new_tenant" {
					return utils.ErrNotImplemented
				}
				return nil
			},
			utils.ResourceSv1AllocateResources: func(args any, reply any) error {
				usageID := utils.IfaceAsString(args.(*utils.CGREvent).APIOpts[utils.OptsResourcesUsageID])
				if usageID == "ORIGIN_ID" {
					return utils.ErrNotImplemented
				}
				return nil
			},
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				if attrIDs, err := utils.IfaceAsSliceString(args.(*utils.CGREvent).APIOpts[utils.OptsAttributesProfileIDs]); err == nil &&
					len(attrIDs) != 0 {
					return utils.ErrNotImplemented
				}
				attrRply := engine.AttrSProcessEventReply{
					CGREvent: &utils.CGREvent{
						Tenant: "cgrates.org",
						ID:     "TestID",
						Event: map[string]any{
							utils.Usage: "10s",
						},
						APIOpts: map[string]any{},
					},
				}
				*reply.(*engine.AttrSProcessEventReply) = attrRply
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources):  chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
		APIOpts: map[string]any{},
	}
	args := NewV1InitSessionArgs(true, []string{},
		false, []string{}, false, []string{}, true, false,
		nil, true)

	rply := &V1InitSessionReply{}
	expected := "MANDATORY_IE_MISSING: [CGREvent]"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	args.CGREvent = cgrEvent
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err != nil {
		t.Error(err)
	}

	//get from cache error
	cgrEvent.ID = "INITIATE_SESSION_ACTIVE"
	args = NewV1InitSessionArgs(true, []string{},
		false, []string{}, false, []string{}, true, false,
		cgrEvent, true)
	caches := engine.NewCacheS(cfg, dm, nil)
	//value's error will be nil, so the error of the initiate sessions will be the same
	value := &utils.CachedRPCResponse{
		Result: &V1InitSessionReply{
			ResourceAllocation: utils.StringPointer("ROUTE_LEASTCOST_1"),
		},
	}
	engine.Cache = caches
	engine.Cache.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1InitiateSession, args.CGREvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err != nil {
		t.Error(err)
	}
	engine.Cache = tmp

	args.CGREvent.Tenant = utils.EmptyString
	args.AttributeIDs = []string{"attr1"}
	expected = "ATTRIBUTES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	args.AllocateResources = true
	args.AttributeIDs = []string{}
	sessions.cgrCfg.SessionSCfg().ResSConns = []string{}
	expected = "NOT_CONNECTED: ResourceS"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}

	args = NewV1InitSessionArgs(true, []string{},
		false, []string{}, false, []string{}, true, false,
		cgrEvent, true)
	delete(args.CGREvent.Event, utils.OriginID)
	expected = "MANDATORY_IE_MISSING: [OriginID]"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	cgrEvent = &utils.CGREvent{
		ID:     "Test_id",
		Tenant: "cgrates.org",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "ORIGIN_ID",
		},
	}
	args = NewV1InitSessionArgs(true, []string{},
		false, []string{}, false, []string{}, true, false,
		cgrEvent, true)
	expected = "RESOURCES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	//missing subsystems
	args = NewV1InitSessionArgs(false, []string{},
		false, []string{}, false, []string{}, false, false,
		cgrEvent, true)
	expected = "MANDATORY_IE_MISSING: [Subsystems]"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
}

func TestBiRPCv1InitiateSession2(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				cghrgs := []*engine.ChrgSProcessEventReply{
					{
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TestID",
							Event: map[string]any{
								utils.Usage: "10s",
							},
						},
					},
				}
				if args.(*utils.CGREvent).ID == "PREPAID" {
					cghrgs[0].CGREvent.Event[utils.RequestType] = utils.MetaPrepaid
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = cghrgs
				return nil
			},
			utils.ResourceSv1AuthorizeResources: func(args any, reply any) error {
				if args.(*utils.CGREvent).Tenant == "new_tenant" {
					return utils.ErrNotImplemented
				}
				return nil
			},
			utils.ThresholdSv1ProcessEvent: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.SessionSCfg().ThreshSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources):  chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID:     "Test_id",
		Tenant: "cgrates.org",
		Event: map[string]any{
			utils.Usage: "invalid_usage",
		},
		APIOpts: map[string]any{
			utils.OptsDebitInterval: "invalid_DUR_FORMAT",
		},
	}

	args := NewV1InitSessionArgs(false, []string{},
		false, []string{}, false, []string{}, false, true,
		cgrEvent, true)

	rply := &V1InitSessionReply{}
	expected := "RALS_ERROR:time: invalid duration \"invalid_DUR_FORMAT\""
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
	args.CGREvent.APIOpts[utils.OptsDebitInterval] = "10s"

	expected = "ChargerS is disabled"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}

	expected = "RALS_ERROR:time: invalid duration \"invalid_usage\""
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	sessions = NewSessionS(cfg, dm, connMgr)
	args.CGREvent.Event[utils.Usage] = "10s"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err != nil {
		t.Error(err)
	}

	//here we process the thresholds
	args = NewV1InitSessionArgs(false, []string{},
		true, []string{}, true, []string{}, false, true,
		cgrEvent, true)
	sessions = NewSessionS(cfg, dm, connMgr)
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err != utils.ErrPartiallyExecuted {
		t.Errorf("Expected %+v, received %+v", utils.ErrPartiallyExecuted, err)
	}

	//is prepaid
	cgrEvent = &utils.CGREvent{
		ID: "PREPAID",
		Event: map[string]any{
			utils.Usage: "1s",
		},
		APIOpts: map[string]any{
			utils.OptsDebitInterval: "10s",
		},
	}
	sessions = NewSessionS(cfg, dm, connMgr)
	args = NewV1InitSessionArgs(false, []string{},
		true, []string{}, true, []string{}, false, true,
		cgrEvent, true)
	expected = "EXISTS"
	if err := sessions.BiRPCv1InitiateSession(context.Background(), args, rply); err == nil || err != utils.ErrPartiallyExecuted {
		t.Errorf("Expected %+v, received %+v", utils.ErrPartiallyExecuted, err)
	}

}
func TestBiRPCv1InitiateSessionWithDigest(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				cgrEv := engine.AttrSProcessEventReply{
					CGREvent: &utils.CGREvent{
						ID:      "TestID",
						Tenant:  "cgrates.org",
						Event:   map[string]any{},
						APIOpts: map[string]any{},
					},
				}
				*reply.(*engine.AttrSProcessEventReply) = cgrEv
				return nil
			},
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				cghrgs := []*engine.ChrgSProcessEventReply{
					{
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TestID",
							Event: map[string]any{
								utils.Usage: "10s",
							},
							APIOpts: map[string]any{},
						},
					},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = cghrgs
				return nil
			},
			utils.ResourceSv1AllocateResources: func(args any, reply any) error {
				return nil
			},
			utils.RouteSv1GetRoutes: func(args any, reply any) error {
				*reply.(*engine.SortedRoutesList) = engine.SortedRoutesList{{
					Routes: []*engine.SortedRoute{
						{
							RouteID: "RouteID",
						},
					},
				}}
				return nil
			},
			utils.ThresholdSv1ProcessEvent: func(args any, reply any) error {
				return nil
			},
			utils.StatSv1ProcessEvent: func(args any, reply any) error {
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	cfg.SessionSCfg().RouteSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes)}
	cfg.SessionSCfg().ThreshSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
	cfg.SessionSCfg().StatSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)}
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 0
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources):  chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats):      chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		Tenant: "cgrates.org",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "ORIGIND_ID",
		},
		APIOpts: map[string]any{},
	}

	args := NewV1InitSessionArgs(true, []string{},
		true, []string{}, true, []string{}, true, true,
		cgrEvent, true)

	authReply := new(V1InitReplyWithDigest)
	expectedRply := &V1InitReplyWithDigest{
		AttributesDigest:   utils.StringPointer(utils.EmptyString),
		ResourceAllocation: utils.StringPointer(utils.EmptyString),
		MaxUsage:           10800,
		Thresholds:         utils.StringPointer(utils.EmptyString),
		StatQueues:         utils.StringPointer(utils.EmptyString),
	}
	if err := sessions.BiRPCv1InitiateSessionWithDigest(context.Background(), args, authReply); err != nil {
		t.Error(err)
	} else if !reflect.DeepEqual(authReply, expectedRply) {
		t.Errorf("Expected %+v, received %+v", utils.ToJSON(expectedRply), utils.ToJSON(authReply))
	}

	sessions.cgrCfg.SessionSCfg().ChargerSConns = nil
	expected := "MANDATORY_IE_MISSING: [OriginID]"
	if err := sessions.BiRPCv1InitiateSessionWithDigest(context.Background(), args,
		authReply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}
}

func TestBiRPCv1UpdateSession1(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				if attrIDs, err := utils.IfaceAsSliceString(args.(*utils.CGREvent).APIOpts[utils.OptsAttributesProfileIDs]); err == nil &&
					len(attrIDs) == 1 {
					return utils.ErrNotImplemented
				}
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
	}
	args := NewV1UpdateSessionArgs(true, false, false, []string{}, nil, nil, false,
		nil, true)
	rply := new(V1UpdateSessionReply)

	expected := "MANDATORY_IE_MISSING: [CGREvent]"
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	caches := engine.NewCacheS(cfg, dm, nil)
	//value's error will be nil, so the error of the initiate sessions will be the same
	value := &utils.CachedRPCResponse{
		Result: &V1UpdateSessionReply{
			MaxUsage: utils.DurationPointer(time.Minute),
		},
	}
	cgrEvent.ID = "test_id"
	args = NewV1UpdateSessionArgs(true, false, false, []string{}, nil, nil, false,
		cgrEvent, true)
	engine.Cache = caches
	engine.Cache.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1UpdateSession, args.CGREvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err != nil {
		t.Error(err)
	}
	engine.Cache = tmp

	cgrEvent.ID = utils.EmptyString
	args = NewV1UpdateSessionArgs(true, false, false, []string{"attrr1"}, nil, nil, false,
		cgrEvent, true)
	expected = "ATTRIBUTES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args = NewV1UpdateSessionArgs(true, false, false, []string{}, nil, nil, false,
		cgrEvent, true)
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err != nil {
		t.Error(err)
	}

	args = NewV1UpdateSessionArgs(false, false, false, []string{}, nil, nil, false,
		cgrEvent, true)
	expected = "MANDATORY_IE_MISSING: [Subsystems]"
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
}

func TestBiRPCv1UpdateSession2(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				cghrgs := []*engine.ChrgSProcessEventReply{
					{
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TestID",
							Event: map[string]any{
								utils.Usage: "10s",
							},
						},
					},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = cghrgs
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage:    "invalid_dur_format",
			utils.OriginID: "TEST_ID",
		},
		APIOpts: map[string]any{
			utils.OptsDebitInterval: "invalid_dur_format",
		},
	}
	args := NewV1UpdateSessionArgs(false, false, false, []string{}, nil, nil, true,
		cgrEvent, true)
	rply := new(V1UpdateSessionReply)
	expected := "RALS_ERROR:time: invalid duration \"invalid_dur_format\""
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.APIOpts[utils.OptsDebitInterval] = "10s"

	args = NewV1UpdateSessionArgs(false, false, false, []string{}, nil, nil, true,
		cgrEvent, true)
	expected = "ChargerS is disabled"
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}

	expected = "RALS_ERROR:time: invalid duration \"invalid_dur_format\""
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	cgrEvent.Event[utils.Usage] = time.Minute
	args = NewV1UpdateSessionArgs(false, false, false, []string{}, nil, nil, true,
		cgrEvent, true)
	if err := sessions.BiRPCv1UpdateSession(context.Background(), args, rply); err != nil {
		t.Error(err)
	}
}

func TestBiRPCv1TerminateSession1(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				cghrgs := []*engine.ChrgSProcessEventReply{
					{
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TestID",
							Event: map[string]any{
								utils.Usage: "10s",
								utils.CGRID: "TEST_ID",
							},
						},
					},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = cghrgs
				return nil
			},
			utils.CacheSv1ReplicateSet: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
	}

	args := NewV1TerminateSessionArgs(true, false, false, nil, false, nil, nil, true)
	var reply string
	expected := "MANDATORY_IE_MISSING: [CGREvent]"
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	cgrEvent.ID = utils.EmptyString
	args = NewV1TerminateSessionArgs(false, false, false, nil, false, nil, cgrEvent, true)
	expected = "MANDATORY_IE_MISSING: [Subsystems]"
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.ID = "test_id"

	caches := engine.NewCacheS(cfg, dm, nil)
	//value's error will be nil, so the error of the initiate sessions will be the same
	value := &utils.CachedRPCResponse{
		Result: utils.StringPointer("ROUTE_LEASTCOST_1"),
	}
	engine.Cache = caches
	engine.Cache.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1TerminateSession, args.CGREvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err != nil {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	engine.Cache = tmp

	cgrEvent.Event[utils.OriginID] = utils.EmptyString
	args = NewV1TerminateSessionArgs(true, false, false, nil, false, nil, cgrEvent, true)
	expected = "MANDATORY_IE_MISSING: [OriginID]"
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.Event[utils.OriginID] = "ORIGIN_ID"

	cgrEvent.APIOpts = make(map[string]any)
	cgrEvent.APIOpts[utils.OptsDebitInterval] = "invalid_time_format"
	args = NewV1TerminateSessionArgs(true, false, false, nil, false, nil, cgrEvent, true)
	expected = "RALS_ERROR:time: invalid duration \"invalid_time_format\""
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.APIOpts[utils.OptsDebitInterval] = "1m"

	//by this CGRID, there will be an empty session
	cgrEvent.Event[utils.CGRID] = "CGR_ID"
	sessions.aSessions = map[string]*Session{
		"CGR_ID": {},
	}
	args = NewV1TerminateSessionArgs(true, false, false, nil, false, nil, cgrEvent, true)
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}
	cgrEvent.Event[utils.CGRID] = "CHANGED_CGRID"

	args = NewV1TerminateSessionArgs(true, false, false, nil, false, nil, cgrEvent, true)
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{}
	expected = "RALS_ERROR:ChargerS is disabled"
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}

	//update session error
	cgrEvent.Event[utils.Usage] = "invalid_dur_time"
	args = NewV1TerminateSessionArgs(true, false, false, nil, false, nil, cgrEvent, true)
	expected = "time: invalid duration \"invalid_dur_time\""
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.Event[utils.Usage] = "1m"

	cgrEvent = &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
	}
	cfg = config.NewDefaultCGRConfig()
	cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.CacheCfg().Partitions[utils.CacheClosedSessions] = &config.CacheParamCfg{
		Replicate: true,
	}
	cfg.SessionSCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	connMgr = engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator): chanInternal,
	})
	sessions = NewSessionS(cfg, dm, connMgr)
	caches = engine.NewCacheS(cfg, dm, nil)
	engine.Cache = caches
	args = NewV1TerminateSessionArgs(true, false, false, nil, false, nil, cgrEvent, true)
	expected = "RALS_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	engine.Cache = tmp
}

func TestBiRPCv1TerminateSession2(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResourceSv1ReleaseResources: func(args any, reply any) error {
				if args.(*utils.CGREvent).Tenant == "CHANGED_ID" {
					return nil
				}
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
		APIOpts: map[string]any{},
	}
	args := NewV1TerminateSessionArgs(false, true, false, nil, false, nil, cgrEvent, true)
	var reply string
	expected := "RESOURCES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	cgrEvent.Event[utils.OriginID] = utils.EmptyString
	args = NewV1TerminateSessionArgs(false, true, false, nil, false, nil, cgrEvent, true)
	expected = "MANDATORY_IE_MISSING: [OriginID]"
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.Event[utils.OriginID] = "ORIGIN_ID"

	args = NewV1TerminateSessionArgs(false, true, false, nil, false, nil, cgrEvent, true)
	expected = "NOT_CONNECTED: ResourceS"
	sessions.cgrCfg.SessionSCfg().ResSConns = []string{}
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}

	cgrEvent.Tenant = "CHANGED_ID"
	args = NewV1TerminateSessionArgs(false, true, true, nil, true, nil, cgrEvent, true)
	if err := sessions.BiRPCv1TerminateSession(context.Background(), args, &reply); err == nil || err != utils.ErrPartiallyExecuted {
		t.Errorf("Exepected %+v, received %+v", utils.ErrPartiallyExecuted, err)
	}
}

func TestBiRPCv1ProcessCDR(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)
	sessions := NewSessionS(cfg, dm, nil)

	cgrEvent := &utils.CGREvent{
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
	}
	var reply string

	cgrEvent.ID = utils.EmptyString
	expected := "MANDATORY_IE_MISSING: [connIDs]"
	if err := sessions.BiRPCv1ProcessCDR(context.Background(), cgrEvent, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.ID = "test_id"

	caches := engine.NewCacheS(cfg, dm, nil)
	//value's error will be nil, so the error of the initiate sessions will be the same
	value := &utils.CachedRPCResponse{
		Result: utils.StringPointer("ROUTE_LEASTCOST_1"),
	}
	engine.Cache = caches
	engine.Cache.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1ProcessCDR, cgrEvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1ProcessCDR(context.Background(), cgrEvent, &reply); err != nil {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	engine.Cache = tmp
}

func TestBiRPCv1ProcessMessage1(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				if args.(*utils.CGREvent).ID == "test_id" {
					return nil
				}
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
	}

	args := NewV1ProcessMessageArgs(false, []string{},
		false, []string{}, false, []string{}, false, false,
		true, false, false, nil, utils.Paginator{}, false, "1")
	reply := V1ProcessMessageReply{}
	expected := "MANDATORY_IE_MISSING: [CGREvent]"
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	cgrEvent.ID = utils.EmptyString
	args = NewV1ProcessMessageArgs(true, []string{},
		false, []string{}, false, []string{}, true, false,
		false, false, false, cgrEvent, utils.Paginator{}, false, "1")
	expected = "ATTRIBUTES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	cgrEvent.ID = "test_id"
	args = NewV1ProcessMessageArgs(true, []string{},
		false, []string{}, false, []string{}, true, false,
		false, false, false, cgrEvent, utils.Paginator{}, false, "1")
	expected = "NOT_CONNECTED: ResourceS"
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	}

	caches := engine.NewCacheS(cfg, dm, nil)
	//value's error will be nil, so the error of the initiate sessions will be the same
	value := &utils.CachedRPCResponse{
		Result: &V1ProcessMessageReply{
			MaxUsage: utils.DurationPointer(time.Hour),
		},
	}
	engine.Cache = caches
	args = NewV1ProcessMessageArgs(true, []string{},
		false, []string{}, false, []string{}, true, false,
		false, false, false, cgrEvent, utils.Paginator{}, false, "1")
	engine.Cache.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1ProcessMessage, args.CGREvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}
	engine.Cache = tmp
}

func TestBiRPCv1ProcessMessage2(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ResourceSv1AllocateResources: func(args any, reply any) error {
				usageID := utils.IfaceAsString(args.(*utils.CGREvent).APIOpts[utils.OptsResourcesUsageID])
				if usageID == "ORIGIN_ID" {
					return nil
				}
				return utils.ErrNotImplemented
			},
			utils.RouteSv1GetRoutes: func(args any, reply any) error {
				*reply.(*engine.SortedRoutesList) = engine.SortedRoutesList{{
					Routes: []*engine.SortedRoute{
						{
							RouteID: "ROUTE_ID",
						},
					},
				}}
				return nil
			},
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes):    chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):  chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage: "10s",
		},
		APIOpts: map[string]any{},
	}

	args := NewV1ProcessMessageArgs(false, []string{},
		false, []string{}, false, []string{}, true, false,
		true, false, false, cgrEvent, utils.Paginator{}, false, "1")
	reply := V1ProcessMessageReply{}
	expected := "MANDATORY_IE_MISSING: [OriginID]"
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	cgrEvent.Event[utils.OriginID] = "ID"

	args = NewV1ProcessMessageArgs(false, []string{},
		false, []string{}, false, []string{}, true, false,
		false, false, false, cgrEvent, utils.Paginator{}, false, "1")
	reply = V1ProcessMessageReply{}
	expected = "RESOURCES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	cgrEvent.Event[utils.OriginID] = "ORIGIN_ID"
	args = NewV1ProcessMessageArgs(false, []string{},
		false, []string{}, false, []string{}, true, true,
		true, false, false, cgrEvent, utils.Paginator{}, false, "1")
	expected = "NOT_CONNECTED: RouteS"
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	sessions.cgrCfg.SessionSCfg().RouteSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes)}
	expected = "ChargerS is disabled"
	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args = NewV1ProcessMessageArgs(false, []string{},
		true, []string{}, true, []string{}, true, true,
		true, false, false, cgrEvent, utils.Paginator{}, false, "1")
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}

	if err := sessions.BiRPCv1ProcessMessage(context.Background(), args, &reply); err == nil || err != utils.ErrPartiallyExecuted {
		t.Errorf("Exepected %+v, received %+v", utils.ErrPartiallyExecuted, err)
	}
}

func TestBiRPCv1ProcessEvent(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				attrs := engine.AttrSProcessEventReply{
					CGREvent: &utils.CGREvent{
						Tenant: "cgrates.org",
						ID:     "TEST_ID",
						Event: map[string]any{
							utils.Destination: "10",
						},
					},
				}
				if args.(*utils.CGREvent).ID == "CHANGED_ID" {
					*reply.(*engine.AttrSProcessEventReply) = attrs
					return nil
				}
				return utils.ErrNotImplemented
			},
			utils.RouteSv1GetRoutes: func(args any, reply any) error {
				if args.(*utils.CGREvent).ID == "SECOND_ID" {
					*reply.(*engine.SortedRoutesList) = engine.SortedRoutesList{{
						ProfileID: "ROUTE_PRFID",
						Routes: []*engine.SortedRoute{
							{
								RouteID: "ROUTE_ID",
							},
						},
					}}
					return nil
				}
				return utils.ErrNotImplemented
			},
			utils.ThresholdSv1ProcessEvent: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
	}

	args := &V1ProcessEventArgs{
		Flags: []string{utils.MetaChargers},
	}
	reply := V1ProcessEventReply{}
	expected := "MANDATORY_IE_MISSING: [CGREvent]"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	args.CGREvent = cgrEvent
	caches := engine.NewCacheS(cfg, dm, nil)
	//value's error will be nil, so the error of the initiate sessions will be the same
	value := &utils.CachedRPCResponse{
		Result: &V1ProcessEventReply{
			MaxUsage: map[string]time.Duration{
				utils.Usage: time.Hour,
			},
		},
	}
	engine.Cache = caches
	engine.Cache.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1ProcessEvent, args.CGREvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}
	engine.Cache = tmp

	cgrEvent.ID = utils.EmptyString
	expected = "CHARGERS_ERROR:MANDATORY_IE_MISSING: [connIDs]"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.CGREvent.ID = "TEST_ID"
	args.Flags = append(args.Flags, utils.MetaAttributes)
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	sessions.cgrCfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}
	expected = "ATTRIBUTES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.CGREvent.ID = "CHANGED_ID"
	args.Flags = append(args.Flags, utils.MetaRoutes)
	sessions.cgrCfg.SessionSCfg().RouteSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRoutes)}
	expected = "ROUTES_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.MetaRoutes, "*routes:*event_cost:2", utils.MetaThresholds}
	args.CGREvent.ID = "SECOND_ID"
	sessions.cgrCfg.SessionSCfg().ThreshSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
	expected = "PARTIALLY_EXECUTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.MetaThresholds, utils.MetaBlockerError}
	sessions.cgrCfg.SessionSCfg().ThreshSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
	expected = "THRESHOLDS_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

}

func TestBiRPCv1ProcessEventStats(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
			utils.StatSv1ProcessEvent: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().StatSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)}
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats):    chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	cgrEvent := &utils.CGREvent{
		ID: "test_id",
		Event: map[string]any{
			utils.Usage:    "10s",
			utils.OriginID: "TEST_ID",
		},
	}

	args := &V1ProcessEventArgs{
		CGREvent: cgrEvent,
		Flags:    []string{utils.MetaChargers, utils.MetaStats},
	}
	reply := V1ProcessEventReply{}
	expected := "PARTIALLY_EXECUTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.MetaStats, utils.MetaBlockerError}
	expected = "STATS_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.MetaSTIRAuthenticate}
	args.CGREvent.APIOpts = make(map[string]any)
	args.CGREvent.APIOpts[utils.OptsStirATest] = "stir;test;opts"
	expected = "*stir_authenticate: missing parts of the message header"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.MetaSTIRInitiate}
	args.CGREvent.APIOpts = make(map[string]any)
	args.CGREvent.APIOpts[utils.OptsStirATest] = "stir;test;opts"
	expected = "*stir_authenticate: open : no such file or directory"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.CGREvent.APIOpts[utils.OptsStirOriginatorURI] = "+407590336423;USER_ID"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
}
func TestBiRPCv1ProcessEventResources(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				return nil
			},
			utils.StatSv1ProcessEvent: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):  chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	args := &V1ProcessEventArgs{
		Flags: []string{
			utils.ConcatenatedKey(utils.MetaResources, utils.MetaDerivedReply),
			utils.ConcatenatedKey(utils.MetaResources, utils.MetaAuthorize),
			utils.MetaChargers},
		CGREvent: &utils.CGREvent{
			Tenant: "cgrates.org",
			ID:     "testBiRPCv1ProcessEventStatsResources",
			Event: map[string]any{
				utils.Tenant:       "cgrates.org",
				utils.ToR:          utils.MetaVoice,
				utils.AccountField: "1001",
				utils.Subject:      "ANY2CNT",
				utils.Destination:  "1002",
			},
			APIOpts: map[string]any{},
		},
	}

	reply := V1ProcessEventReply{}
	expected := "NOT_CONNECTED: ResourceS"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	args.Flags = append(args.Flags, utils.MetaResources)

	expected = "MANDATORY_IE_MISSING: [OriginID]"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.CGREvent.Event[utils.OriginID] = "ORIGIN_ID"
	args.Flags = append(args.Flags, utils.MetaBlockerError)
	expected = "RESOURCES_ERROR:UNSUPPORTED_SERVICE_METHOD"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = args.Flags[:len(args.Flags)-1]
	expected = "PARTIALLY_EXECUTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.ConcatenatedKey(utils.MetaResources, utils.MetaDerivedReply),
		utils.ConcatenatedKey(utils.MetaResources, utils.MetaAllocate),
		utils.MetaChargers}
	args.Flags = append(args.Flags, utils.MetaBlockerError)
	expected = "RESOURCES_ERROR:UNSUPPORTED_SERVICE_METHOD"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = args.Flags[:len(args.Flags)-1]
	expected = "PARTIALLY_EXECUTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.ConcatenatedKey(utils.MetaResources, utils.MetaDerivedReply),
		utils.ConcatenatedKey(utils.MetaResources, utils.MetaRelease),
		utils.MetaChargers}
	args.Flags = append(args.Flags, utils.MetaBlockerError)
	expected = "RESOURCES_ERROR:UNSUPPORTED_SERVICE_METHOD"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = args.Flags[:len(args.Flags)-1]
	expected = "PARTIALLY_EXECUTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
}

func TestBiRPCv1ProcessEventRals1(t *testing.T) {
	log.SetOutput(io.Discard)
	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				if args.(*utils.CGREvent).ID != "RALS_ID" {
					return nil
				}
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
			utils.ResponderGetCost: func(args any, reply any) error {
				if args.(*engine.CallDescriptorWithAPIOpts).Tenant == "CHANGED_ID" {
					return nil
				}
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheEventCharges].Limit = -1
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):     chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	engine.Cache = engine.NewCacheS(cfg, dm, nil)
	sessions := NewSessionS(cfg, dm, connMgr)

	args := &V1ProcessEventArgs{
		Flags: []string{utils.MetaRALs,
			utils.ConcatenatedKey(utils.MetaRALs, utils.MetaCost),
			utils.ConcatenatedKey(utils.MetaRALs, utils.MetaDerivedReply),
			utils.MetaChargers},
		CGREvent: &utils.CGREvent{
			Tenant: "cgrates.org",
			ID:     "testBiRPCv1ProcessEventStatsResources",
			Event: map[string]any{
				utils.Tenant:       "cgrates.org",
				utils.ToR:          utils.MetaVoice,
				utils.AccountField: "1001",
				utils.Destination:  "1002",
			},
		},
	}

	reply := V1ProcessEventReply{}
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err != utils.ErrNotImplemented {
		t.Errorf("Exepected %+v, received %+v", utils.ErrNotImplemented, err)
	}

	args.CGREvent.Tenant = "CHANGED_ID"
	args.Flags = []string{utils.MetaRALs,
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaCost),
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaDerivedReply),
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaAuthorize),
		utils.MetaChargers}
	args.CGREvent.Event[utils.Usage] = "invalid_usage_format"
	expected := "time: invalid duration \"invalid_usage_format\""
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.CGREvent.Event[utils.Usage] = "1m"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err != nil {
		t.Error(expected)
	}

	args.Flags = []string{utils.MetaRALs,
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaInitiate),
		utils.MetaChargers}
	args.APIOpts = make(map[string]any)
	args.APIOpts[utils.OptsDebitInterval] = "invalid_dbtitrvl_format"
	expected = "RALS_ERROR:time: invalid duration \"invalid_dbtitrvl_format\""
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	args.APIOpts[utils.OptsDebitInterval] = "5s"

	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{}
	expected = "ChargerS is disabled"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}

	args.CGREvent.Event[utils.Usage] = "invalid_format"
	args.CGREvent.Tenant = "cgrates.org"
	expected = "RALS_ERROR:time: invalid duration \"invalid_format\""
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	args.CGREvent.Event[utils.Usage] = "10s"
}

func TestBiRPCv1ProcessEventRals2(t *testing.T) {
	tmp := engine.Cache
	log.SetOutput(io.Discard)

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
								utils.RequestType: utils.MetaPrepaid,
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
			utils.CacheSv1ReplicateSet: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
			utils.ResponderMaxDebit: func(args any, reply any) error {
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheEventCharges].Limit = -1
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}
	cfg.SessionSCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):       chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers):   chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	engine.Cache = engine.NewCacheS(cfg, dm, nil)
	sessions := NewSessionS(cfg, dm, connMgr)

	args := &V1ProcessEventArgs{
		Flags: []string{utils.MetaRALs,
			utils.ConcatenatedKey(utils.MetaRALs, utils.MetaInitiate),
			utils.MetaChargers},
		CGREvent: &utils.CGREvent{
			Tenant: "cgrates.org",
			ID:     "testBiRPCv1ProcessEventStatsResources",
			Event: map[string]any{
				utils.Tenant:      "cgrates.org",
				utils.Destination: "1002",
				utils.RequestType: utils.MetaPrepaid,
			},
			APIOpts: map[string]any{
				utils.OptsDebitInterval: "10s",
			},
		},
	}

	reply := V1ProcessEventReply{}

	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}

	args.Flags = []string{utils.MetaRALs,
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaUpdate),
		utils.MetaChargers}
	args.APIOpts[utils.OptsDebitInterval] = "invalid_format"
	expected := "RALS_ERROR:time: invalid duration \"invalid_format\""
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	args.APIOpts[utils.OptsDebitInterval] = "10s"

	args.Event[utils.CGRID] = "test_id_new"
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{}
	expected = "ChargerS is disabled"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	args.Event[utils.CGRID] = utils.EmptyString

	args.CGREvent.Event[utils.Usage] = "invalid_format"
	expected = "RALS_ERROR:time: invalid duration \"invalid_format\""
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	args.CGREvent.Event[utils.Usage] = "10"

	args.Flags = []string{utils.MetaRALs,
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaUpdate),
		utils.MetaChargers}
	delete(args.APIOpts, utils.OptsDebitInterval)
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}

	args.Flags = []string{utils.MetaRALs,
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaTerminate),
		utils.MetaChargers}
	args.APIOpts[utils.OptsDebitInterval] = "invalid_format"
	expected = "RALS_ERROR:time: invalid duration \"invalid_format\""
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	args.APIOpts[utils.OptsDebitInterval] = "10s"

	args.Event[utils.CGRID] = "test_id_new"
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{}
	expected = "ChargerS is disabled"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	args.Event[utils.CGRID] = utils.EmptyString

	engine.Cache.Clear(nil)
	cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.CacheCfg().Partitions[utils.CacheClosedSessions] = &config.CacheParamCfg{
		Replicate: true,
	}
	cacheS := engine.NewCacheS(cfg, nil, nil)
	engine.Cache = cacheS
	engine.SetConnManager(connMgr)
	expected = "RALS_ERROR:NOT_IMPLEMENTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	engine.Cache = tmp
}

func TestBiRPCv1ProcessEventCDRs11(t *testing.T) {
	log.SetOutput(io.Discard)

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.ChargerSv1ProcessEvent: func(args any, reply any) error {
				chrgrs := []*engine.ChrgSProcessEventReply{
					{ChargerSProfile: "TEST_PROFILE1",
						CGREvent: &utils.CGREvent{
							Tenant: "cgrates.org",
							ID:     "TEST_ID",
							Event: map[string]any{
								utils.Destination: "10",
								utils.RequestType: utils.MetaPrepaid,
							},
						}},
				}
				*reply.(*[]*engine.ChrgSProcessEventReply) = chrgrs
				return nil
			},
			utils.CDRsV1ProcessEvent: func(args any, reply any) error {
				return utils.ErrNotImplemented
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)}
	cfg.SessionSCfg().CDRsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs)}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs):     chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	args := &V1ProcessEventArgs{
		Flags: []string{utils.MetaCDRs,
			utils.ConcatenatedKey(utils.MetaRALs, utils.MetaDerivedReply),
			utils.MetaChargers},
		CGREvent: &utils.CGREvent{
			Tenant: "cgrates.org",
			ID:     "testBiRPCv1ProcessEventStatsResources",
			Event: map[string]any{
				utils.Tenant:      "cgrates.org",
				utils.CGRID:       "TEST_CGRID",
				utils.Destination: "1002",
				utils.RequestType: utils.MetaPrepaid,
			},
			APIOpts: map[string]any{
				utils.OptsDebitInterval: "10s",
			},
		},
	}
	sessions.aSessions = map[string]*Session{
		"TEST_CGRID": {
			Tenant: "cgrates.org",
			CGRID:  "TEST_CGRID",
			SRuns: []*SRun{
				{
					Event: map[string]any{
						utils.RequestType: utils.MetaDynaprepaid,
					},
					CD:            &engine.CallDescriptor{Category: "test"},
					EventCost:     &engine.EventCost{CGRID: "testCGRID"},
					ExtraDuration: 1,
					LastUsage:     time.Minute,
					TotalUsage:    3 * time.Minute,
					NextAutoDebit: utils.TimePointer(time.Date(2020, time.April, 18, 23, 0, 0, 0, time.UTC)),
				},
			},
		},
	}
	reply := V1ProcessEventReply{}

	expected := "PARTIALLY_EXECUTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}

	args.Flags = []string{utils.MetaCDRs, utils.MetaBlockerError,
		utils.ConcatenatedKey(utils.MetaRALs, utils.MetaDerivedReply),
		utils.MetaChargers}

	utils.Logger, err = utils.Newlogger(utils.MetaStdLog, utils.EmptyString)
	if err != nil {
		t.Error(err)
	}
	utils.Logger.SetLogLevel(7)
	buff := new(bytes.Buffer)
	log.SetOutput(buff)

	expectedLogger := "[WARNING] <SessionS> ProcessCDR called for active session with CGRID: <TEST_CGRID>"
	expected = "CDRS_ERROR:PARTIALLY_EXECUTED"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Expected %+v, received %+v", expected, err)
	} else if rcv := buff.String(); !strings.Contains(rcv, expectedLogger) {
		t.Errorf("Expected %+v, received %+v", expectedLogger, rcv)
	}
	buff.Reset()

	sessions.cgrCfg.SessionSCfg().CDRsConns = []string{}
	expected = "NOT_CONNECTED: CDRs"
	if err := sessions.BiRPCv1ProcessEvent(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
}

func TestBiRPCv1GetCost(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache

	engine.Cache.Clear(nil)
	clnt := &testMockClients{
		calls: map[string]func(args any, reply any) error{
			utils.AttributeSv1ProcessEvent: func(args any, reply any) error {
				attr := &engine.AttrSProcessEventReply{
					CGREvent: &utils.CGREvent{
						Tenant: "cgrates.org",
						ID:     "ATTRIBUTES",
						Event: map[string]any{
							utils.Usage: "20m",
						},
					},
				}
				*reply.(*engine.AttrSProcessEventReply) = *attr
				return nil
			},
			utils.ResponderGetCost: func(args any, reply any) error {
				return nil
			},
		},
	}
	chanInternal := make(chan birpc.ClientConnector, 1)
	chanInternal <- clnt
	cfg := config.NewDefaultCGRConfig()
	cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs):       chanInternal,
		utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes): chanInternal,
	})
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)

	args := &V1ProcessEventArgs{
		Flags: []string{utils.MetaAttributes,
			utils.ConcatenatedKey(utils.MetaRALs, utils.MetaDerivedReply),
			utils.MetaChargers},
	}
	cgrEvent := &utils.CGREvent{
		ID: "TestBiRPCv1GetCost",
		Event: map[string]any{
			utils.Tenant:      "cgrates.org",
			utils.Destination: "1002",
			utils.RequestType: utils.MetaPrepaid,
		},
		APIOpts: map[string]any{
			utils.OptsDebitInterval: "10s",
		},
	}
	reply := V1GetCostReply{}
	expected := "MANDATORY_IE_MISSING: [CGREvent]"
	if err := sessions.BiRPCv1GetCost(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	args.CGREvent = cgrEvent

	caches := engine.NewCacheS(cfg, dm, nil)
	//value's error will be nil, so the error of the initiate sessions will be the same
	value := &utils.CachedRPCResponse{
		Result: &V1GetCostReply{
			EventCost: &engine.EventCost{
				Cost: utils.Float64Pointer(1.50),
			},
		},
	}
	engine.Cache = caches
	engine.Cache.SetWithoutReplicate(utils.CacheRPCResponses, utils.ConcatenatedKey(utils.SessionSv1GetCost, args.CGREvent.ID),
		value, nil, true, utils.NonTransactional)
	if err := sessions.BiRPCv1GetCost(context.Background(), args, &reply); err != nil {
		t.Error(err)
	}
	engine.Cache = tmp

	args.CGREvent.ID = utils.EmptyString
	expected = "ATTRIBUTES_ERROR:NOT_CONNECTED: AttributeS"
	if err := sessions.BiRPCv1GetCost(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().AttrSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes)}

	expected = "MANDATORY_IE_MISSING: [connIDs]"
	if err := sessions.BiRPCv1GetCost(context.Background(), args, &reply); err == nil || err.Error() != expected {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	sessions.cgrCfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRALs)}

	expectedVal := V1GetCostReply{
		Attributes: &engine.AttrSProcessEventReply{
			CGREvent: &utils.CGREvent{
				Tenant: "cgrates.org",
				ID:     "ATTRIBUTES",
				Event: map[string]any{
					utils.Usage: "20m",
				},
			},
		},
		EventCost: &engine.EventCost{
			CGRID:         "ATTRIBUTES",
			Usage:         utils.DurationPointer(0),
			Cost:          utils.Float64Pointer(0),
			Charges:       []*engine.ChargingInterval{},
			Rating:        map[string]*engine.RatingUnit{},
			Accounting:    map[string]*engine.BalanceCharge{},
			RatingFilters: map[string]engine.RatingMatchedFilters{},
			Rates:         map[string]engine.RateGroups{},
			Timings:       map[string]*engine.ChargedTiming{},
		},
	}
	expectedVal.EventCost.Compute()
	if err := sessions.BiRPCv1GetCost(context.Background(), args, &reply); err != nil {
		t.Errorf("Exepected %+v, received %+v", expected, err)
	}
	/*
		else if !reflect.DeepEqual(expectedVal, reply) {
			fmt.Printf("%T and %T \n", expectedVal.EventCost.Cost, reply.EventCost.Cost)
			t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expectedVal), utils.ToJSON(reply))
		}

	*/
}

func TestSyncSessionsSync(t *testing.T) {
	log.SetOutput(io.Discard)
	tmp := engine.Cache
	engine.Cache.Clear(nil)
	cfg := config.NewDefaultCGRConfig()
	cfg.SessionSCfg().ResSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)}
	cfg.CacheCfg().ReplicationConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaReplicator)}
	cfg.CacheCfg().Partitions[utils.CacheClosedSessions] = &config.CacheParamCfg{
		Replicate: true,
	}
	data, err := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	if err != nil {
		t.Error(err)
	}
	connMgr := engine.NewConnManager(cfg, nil)
	dm := engine.NewDataManager(data, cfg.CacheCfg(), connMgr)
	sessions := NewSessionS(cfg, dm, connMgr)
	sessions.aSessions = map[string]*Session{}
	sessions.cgrCfg.GeneralCfg().ReplyTimeout = 1
	cacheS := engine.NewCacheS(cfg, nil, nil)
	engine.Cache = cacheS

	engine.SetConnManager(connMgr)
	sessions.aSessions = map[string]*Session{}

	var reply string
	if err := sessions.BiRPCv1SyncSessions(context.Background(), nil, &reply); err != nil {
		t.Error(err)
	} else if reply != utils.OK {
		t.Errorf("Expected to be OK")
	}

	engine.Cache = tmp

	//There are no sessions to be removed
	sessions.terminateSyncSessions([]string{"no_sesssion"})
}

func TestBiRPCv1Sleep(t *testing.T) {
	ss := &SessionS{}

	ctx := &context.Context{}
	reply := ""
	duration := 10 * time.Millisecond

	start := time.Now()
	err := ss.BiRPCv1Sleep(ctx, &utils.DurationArgs{Duration: duration}, &reply)
	elapsed := time.Since(start)

	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if reply != utils.OK {
		t.Errorf("expected reply = %s, got %s", utils.OK, reply)
	}

	if elapsed < duration {
		t.Errorf("function returned too quickly, expected >= %v, got %v", duration, elapsed)
	}
}

func TestUnregisterSession(t *testing.T) {
	ss := &SessionS{
		aSessions: map[string]*Session{
			"active1": {ClientConnID: "conn01"},
		},
		pSessions: map[string]*Session{
			"passive1": {ClientConnID: "conn02"},
		},
		bkpSessionIDs:  make(utils.StringSet),
		removeSsCGRIDs: make(utils.StringSet),
		cgrCfg:         config.NewDefaultCGRConfig(),
	}

	ss.cgrCfg.SessionSCfg().BackupInterval = 10

	ok := ss.unregisterSession("active1", false)
	if !ok {
		t.Errorf("expected active session to be unregistered")
	}
	if _, exists := ss.aSessions["active1"]; exists {
		t.Errorf("active session still exists after unregister")
	}
	if _, inRemove := ss.removeSsCGRIDs["active1"]; !inRemove {
		t.Errorf("active session ID not added to removeSsCGRIDs")
	}

	ok = ss.unregisterSession("passive1", true)
	if !ok {
		t.Errorf("expected passive session to be unregistered")
	}
	if _, exists := ss.pSessions["passive1"]; exists {
		t.Errorf("passive session still exists after unregister")
	}
}

func TestBiRPCv1BackupActiveSessions(t *testing.T) {
	cfg := config.NewDefaultCGRConfig()
	data, _ := engine.NewInternalDB(nil, nil, true, nil, cfg.DataDbCfg().Items)
	dm := engine.NewDataManager(data, cfg.CacheCfg(), nil)

	sess := &Session{
		CGRID:        "sess01",
		ClientConnID: "",
		EventStart: map[string]any{
			"Destination": "1002",
			"Tenant":      "cgrates.org",
		},
		lk: sync.RWMutex{},
	}

	ss := &SessionS{
		aSessions: map[string]*Session{
			sess.CGRID: sess,
		},
		cgrCfg:       cfg,
		dm:           dm,
		storeSessMux: sync.RWMutex{},
	}

	var reply int
	if err := ss.BiRPCv1BackupActiveSessions(context.Background(), "", &reply); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if reply != 1 {
		t.Errorf("expected 1 session stored, got %d", reply)
	}

	storedSessions, err := dm.GetSessionsBackup(cfg.GeneralCfg().NodeID, cfg.GeneralCfg().DefaultTenant)
	if err != nil {
		t.Fatalf("failed to get backup sessions: %v", err)
	}
	if len(storedSessions) != 1 || storedSessions[0].CGRID != "sess01" {
		t.Errorf("expected stored session with CGRID 'sess01', got %+v", storedSessions)
	}
}
