From 4cba4a699de6cc6a341e335f409a115df659cda5 Mon Sep 17 00:00:00 2001 From: ionutboangiu Date: Tue, 18 Jun 2024 18:59:13 +0300 Subject: [PATCH] Implement SharedActionsData for action groups - holds common relevant data between actions. - currently supports only *cdrlog, making the process more reliable and less repetitive. It also provides access to more information about actions when creating CDRs. - easier to scale. - removes the need for cloning accounts before executing a group of actions. - added Actions method to check if specific action types exist inside. --- ees/libactions.go | 7 +- engine/account_test.go | 2 +- engine/action.go | 281 ++++++++++++---------- engine/action_plan.go | 15 +- engine/action_trigger.go | 13 +- engine/actions_test.go | 150 ++++++------ engine/libtest.go | 6 +- general_tests/transfer_balance_it_test.go | 26 +- utils/consts.go | 2 + 9 files changed, 265 insertions(+), 237 deletions(-) diff --git a/ees/libactions.go b/ees/libactions.go index f6488cbfa..60ae2af8e 100644 --- a/ees/libactions.go +++ b/ees/libactions.go @@ -22,7 +22,6 @@ import ( "encoding/gob" "encoding/json" "net/http" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -49,7 +48,7 @@ func getOneData(ub *engine.Account, extraData any) ([]byte, error) { } func callURL(ub *engine.Account, a *engine.Action, _ engine.Actions, _ *engine.FilterS, extraData any, - _ time.Time, _ engine.ActionConnCfg) error { + _ engine.SharedActionsData, _ engine.ActionConnCfg) error { body, err := getOneData(ub, extraData) if err != nil { return err @@ -69,7 +68,7 @@ func callURL(ub *engine.Account, a *engine.Action, _ engine.Actions, _ *engine.F // Does not block for posts, no error reports func callURLAsync(ub *engine.Account, a *engine.Action, _ engine.Actions, _ *engine.FilterS, extraData any, - _ time.Time, _ engine.ActionConnCfg) error { + _ engine.SharedActionsData, _ engine.ActionConnCfg) error { body, err := getOneData(ub, extraData) if err != nil { return err @@ -85,7 +84,7 @@ func callURLAsync(ub *engine.Account, a *engine.Action, _ engine.Actions, _ *eng } func postEvent(_ *engine.Account, a *engine.Action, _ engine.Actions, _ *engine.FilterS, extraData any, - _ time.Time, _ engine.ActionConnCfg) error { + _ engine.SharedActionsData, _ engine.ActionConnCfg) error { body, err := json.Marshal(extraData) if err != nil { return err diff --git a/engine/account_test.go b/engine/account_test.go index 26f2cb2fc..9d39c4a5b 100644 --- a/engine/account_test.go +++ b/engine/account_test.go @@ -1265,7 +1265,7 @@ func TestAccountExecuteTriggeredDayWeek(t *testing.T) { // we can reset them resetCountersAction(ub, &Action{ Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaMonetary), - ID: utils.StringPointer("day_trigger")}}, nil, nil, nil, time.Now(), ActionConnCfg{}) + ID: utils.StringPointer("day_trigger")}}, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.UnitCounters[utils.MetaMonetary][0].Counters[0].Value != 0 || ub.UnitCounters[utils.MetaMonetary][0].Counters[1].Value != 1 { t.Error("Error reseting both counters", diff --git a/engine/action.go b/engine/action.go index 223c6449d..f0b6a76fb 100644 --- a/engine/action.go +++ b/engine/action.go @@ -74,6 +74,48 @@ func (a *Action) Clone() (cln *Action) { } } +// SharedActionsData holds shared data for processing actions within a group. +type SharedActionsData struct { + + // idx represents the current iteration index of the action being processed. + // It is used as a unique key to link stored data to the correct action, since actions + // within a group do not have a unique identifier. + idx int + + refTime time.Time // reference time, constant for all actions in the group + transferBal map[int]transferInfo // data for *transfer_balance actions + remBal map[int]BalanceSummaries // data for *remove_balance actions + remExp map[int]BalanceSummaries // data for *remove_expired actions + cdrLog bool // indicates if a *cdrlog action is in the group +} + +// NewSharedActionsData initializes SharedActionsData based on the provided actions. +func NewSharedActionsData(acts Actions) SharedActionsData { + sd := SharedActionsData{ + refTime: time.Now(), + cdrLog: acts.HasAction(utils.CDRLog), + } + if acts.HasAction(utils.MetaRemoveBalance) { + sd.remBal = make(map[int]BalanceSummaries) + } + if acts.HasAction(utils.MetaRemoveExpired) { + sd.remExp = make(map[int]BalanceSummaries) + } + if acts.HasAction(utils.MetaTransferBalance) { + sd.transferBal = make(map[int]transferInfo) + } + return sd +} + +// transferInfo holds information for *transfer_balance actions. +type transferInfo struct { + srcAccID string // source account ID + destAccID string // destination account ID + units float64 // number of units to transfer + srcBal *BalanceSummary // source balance summary + destBal *BalanceSummary // destination balance summary +} + type ActionConnCfg struct { ConnIDs []string } @@ -99,7 +141,7 @@ func newActionConnCfg(source, action string, cfg *config.CGRConfig) ActionConnCf return act } -type actionTypeFunc func(*Account, *Action, Actions, *FilterS, any, time.Time, ActionConnCfg) error +type actionTypeFunc func(*Account, *Action, Actions, *FilterS, any, SharedActionsData, ActionConnCfg) error var actionFuncMap = make(map[string]actionTypeFunc) @@ -155,7 +197,7 @@ func RegisterActionFunc(action string, f actionTypeFunc) { // Destination account and balance IDs, and optionally a reference value, are obtained from Action's ExtraParameters. // If a reference value is specified, the transfer ensures the destination balance reaches this value. // If the destination account is different from the source, it is locked during the transfer. -func transferBalanceAction(srcAcc *Account, act *Action, _ Actions, fltrS *FilterS, _ any, _ time.Time, _ ActionConnCfg) error { +func transferBalanceAction(srcAcc *Account, act *Action, acts Actions, fltrS *FilterS, _ any, sd SharedActionsData, _ ActionConnCfg) error { if srcAcc == nil { return errors.New("source account is nil") } @@ -251,6 +293,18 @@ func transferBalanceAction(srcAcc *Account, act *Action, _ Actions, fltrS *Filte destBalance.AddValue(transferUnits) destBalance.dirty = true + if sd.cdrLog { + sd.transferBal[sd.idx] = transferInfo{ + srcAccID: utils.NewTenantID(srcAcc.ID).ID, + destAccID: utils.NewTenantID(destAcc.ID).ID, + units: transferUnits, + srcBal: srcBalance.AsBalanceSummary(srcBalanceType), + destBal: destBalance.AsBalanceSummary(srcBalanceType), + } + sd.transferBal[sd.idx].srcBal.Initial = sd.transferBal[sd.idx].srcBal.Value + transferUnits + sd.transferBal[sd.idx].destBal.Initial = sd.transferBal[sd.idx].destBal.Value - transferUnits + } + if diffAcnts { destAcc.InitCounters() destAcc.ExecuteActionTriggers(act, fltrS) @@ -271,7 +325,7 @@ func transferBalanceAction(srcAcc *Account, act *Action, _ Actions, fltrS *Filte return nil } -func logAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func logAction(ub *Account, _ *Action, _ Actions, _ *FilterS, extraData any, _ SharedActionsData, _ ActionConnCfg) (err error) { switch { case ub != nil: body, _ := json.Marshal(ub) @@ -284,7 +338,7 @@ func logAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ } func cdrLogAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData any, - referenceTime time.Time, _ ActionConnCfg) (err error) { + sd SharedActionsData, _ ActionConnCfg) (err error) { if len(config.CgrConfig().SchedulerCfg().CDRsConns) == 0 { return errors.New("No connection with CDR Server") } @@ -321,7 +375,7 @@ func cdrLogAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData an // set stored cdr values var cdrs []*CDR - for _, action := range acs { + for i, action := range acs { if !slices.Contains( []string{utils.MetaDebit, utils.MetaDebitReset, utils.MetaTopUp, utils.MetaTopUpReset, @@ -334,8 +388,8 @@ func cdrLogAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData an cdr := &CDR{ RunID: action.ActionType, Source: utils.CDRLog, - SetupTime: referenceTime, - AnswerTime: referenceTime, + SetupTime: sd.refTime, + AnswerTime: sd.refTime, OriginID: utils.GenUUID(), ExtraFields: make(map[string]string), PreRated: true, @@ -373,38 +427,29 @@ func cdrLogAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData an } } - // Function to process balances and append CDR if conditions are met. - processBalances := func(checkFunc func(*Balance, string) bool) error { - if acc == nil { - return fmt.Errorf("nil account for action %s", utils.ToJSON(action)) - } - found := false - for bType, bChain := range acc.BalanceMap { - for _, balance := range bChain { - if checkFunc(balance, bType) { - // Create a new CDR instance for each balance that meets the condition. - newCDR := *cdr // Copy CDR's values to a new CDR instance. - newCDR.Cost = balance.Value - newCDR.OriginID = utils.GenUUID() // OriginID must be unique for every CDR. - newCDR.CGRID = utils.Sha1(newCDR.OriginID, newCDR.OriginHost) - newCDR.ToR = bType - - // Clone the ExtraFields map to avoid changing its value in - // CDRs appended previously. - newCDR.ExtraFields = make(map[string]string, len(cdr.ExtraFields)+1) - for key, val := range cdr.ExtraFields { - newCDR.ExtraFields[key] = val - } - newCDR.ExtraFields[utils.BalanceID] = balance.ID - - cdrs = append(cdrs, &newCDR) // Append the address of the new instance. - found = true - } - } - } - if !found { + // Function to create (and append) CDRs based on each BalanceSummary element. + processBalances := func(balances BalanceSummaries) error { + if len(balances) == 0 { return utils.ErrNotFound } + for _, b := range balances { + // Create a new CDR instance for each balance that meets the condition. + newCDR := *cdr // Copy CDR's values to a new CDR instance. + newCDR.Cost = b.Value + newCDR.OriginID = utils.GenUUID() // OriginID must be unique for every CDR. + newCDR.CGRID = utils.Sha1(newCDR.OriginID, newCDR.OriginHost) + newCDR.ToR = b.Type + + // Clone the ExtraFields map to avoid changing its value in + // CDRs appended previously. + newCDR.ExtraFields = make(map[string]string, len(cdr.ExtraFields)+1) + for key, val := range cdr.ExtraFields { + newCDR.ExtraFields[key] = val + } + newCDR.ExtraFields[utils.BalanceID] = b.ID + + cdrs = append(cdrs, &newCDR) // Append the address of the new instance. + } return nil } @@ -412,57 +457,22 @@ func cdrLogAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData an // assign the balance values to the CDR cost and append to the list of CDRs. switch action.ActionType { case utils.MetaRemoveBalance: - if err = processBalances(func(b *Balance, typ string) bool { - return b.MatchFilter(action.Balance, typ, false, false) - }); err != nil { + if err = processBalances(sd.remBal[i]); err != nil { return err } continue case utils.MetaRemoveExpired: - if err = processBalances(func(b *Balance, typ string) bool { - return b.IsExpiredAt(referenceTime) && - b.MatchFilter(action.Balance, typ, false, true) - }); err != nil { + if err = processBalances(sd.remExp[i]); err != nil { return err } continue case utils.MetaTransferBalance: - cdr.Account = utils.SplitConcatenatedKey(acc.ID)[1] // Extract ID from TenantID. - destInfo := struct { - AccID string `json:"DestinationAccountID"` - BalID string `json:"DestinationBalanceID"` - RefVal *float64 `json:"DestinationReferenceValue"` - }{} - if err := json.Unmarshal([]byte(action.ExtraParameters), &destInfo); err != nil { - return err - } - - transferUnits := action.Balance.GetValue() - if destInfo.RefVal != nil { - tmpDestVal := 0.0 - _, srcBalanceType := acc.FindBalanceByID(*action.Balance.ID) - destAcc := acc - if acc.ID != destInfo.AccID { - destAcc, err = dm.GetAccount(destInfo.AccID) - if err != nil { - return fmt.Errorf("retrieving destination account failed: %w", err) - } - } - if destAcc.BalanceMap != nil { - destBalance := destAcc.GetBalanceWithID(srcBalanceType, destInfo.BalID) - if destBalance != nil { - tmpDestVal = destBalance.Value - } - } - transferUnits = *destInfo.RefVal - tmpDestVal - } - cdr.Cost = transferUnits - cdr.Destination = utils.SplitConcatenatedKey(destInfo.AccID)[1] // Extract ID from TenantID. - cdr.ExtraFields[utils.SourceBalanceID] = *action.Balance.ID - cdr.ExtraFields[utils.DestinationBalanceID] = destInfo.BalID - cdr.ExtraFields[utils.DestinationAccountID] = destInfo.AccID + cdr.Account = sd.transferBal[i].srcAccID + cdr.Destination = sd.transferBal[i].destAccID + cdr.Cost = sd.transferBal[i].units + cdr.ExtraFields[utils.SourceBalanceSummary] = utils.ToJSON(sd.transferBal[i].srcBal) + cdr.ExtraFields[utils.DestinationBalanceSummary] = utils.ToJSON(sd.transferBal[i].destBal) } - cdrs = append(cdrs, cdr) } @@ -484,7 +494,7 @@ func cdrLogAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData an return nil } -func resetTriggersAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func resetTriggersAction(ub *Account, a *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -492,7 +502,7 @@ func resetTriggersAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, ex return } -func setRecurrentAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func setRecurrentAction(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -500,7 +510,7 @@ func setRecurrentAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraDa return } -func unsetRecurrentAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func unsetRecurrentAction(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -508,7 +518,7 @@ func unsetRecurrentAction(ub *Account, a *Action, acs Actions, _ *FilterS, extra return } -func allowNegativeAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func allowNegativeAction(ub *Account, _ *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -516,7 +526,7 @@ func allowNegativeAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraD return } -func denyNegativeAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func denyNegativeAction(ub *Account, _ *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -524,14 +534,14 @@ func denyNegativeAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraDa return } -func resetAccountAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func resetAccountAction(ub *Account, _ *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } return genericReset(ub, fltrS) } -func topupResetAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func topupResetAction(ub *Account, a *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -545,7 +555,7 @@ func topupResetAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extra return } -func topupAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func topupAction(ub *Account, a *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -556,7 +566,7 @@ func topupAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData return } -func debitResetAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func debitResetAction(ub *Account, a *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -566,7 +576,7 @@ func debitResetAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extra return genericDebit(ub, a, true, fltrS) } -func debitAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func debitAction(ub *Account, a *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -574,7 +584,7 @@ func debitAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData return } -func resetCountersAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func resetCountersAction(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if ub == nil { return errors.New("nil account") } @@ -600,7 +610,7 @@ func genericDebit(ub *Account, a *Action, reset bool, fltrS *FilterS) (err error return ub.debitBalanceAction(a, reset, false, fltrS) } -func enableAccountAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func enableAccountAction(acc *Account, _ *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if acc == nil { return errors.New("nil account") } @@ -608,7 +618,7 @@ func enableAccountAction(acc *Account, a *Action, acs Actions, _ *FilterS, extra return } -func disableAccountAction(acc *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func disableAccountAction(acc *Account, _ *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { if acc == nil { return errors.New("nil account") } @@ -634,7 +644,7 @@ func genericReset(ub *Account, fltrS *FilterS) error { } // Mails the balance hitting the threshold towards predefined list of addresses -func mailAsync(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) error { +func mailAsync(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { cgrCfg := config.CgrConfig() params := strings.Split(a.ExtraParameters, string(utils.CSVSep)) if len(params) == 0 { @@ -676,7 +686,7 @@ func mailAsync(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ return nil } -func setddestinations(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func setddestinations(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { var ddcDestID string for _, bchain := range ub.BalanceMap { for _, b := range bchain { @@ -748,7 +758,7 @@ func setddestinations(ub *Account, a *Action, acs Actions, _ *FilterS, extraData return nil } -func removeAccountAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) error { +func removeAccountAction(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { var accID string if ub != nil { accID = ub.ID @@ -805,8 +815,8 @@ func removeAccountAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraD }, config.CgrConfig().GeneralCfg().LockingTimeout, utils.ActionPlanPrefix) } -func removeBalanceAction(acc *Account, a *Action, _ Actions, _ *FilterS, _ any, - _ time.Time, _ ActionConnCfg) error { +func removeBalanceAction(acc *Account, a *Action, acts Actions, _ *FilterS, _ any, + sd SharedActionsData, _ ActionConnCfg) error { if acc == nil { return fmt.Errorf("nil account for %s action", utils.ToJSON(a)) } @@ -814,6 +824,12 @@ func removeBalanceAction(acc *Account, a *Action, _ Actions, _ *FilterS, _ any, for bType, bChain := range acc.BalanceMap { for i := 0; i < len(bChain); i++ { if bChain[i].MatchFilter(a.Balance, bType, false, false) { + if sd.cdrLog { + // If *cdrlog action is present, add the balance summary to remBal in SharedActionsData + // for CDR creation. + sd.remBal[sd.idx] = append(sd.remBal[sd.idx], bChain[i].AsBalanceSummary(bType)) + } + // Remove balance without preserving order. bChain[i] = bChain[len(bChain)-1] bChain = bChain[:len(bChain)-1] @@ -829,14 +845,14 @@ func removeBalanceAction(acc *Account, a *Action, _ Actions, _ *FilterS, _ any, return nil } -func setBalanceAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) error { +func setBalanceAction(ub *Account, a *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { if ub == nil { return fmt.Errorf("nil account for %s action", utils.ToJSON(a)) } return ub.setBalanceAction(a, fltrS) } -func transferMonetaryDefaultAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) error { +func transferMonetaryDefaultAction(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { if ub == nil { utils.Logger.Err("*transfer_monetary_default called without account") return utils.ErrAccountNotFound @@ -884,7 +900,7 @@ Sq - CDRStatsQueueTriggered object We can actually use everythiong that go templates offer. You can read more here: https://golang.org/pkg/text/template/ */ -func cgrRPCAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func cgrRPCAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ SharedActionsData, _ ActionConnCfg) (err error) { // parse template tmpl := template.New("extra_params") tmpl.Delims("<<", ">>") @@ -963,7 +979,7 @@ func cgrRPCAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any // // Parameters are separated by ";" and must be provided in the specified order. func alterSessionsAction(_ *Account, act *Action, _ Actions, _ *FilterS, _ any, - _ time.Time, connCfg ActionConnCfg) (err error) { + _ SharedActionsData, connCfg ActionConnCfg) (err error) { // Parse action parameters based on the predefined format. params := strings.Split(act.ExtraParameters, ";") @@ -1008,7 +1024,7 @@ func alterSessionsAction(_ *Account, act *Action, _ Actions, _ *FilterS, _ any, // // Parameters are separated by ";" and must be provided in the specified order. func forceDisconnectSessionsAction(_ *Account, act *Action, _ Actions, _ *FilterS, _ any, - _ time.Time, connCfg ActionConnCfg) (err error) { + _ SharedActionsData, connCfg ActionConnCfg) (err error) { // Parse action parameters based on the predefined format. params := strings.Split(act.ExtraParameters, ";") @@ -1056,7 +1072,7 @@ func parseParamStringToMap(paramStr string, targetMap map[string]any) error { return nil } -func topupZeroNegativeAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any, _ time.Time, _ ActionConnCfg) error { +func topupZeroNegativeAction(ub *Account, a *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { if ub == nil { return errors.New("nil account") } @@ -1066,7 +1082,7 @@ func topupZeroNegativeAction(ub *Account, a *Action, acs Actions, fltrS *FilterS return ub.debitBalanceAction(a, false, true, fltrS) } -func setExpiryAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) error { +func setExpiryAction(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { if ub == nil { return errors.New("nil account") } @@ -1080,7 +1096,7 @@ func setExpiryAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData } // publishAccount will publish the account as well as each balance received to ThresholdS -func publishAccount(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) error { +func publishAccount(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { if ub == nil { return errors.New("nil account") } @@ -1097,36 +1113,43 @@ func publishAccount(ub *Account, a *Action, acs Actions, _ *FilterS, extraData a // Actions used to store actions according to weight type Actions []*Action -func (apl Actions) Len() int { - return len(apl) +func (a Actions) Len() int { + return len(a) } -func (apl Actions) Swap(i, j int) { - apl[i], apl[j] = apl[j], apl[i] +func (a Actions) Swap(i, j int) { + a[i], a[j] = a[j], a[i] } // we need higher weights earlyer in the list -func (apl Actions) Less(j, i int) bool { - return apl[i].Weight < apl[j].Weight +func (a Actions) Less(j, i int) bool { + return a[i].Weight < a[j].Weight } // Sort used to implement sort interface -func (apl Actions) Sort() { - sort.Sort(apl) +func (a Actions) Sort() { + sort.Sort(a) } // Clone returns a clone from object -func (apl Actions) Clone() (any, error) { - if apl == nil { +func (a Actions) Clone() (any, error) { + if a == nil { return nil, nil } - cln := make(Actions, len(apl)) - for i, action := range apl { + cln := make(Actions, len(a)) + for i, action := range a { cln[i] = action.Clone() } return cln, nil } +// HasAction checks if the action list contains an action of the given type. +func (a Actions) HasAction(typ string) bool { + return slices.ContainsFunc(a, func(act *Action) bool { + return act.ActionType == typ + }) +} + // newCdrLogProvider constructs a DataProvider func newCdrLogProvider(acnt *Account, action *Action) (dP utils.DataProvider) { dP = &cdrLogProvider{acnt: acnt, action: action, cache: utils.MapStorage{}} @@ -1223,7 +1246,7 @@ func (cdrP *cdrLogProvider) FieldAsString(fldPath []string) (data string, err er return utils.IfaceAsString(valIface), nil } -func removeSessionCosts(_ *Account, action *Action, _ Actions, _ *FilterS, _ any, _ time.Time, _ ActionConnCfg) error { // FiltersID;inlineFilter +func removeSessionCosts(_ *Account, action *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { // FiltersID;inlineFilter tenant := config.CgrConfig().GeneralCfg().DefaultTenant smcFilter := new(utils.SMCostFilter) for _, fltrID := range strings.Split(action.ExtraParameters, utils.InfieldSep) { @@ -1246,17 +1269,21 @@ func removeSessionCosts(_ *Account, action *Action, _ Actions, _ *FilterS, _ any return cdrStorage.RemoveSMCosts(smcFilter) } -func removeExpired(acc *Account, action *Action, _ Actions, _ *FilterS, _ any, - referenceTime time.Time, _ ActionConnCfg) error { +func removeExpired(acc *Account, action *Action, acts Actions, _ *FilterS, _ any, + sd SharedActionsData, _ ActionConnCfg) error { if acc == nil { return fmt.Errorf("nil account for %s action", utils.ToJSON(action)) } - found := false for bType, bChain := range acc.BalanceMap { for i := 0; i < len(bChain); i++ { - if bChain[i].IsExpiredAt(referenceTime) && + if bChain[i].IsExpiredAt(sd.refTime) && bChain[i].MatchFilter(action.Balance, bType, false, false) { + if sd.cdrLog { + // If *cdrlog action is present, add the balance summary to remExp in SharedActionsData + // for CDR creation. + sd.remExp[sd.idx] = append(sd.remExp[sd.idx], bChain[i].AsBalanceSummary(bType)) + } // Remove balance without maintaining order. bChain[i] = bChain[len(bChain)-1] @@ -1275,7 +1302,7 @@ func removeExpired(acc *Account, action *Action, _ Actions, _ *FilterS, _ any, } // resetAccountCDR resets the account out of values from CDR -func resetAccountCDR(ub *Account, action *Action, acts Actions, fltrS *FilterS, _ any, _ time.Time, _ ActionConnCfg) error { +func resetAccountCDR(ub *Account, action *Action, _ Actions, fltrS *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) error { if ub == nil { return errors.New("nil account") } @@ -1322,7 +1349,7 @@ func resetAccountCDR(ub *Account, action *Action, acts Actions, fltrS *FilterS, return nil } -func export(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func export(ub *Account, a *Action, _ Actions, _ *FilterS, extraData any, _ SharedActionsData, _ ActionConnCfg) (err error) { var cgrEv *utils.CGREvent switch { case ub != nil: @@ -1363,7 +1390,7 @@ func export(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ ti utils.EeSv1ProcessEvent, args, &rply) } -func resetThreshold(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func resetThreshold(_ *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { args := &utils.TenantIDWithAPIOpts{ TenantID: utils.NewTenantID(a.ExtraParameters), } @@ -1372,7 +1399,7 @@ func resetThreshold(ub *Account, a *Action, acs Actions, _ *FilterS, extraData a utils.ThresholdSv1ResetThreshold, args, &rply) } -func resetStatQueue(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func resetStatQueue(_ *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { args := &utils.TenantIDWithAPIOpts{ TenantID: utils.NewTenantID(a.ExtraParameters), } @@ -1381,7 +1408,7 @@ func resetStatQueue(ub *Account, a *Action, acs Actions, _ *FilterS, extraData a utils.StatSv1ResetStatQueue, args, &rply) } -func remoteSetAccount(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any, _ time.Time, _ ActionConnCfg) (err error) { +func remoteSetAccount(ub *Account, a *Action, _ Actions, _ *FilterS, _ any, _ SharedActionsData, _ ActionConnCfg) (err error) { client := &http.Client{Transport: httpPstrTransport} var resp *http.Response req := new(bytes.Buffer) diff --git a/engine/action_plan.go b/engine/action_plan.go index 2a3505e83..b890954c5 100644 --- a/engine/action_plan.go +++ b/engine/action_plan.go @@ -216,9 +216,8 @@ func (at *ActionTiming) Execute(fltrS *FilterS, originService string) (err error } transactionFailed := false removeAccountActionFound := false - accClone := acc.Clone() // *cdrlog action requires the original account - referenceTime := time.Now() - for _, act := range acts { + sharedData := NewSharedActionsData(acts) + for i, act := range acts { // check action filter if len(act.Filters) > 0 { if pass, err := fltrS.Pass(utils.NewTenantID(accID).Tenant, act.Filters, @@ -250,11 +249,8 @@ func (at *ActionTiming) Execute(fltrS *FilterS, originService string) (err error transactionFailed = true break } - tmpAcc := acc - if act.ActionType == utils.CDRLog { - tmpAcc = accClone - } - if err := actionFunction(tmpAcc, act, acts, fltrS, at.ExtraData, referenceTime, + sharedData.idx = i // set the current action index in shared data + if err := actionFunction(acc, act, acts, fltrS, at.ExtraData, sharedData, newActionConnCfg(originService, act.ActionType, config.CgrConfig())); err != nil { utils.Logger.Err( fmt.Sprintf("Error executing action %s: %v!", @@ -276,7 +272,6 @@ func (at *ActionTiming) Execute(fltrS *FilterS, originService string) (err error //reset the error in case that the account is not found err = nil if len(at.accountIDs) == 0 { // action timing executing without accounts - referenceTime := time.Now() for _, act := range acts { if expDate, parseErr := utils.ParseTimeDetectLayout(act.ExpirationString, config.CgrConfig().GeneralCfg().DefaultTimezone); (act.Balance == nil || act.Balance.EmptyExpirationDate()) && @@ -295,7 +290,7 @@ func (at *ActionTiming) Execute(fltrS *FilterS, originService string) (err error partialyExecuted = true break } - if err := actionFunction(nil, act, acts, fltrS, at.ExtraData, referenceTime, + if err := actionFunction(nil, act, acts, fltrS, at.ExtraData, SharedActionsData{}, newActionConnCfg(originService, act.ActionType, config.CgrConfig())); err != nil { utils.Logger.Err( fmt.Sprintf("Error executing accountless action %s: %v!", diff --git a/engine/action_trigger.go b/engine/action_trigger.go index 23e0b2213..d3c09532e 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -68,9 +68,8 @@ func (at *ActionTrigger) Execute(acc *Account, fltrS *FilterS) (err error) { at.Executed = true transactionFailed := false removeAccountActionFound := false - accClone := acc.Clone() // *cdrlog action requires the original account - referenceTime := time.Now() - for _, act := range acts { + sharedData := NewSharedActionsData(acts) + for i, act := range acts { // check action filter if len(act.Filters) > 0 { if pass, err := fltrS.Pass(utils.NewTenantID(act.Id).Tenant, act.Filters, @@ -99,12 +98,8 @@ func (at *ActionTrigger) Execute(acc *Account, fltrS *FilterS) (err error) { transactionFailed = false break } - //go utils.Logger.Info(fmt.Sprintf("Executing %v, %v: %v", ub, sq, a)) - tmpAcc := acc - if act.ActionType == utils.CDRLog { - tmpAcc = accClone - } - if err := actionFunction(tmpAcc, act, acts, fltrS, nil, referenceTime, + sharedData.idx = i // set the current action index in shared data + if err := actionFunction(acc, act, acts, fltrS, nil, sharedData, newActionConnCfg(utils.RALs, act.ActionType, config.CgrConfig())); err != nil { utils.Logger.Err( fmt.Sprintf("Error executing action %s: %v!", diff --git a/engine/actions_test.go b/engine/actions_test.go index 4339d39e7..dccb5ef5d 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -835,7 +835,7 @@ func TestActionResetTriggres(t *testing.T) { }, }, } - resetTriggersAction(ub, nil, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetTriggersAction(ub, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.ActionTriggers[0].Executed == true || ub.ActionTriggers[1].Executed == true { t.Error("Reset triggers action failed!") } @@ -864,7 +864,7 @@ func TestActionResetTriggresExecutesThem(t *testing.T) { }, }, } - resetTriggersAction(ub, nil, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetTriggersAction(ub, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.ActionTriggers[0].Executed == true || ub.BalanceMap[utils.MetaMonetary][0].GetValue() == 12 { t.Error("Reset triggers action failed!") } @@ -903,7 +903,7 @@ func TestActionResetTriggresActionFilter(t *testing.T) { ActionsID: "TEST_ACTIONS", Executed: true}}, } - resetTriggersAction(ub, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaSMS)}}, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetTriggersAction(ub, &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaSMS)}}, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.ActionTriggers[0].Executed == false || ub.ActionTriggers[1].Executed == false { t.Error("Reset triggers action failed!") } @@ -942,7 +942,7 @@ func TestActionResetTriggresActionFilter2(t *testing.T) { ActionsID: "TEST_ACTIONS", Executed: true}}, } - resetTriggersAction(ub, &Action{}, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetTriggersAction(ub, &Action{}, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.ActionTriggers[0].Executed != false && ub.ActionTriggers[1].Executed != false { t.Error("Reset triggers action failed!") } @@ -964,7 +964,7 @@ func TestActionSetPostpaid(t *testing.T) { &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaMonetary)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - allowNegativeAction(ub, nil, nil, nil, nil, time.Now(), ActionConnCfg{}) + allowNegativeAction(ub, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if !ub.AllowNegative { t.Error("Set postpaid action failed!") } @@ -987,7 +987,7 @@ func TestActionSetPrepaid(t *testing.T) { &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaMonetary)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - denyNegativeAction(ub, nil, nil, nil, nil, time.Now(), ActionConnCfg{}) + denyNegativeAction(ub, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative { t.Error("Set prepaid action failed!") } @@ -1010,7 +1010,7 @@ func TestActionResetPrepaid(t *testing.T) { &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaSMS)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - resetAccountAction(ub, nil, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetAccountAction(ub, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if !ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 0 || len(ub.UnitCounters) != 0 || @@ -1037,7 +1037,7 @@ func TestActionResetPostpaid(t *testing.T) { &ActionTrigger{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaSMS)}, ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } - resetAccountAction(ub, nil, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetAccountAction(ub, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 0 || len(ub.UnitCounters) != 0 || ub.BalanceMap[utils.MetaVoice][0].GetValue() != 0 || @@ -1066,7 +1066,7 @@ func TestActionTopupResetCredit(t *testing.T) { } a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaMonetary), Value: &utils.ValueFormula{Static: 10}}} - topupResetAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + topupResetAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 10 || len(ub.UnitCounters) != 0 || // InitCounters finds no counters @@ -1088,7 +1088,7 @@ func TestActionTopupValueFactors(t *testing.T) { }, ExtraParameters: `{"*monetary":2}`, } - topupResetAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + topupResetAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if len(ub.BalanceMap) != 1 || ub.BalanceMap[utils.MetaMonetary][0].Factors[utils.MetaMonetary] != 2.0 { t.Errorf("Topup reset action failed to set Factors: %+v", @@ -1110,7 +1110,7 @@ func TestActionTopupResetCreditId(t *testing.T) { Type: utils.StringPointer(utils.MetaMonetary), ID: utils.StringPointer("TEST_B"), Value: &utils.ValueFormula{Static: 10}}} - topupResetAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + topupResetAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 110 || len(ub.BalanceMap[utils.MetaMonetary]) != 2 { @@ -1132,7 +1132,7 @@ func TestActionTopupResetCreditNoId(t *testing.T) { a := &Action{Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MetaMonetary), Value: &utils.ValueFormula{Static: 10}}} - topupResetAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + topupResetAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 20 || len(ub.BalanceMap[utils.MetaMonetary]) != 2 { @@ -1162,7 +1162,7 @@ func TestActionTopupResetMinutes(t *testing.T) { Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaVoice), Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}} - topupResetAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + topupResetAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaVoice].GetTotalValue() != 5 || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 100 || @@ -1197,7 +1197,7 @@ func TestActionTopupCredit(t *testing.T) { a := &Action{Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MetaMonetary), Value: &utils.ValueFormula{Static: 10}}} - topupAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + topupAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 110 || len(ub.UnitCounters) != 0 || @@ -1230,7 +1230,7 @@ func TestActionTopupMinutes(t *testing.T) { a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaVoice), Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}} - topupAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + topupAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaVoice].GetTotalValue() != 15 || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 100 || @@ -1261,7 +1261,7 @@ func TestActionDebitCredit(t *testing.T) { a := &Action{Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MetaMonetary), Value: &utils.ValueFormula{Static: 10}}} - debitAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + debitAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 90 || len(ub.UnitCounters) != 0 || @@ -1294,7 +1294,7 @@ func TestActionDebitMinutes(t *testing.T) { Value: &utils.ValueFormula{Static: 5}, Weight: utils.Float64Pointer(20), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT"))}} - debitAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + debitAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if ub.AllowNegative || ub.BalanceMap[utils.MetaVoice][0].GetValue() != 5 || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 100 || @@ -1323,7 +1323,7 @@ func TestActionResetAllCounters(t *testing.T) { ActionsID: "TEST_ACTIONS", Executed: true}}, } ub.InitCounters() - resetCountersAction(ub, nil, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetCountersAction(ub, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if !ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 100 || len(ub.UnitCounters) != 1 || @@ -1359,7 +1359,7 @@ func TestActionResetCounterOnlyDefault(t *testing.T) { } a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaMonetary)}} ub.InitCounters() - resetCountersAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetCountersAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if !ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 100 || len(ub.UnitCounters) != 1 || @@ -1400,7 +1400,7 @@ func TestActionResetCounterCredit(t *testing.T) { ThresholdValue: 2, ActionsID: "TEST_ACTIONS", Executed: true}}, } a := &Action{Balance: &BalanceFilter{Type: utils.StringPointer(utils.MetaMonetary)}} - resetCountersAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}) + resetCountersAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if !ub.AllowNegative || ub.BalanceMap[utils.MetaMonetary].GetTotalValue() != 100 || len(ub.UnitCounters) != 2 || @@ -2472,7 +2472,7 @@ func TestCgrRpcAction(t *testing.T) { "Async" :false, "Params": {"Name":"n", "Surname":"s", "Age":10.2}}`, } - if err := cgrRPCAction(nil, a, nil, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err := cgrRPCAction(nil, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error("error executing cgr action: ", err) } if trpcp.status != utils.OK { @@ -2493,7 +2493,7 @@ func TestCgrRpcAction(t *testing.T) { "Async" :false, "Params": {"Name":"n", "Surname":"s", "Age":10.2}}`, } - if err := cgrRPCAction(nil, a, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil { + if err := cgrRPCAction(nil, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil { t.Error("error executing cgr action: ", err) } } @@ -2689,7 +2689,7 @@ func TestCdrLogAction(t *testing.T) { balanceValue: 10, }, } - if err := cdrLogAction(acc, a, acs, nil, extraData, time.Now(), ActionConnCfg{}); err != nil { + if err := cdrLogAction(acc, a, acs, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Fatal(err) } if mock.args == nil { @@ -2734,7 +2734,7 @@ func TestCdrLogAction(t *testing.T) { func TestRemoteSetAccountAction(t *testing.T) { expError := `Post "127.1.0.11//": unsupported protocol scheme ""` - if err = remoteSetAccount(nil, &Action{ExtraParameters: "127.1.0.11//"}, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || + if err = remoteSetAccount(nil, &Action{ExtraParameters: "127.1.0.11//"}, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expError { t.Fatalf("Expected error: %s, received: %v", expError, err) } @@ -2747,7 +2747,7 @@ func TestRemoteSetAccountAction(t *testing.T) { }, }, }}, - }, &Action{ExtraParameters: "127.1.0.11//"}, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || + }, &Action{ExtraParameters: "127.1.0.11//"}, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expError { t.Fatalf("Expected error: %s, received: %v", expError, err) } @@ -2755,7 +2755,7 @@ func TestRemoteSetAccountAction(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.Write([]byte("5")) })) acc := &Account{ID: "1001"} expError = `json: cannot unmarshal number into Go value of type engine.Account` - if err = remoteSetAccount(acc, &Action{ExtraParameters: ts.URL}, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || + if err = remoteSetAccount(acc, &Action{ExtraParameters: ts.URL}, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expError { t.Fatalf("Expected error: %s, received: %v", expError, err) } @@ -2789,7 +2789,7 @@ func TestRemoteSetAccountAction(t *testing.T) { } rw.Write([]byte(utils.ToJSON(exp))) })) - if err = remoteSetAccount(acc, &Action{ExtraParameters: ts.URL}, nil, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err = remoteSetAccount(acc, &Action{ExtraParameters: ts.URL}, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Fatal(err) } else if !reflect.DeepEqual(exp, acc) { t.Errorf("Expected: %s,received: %s", utils.ToJSON(exp), utils.ToJSON(acc)) @@ -2865,13 +2865,13 @@ func TestResetAccountCDR(t *testing.T) { balanceValue: 10, }, } - if err := resetAccountCDR(nil, a, acs, fltrs, extraData, time.Now(), ActionConnCfg{}); err == nil || err.Error() != "nil account" { + if err := resetAccountCDR(nil, a, acs, fltrs, extraData, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != "nil account" { t.Errorf("expected ,received <%+v>", err) - } else if err = resetAccountCDR(acc, a, acs, fltrs, extraData, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + } else if err = resetAccountCDR(acc, a, acs, fltrs, extraData, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Error(err) } SetCdrStorage(nil) - if err := resetAccountCDR(acc, a, acs, fltrs, extraData, time.Now(), ActionConnCfg{}); err == nil || err.Error() != fmt.Sprintf("nil cdrStorage for %s action", utils.ToJSON(a)) { + if err := resetAccountCDR(acc, a, acs, fltrs, extraData, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != fmt.Sprintf("nil cdrStorage for %s action", utils.ToJSON(a)) { t.Error(err) } @@ -2897,7 +2897,7 @@ func TestSetRecurrentAction(t *testing.T) { ac := &Action{ Id: "acTrigger", } - if err = setRecurrentAction(ub, ac, nil, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err = setRecurrentAction(ub, ac, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } } @@ -3024,7 +3024,7 @@ func TestActionSetDDestinations(t *testing.T) { } SetDataStorage(dm) - if err := setddestinations(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err := setddestinations(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } @@ -3126,7 +3126,7 @@ func TestActionPublishAccount(t *testing.T) { } expLog := ` with ThresholdS` expLog2 := `with StatS.` - if err := publishAccount(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err := publishAccount(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Errorf("received %v", err) } else if rcvLog := buf.String(); !strings.Contains(rcvLog, expLog) { t.Errorf("Logger %v doesn't contain %v", rcvLog, expLog) @@ -3223,13 +3223,13 @@ func TestExportAction(t *testing.T) { Event: map[string]any{}, APIOpts: map[string]any{}, } - if err := export(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err := export(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Errorf("received %v", err) - } else if err = export(nil, a, acs, nil, extraData, time.Now(), ActionConnCfg{}); err != nil { + } else if err = export(nil, a, acs, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Errorf("received %v", err) - } else if err = export(nil, a, acs, nil, "test", time.Now(), ActionConnCfg{}); err != nil { + } else if err = export(nil, a, acs, nil, "test", SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) - } else if err = export(nil, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + } else if err = export(nil, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } } @@ -3257,7 +3257,7 @@ func TestResetStatQueue(t *testing.T) { ExtraParameters: "cgrates.org:id", } acs := Actions{} - if err := resetStatQueue(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err == nil { + if err := resetStatQueue(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil { t.Errorf("received <%+v>", err) } @@ -3288,7 +3288,7 @@ func TestResetTreshold(t *testing.T) { ExtraParameters: "cgrates.org:id", } acs := Actions{} - if err := resetThreshold(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err == nil { + if err := resetThreshold(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil { t.Errorf("received <%+v>", err) } @@ -3298,33 +3298,33 @@ func TestEnableDisableAccountAction(t *testing.T) { var acc *Account expErr := "nil account" - if err := enableAccountAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + if err := enableAccountAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = disableAccountAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = disableAccountAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) } else if err = genericDebit(acc, nil, true, nil); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = resetCountersAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = resetCountersAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = debitAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = debitAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = debitResetAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = debitResetAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = topupAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = topupAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = topupResetAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = topupResetAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = resetAccountAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = resetAccountAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = denyNegativeAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = denyNegativeAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = allowNegativeAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = allowNegativeAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = unsetRecurrentAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = unsetRecurrentAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = setRecurrentAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = setRecurrentAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) - } else if err = resetTriggersAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != expErr { + } else if err = resetTriggersAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != expErr { t.Errorf("expected %+v ,received %v", expErr, err) } } @@ -3422,7 +3422,7 @@ func TestResetAccountCDRSuccesful(t *testing.T) { balanceValue: 10, }, } - if err = resetAccountCDR(acc, a, acs, fltrs, extraData, time.Now(), ActionConnCfg{}); err != nil { + if err = resetAccountCDR(acc, a, acs, fltrs, extraData, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } @@ -3462,7 +3462,7 @@ func TestRemoveSessionCost(t *testing.T) { expLog := `for filter` expLog2 := `in action:` - if err := removeSessionCosts(nil, action, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + if err := removeSessionCosts(nil, action, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Error(err) } else if rcvLog := buf.String(); !strings.Contains(rcvLog, expLog) { t.Errorf("expected %v,received %v", expLog, rcvLog) @@ -3494,9 +3494,9 @@ func TestLogAction(t *testing.T) { "field1": "value", "field2": "second", } - if err := logAction(acc, nil, nil, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err := logAction(acc, nil, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) - } else if err = logAction(nil, nil, nil, nil, extraData, time.Now(), ActionConnCfg{}); err != nil { + } else if err = logAction(nil, nil, nil, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } @@ -3683,7 +3683,7 @@ func TestRemoveAccountAcc(t *testing.T) { Event: map[string]any{}, APIOpts: map[string]any{}, } - if err := removeAccountAction(nil, a, acs, nil, extraData, time.Now(), ActionConnCfg{}); err != nil { + if err := removeAccountAction(nil, a, acs, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } } @@ -3782,12 +3782,12 @@ func TestRemoveAccountActionErr(t *testing.T) { db := NewInternalDB(nil, nil, true, cfg.DataDbCfg().Items) dm := NewDataManager(db, cfg.CacheCfg(), connMgr) SetDataStorage(nil) - if err := removeAccountAction(ub, a, acs, nil, extraData, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrInvalidKey { + if err := removeAccountAction(ub, a, acs, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrInvalidKey { t.Error(err) } ub.ID = "cgrates.org:exp" expLog := `[ERROR] Could not remove account Id: cgrates.org:exp: NO_DATABASE_CONNECTION` - if err := removeAccountAction(ub, a, acs, nil, extraData, time.Now(), ActionConnCfg{}); err == nil { + if err := removeAccountAction(ub, a, acs, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err == nil { t.Error(err) } else if rcvLog := buf.String(); !strings.Contains(rcvLog, expLog) { t.Errorf("expected log <%+v> to be included in: <%+v>", @@ -3803,7 +3803,7 @@ func TestRemoveAccountActionErr(t *testing.T) { buf2 := new(bytes.Buffer) setLogger(buf2) expLog = `Could not get action plans` - if err := removeAccountAction(ub, a, acs, nil, extraData, time.Now(), ActionConnCfg{}); err == nil { + if err := removeAccountAction(ub, a, acs, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err == nil { t.Error(err) } else if rcvLog := buf2.String(); !strings.Contains(rcvLog, expLog) { t.Errorf("Logger %v doesn't contain %v", rcvLog, expLog) @@ -3813,7 +3813,7 @@ func TestRemoveAccountActionErr(t *testing.T) { setLogger(buf3) expLog = `Could not retrieve action plan:` dm.SetAccountActionPlans(ub.ID, []string{"acc1"}, true) - if err := removeAccountAction(ub, a, acs, nil, extraData, time.Now(), ActionConnCfg{}); err == nil { + if err := removeAccountAction(ub, a, acs, nil, extraData, SharedActionsData{}, ActionConnCfg{}); err == nil { t.Error(err) } else if rcvLog := buf3.String(); !strings.Contains(rcvLog, expLog) { t.Errorf("Logger %v doesn't contain %v", rcvLog, expLog) @@ -3849,7 +3849,7 @@ func TestRemoveExpiredErrs(t *testing.T) { Blocker: utils.BoolPointer(false), }, } - if err := removeExpired(acc, action, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err.Error() != fmt.Sprintf("nil account for %s action", utils.ToJSON(action)) { + if err := removeExpired(acc, action, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err.Error() != fmt.Sprintf("nil account for %s action", utils.ToJSON(action)) { t.Error(err) } acc = &Account{ @@ -3857,7 +3857,7 @@ func TestRemoveExpiredErrs(t *testing.T) { BalanceMap: map[string]Balances{}, Disabled: true, } - if err = removeExpired(acc, action, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + if err = removeExpired(acc, action, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Error(err) } acc.BalanceMap = map[string]Balances{ @@ -3882,7 +3882,7 @@ func TestRemoveExpiredErrs(t *testing.T) { }, }, } - if err := removeExpired(acc, action, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + if err := removeExpired(acc, action, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Error(err) } } @@ -3911,14 +3911,14 @@ func TestTransferMonetaryDefaultAction(t *testing.T) { }, } expLog := `*transfer_monetary_default called without account` - if err := transferMonetaryDefaultAction(nil, a, acs, nil, "data", time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrAccountNotFound { + if err := transferMonetaryDefaultAction(nil, a, acs, nil, "data", SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrAccountNotFound { t.Errorf("expected <%v>,received <%v>", utils.ErrAccountNotFound, err) } else if rcvLog := buf.String(); !strings.Contains(rcvLog, expLog) { t.Errorf("expected log <%+v> to be included in: <%+v>", expLog, rcvLog) } ub := &Account{} - if err := transferMonetaryDefaultAction(ub, a, acs, nil, "data", time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + if err := transferMonetaryDefaultAction(ub, a, acs, nil, "data", SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Errorf("expected <%v>,received <%v>", utils.ErrNotFound, err) } } @@ -3944,10 +3944,10 @@ func TestRemoveBalanceActionErr(t *testing.T) { Value: &utils.ValueFormula{Static: 10}, }, } - if err := removeBalanceAction(nil, acs, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil { + if err := removeBalanceAction(nil, acs, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil { t.Error(err) } - if err := removeBalanceAction(acc, acs, nil, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + if err := removeBalanceAction(acc, acs, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Error(err) } } @@ -3980,7 +3980,7 @@ func TestDebitResetAction(t *testing.T) { Blocker: utils.BoolPointer(false), }, } - if err := debitResetAction(ub, a, nil, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err := debitResetAction(ub, a, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } } @@ -4087,7 +4087,7 @@ func TestSetDestinationsErr(t *testing.T) { config.SetCgrConfig(cfg) SetConnManager(connMgr) SetDataStorage(dm) - if err := setddestinations(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + if err := setddestinations(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Error(err) } ub = &Account{ @@ -4098,7 +4098,7 @@ func TestSetDestinationsErr(t *testing.T) { }, }, } - if err := setddestinations(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err == nil || err != utils.ErrNotFound { + if err := setddestinations(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err == nil || err != utils.ErrNotFound { t.Error(err) } } @@ -4188,7 +4188,7 @@ func TestRemoveAccountActionLogg(t *testing.T) { } SetDataStorage(dm) config.SetCgrConfig(cfg) - if err := removeAccountAction(ub, a, acs, nil, nil, time.Now(), ActionConnCfg{}); err != nil { + if err := removeAccountAction(ub, a, acs, nil, nil, SharedActionsData{}, ActionConnCfg{}); err != nil { t.Error(err) } @@ -4759,7 +4759,7 @@ func TestActionsTransferBalance(t *testing.T) { t.Run(tc.name, func(t *testing.T) { srcAcc = tc.srcAcc destAcc = tc.destAcc - err := transferBalanceAction(srcAcc, tc.act, nil, nil, nil, time.Now(), ActionConnCfg{}) + err := transferBalanceAction(srcAcc, tc.act, nil, nil, nil, SharedActionsData{}, ActionConnCfg{}) if tc.expectedErr != "" { if err == nil || err.Error() != tc.expectedErr { t.Errorf("expected error %v, received %v", tc.expectedErr, err) @@ -4840,7 +4840,7 @@ func TestActionsAlterAndDisconnectSessions(t *testing.T) { disconnectSessionsRequest = "" }) err := alterSessionsAction(nil, action, nil, nil, nil, - time.Now(), ActionConnCfg{ + SharedActionsData{}, ActionConnCfg{ ConnIDs: tc.connIDs, }) if tc.expectedErr != "" { @@ -4853,7 +4853,7 @@ func TestActionsAlterAndDisconnectSessions(t *testing.T) { t.Errorf("expected: %v\nreceived: %v", tc.expectedRequest, alterSessionsRequest) } err = forceDisconnectSessionsAction(nil, action, nil, nil, nil, - time.Now(), ActionConnCfg{ + SharedActionsData{}, ActionConnCfg{ ConnIDs: tc.connIDs, }) if tc.expectedErr != "" { diff --git a/engine/libtest.go b/engine/libtest.go index 29a970a8c..bc835067e 100644 --- a/engine/libtest.go +++ b/engine/libtest.go @@ -343,7 +343,11 @@ func StartEngine(cfgPath string, waitEngine int) (*exec.Cmd, error) { if err != nil { return nil, err } - engine := exec.Command(enginePath, "-config_path", cfgPath) + + f, _ := os.Create("/tmp/LOGS") + engine := exec.Command(enginePath, "-config_path", cfgPath, "-logger=*stdout") + engine.Stderr = f + engine.Stdout = f if err := engine.Start(); err != nil { return nil, err } diff --git a/general_tests/transfer_balance_it_test.go b/general_tests/transfer_balance_it_test.go index 424bc5e56..fcbdb1427 100644 --- a/general_tests/transfer_balance_it_test.go +++ b/general_tests/transfer_balance_it_test.go @@ -22,6 +22,7 @@ package general_tests import ( "sort" + "strings" "testing" "time" @@ -49,6 +50,10 @@ func TestTransferBalance(t *testing.T) { content := `{ +"general": { + "log_level": 7 +}, + "data_db": { "db_type": "*internal" }, @@ -83,15 +88,17 @@ PACKAGE_ACC_DEST,ACT_TOPUP_DEST,*asap,10`, utils.ActionsCsv: `#ActionsId[0],Action[1],ExtraParameters[2],Filter[3],BalanceId[4],BalanceType[5],Categories[6],DestinationIds[7],RatingSubject[8],SharedGroup[9],ExpiryTime[10],TimingIds[11],Units[12],BalanceWeight[13],BalanceBlocker[14],BalanceDisabled[15],Weight[16] ACT_TOPUP_SRC,*topup_reset,,,balance_src,*monetary,,*any,,,*unlimited,,10,20,false,false,20 ACT_TOPUP_DEST,*topup_reset,,,balance_dest,*monetary,,*any,,,*unlimited,,10,10,false,false,10 -ACT_TRANSFER,*cdrlog,,,,,,,,,,,,,,, -ACT_TRANSFER,*transfer_balance,"{""DestinationAccountID"":""cgrates.org:ACC_DEST"",""DestinationBalanceID"":""balance_dest""}",,balance_src,,,,,,*unlimited,,4,,,,`, +ACT_TRANSFER,*transfer_balance,"{""DestinationAccountID"":""cgrates.org:ACC_DEST"",""DestinationBalanceID"":""balance_dest""}",,balance_src,,,,,,*unlimited,,4,,,, +ACT_TRANSFER,*cdrlog,,,,,,,,,,,,,,,`, } testEnv := TestEnvironment{ Name: "TestTransferBalance", ConfigJSON: content, TpFiles: tpFiles, + // LogBuffer: &bytes.Buffer{}, } + // defer fmt.Println(testEnv.LogBuffer) client, _ := testEnv.Setup(t, *utils.WaitRater) t.Run("CheckInitialBalances", func(t *testing.T) { @@ -263,16 +270,15 @@ ACT_TRANSFER,*transfer_balance,"{""DestinationAccountID"":""cgrates.org:ACC_DEST } if len(cdrs) != 3 { - t.Errorf("expected to receive 2 cdrs: %v", utils.ToJSON(cdrs)) + t.Errorf("expected to receive 3 cdrs: %v", utils.ToJSON(cdrs)) } - if cdrs[0].Account != "ACC_SRC" || cdrs[0].Destination != "ACC_DEST" || cdrs[0].RunID != utils.MetaTransferBalance || cdrs[0].Source != utils.CDRLog || cdrs[0].ToR != utils.MetaVoice || - cdrs[0].ExtraFields["DestinationBalanceID"] != "balance_dest" || - cdrs[0].ExtraFields["SourceBalanceID"] != "balance_src" { + !strings.Contains(cdrs[0].ExtraFields[utils.DestinationBalanceSummary], "ID\":\"balance_dest\",\"Type\":\"*monetary\",\"Initial\":14,\"Value\":16,\"Weight\":10,\"Disabled\":false") || + !strings.Contains(cdrs[0].ExtraFields[utils.SourceBalanceSummary], "\"ID\":\"balance_src\",\"Type\":\"*monetary\",\"Initial\":6,\"Value\":4,\"Weight\":20,\"Disabled\":false") { t.Errorf("unexpected cdr received: %v", utils.ToJSON(cdrs[0])) } if cdrs[0].Cost != 2 { @@ -283,8 +289,8 @@ ACT_TRANSFER,*transfer_balance,"{""DestinationAccountID"":""cgrates.org:ACC_DEST cdrs[1].RunID != utils.MetaTransferBalance || cdrs[1].Source != utils.CDRLog || cdrs[1].ToR != utils.MetaVoice || - cdrs[1].ExtraFields["DestinationBalanceID"] != "nonexistent_balance" || - cdrs[1].ExtraFields["SourceBalanceID"] != "balance_src" { + !strings.Contains(cdrs[1].ExtraFields[utils.DestinationBalanceSummary], "\"ID\":\"nonexistent_balance\",\"Type\":\"*monetary\",\"Initial\":0,\"Value\":3,\"Disabled\":false") || + !strings.Contains(cdrs[1].ExtraFields[utils.SourceBalanceSummary], "\"ID\":\"balance_src\",\"Type\":\"*monetary\",\"Initial\":4,\"Value\":1,\"Weight\":20,\"Disabled\":false") { t.Errorf("unexpected cdr received: %v", utils.ToJSON(cdrs[1])) } if cdrs[1].Cost != 3 { @@ -295,8 +301,8 @@ ACT_TRANSFER,*transfer_balance,"{""DestinationAccountID"":""cgrates.org:ACC_DEST cdrs[2].RunID != utils.MetaTransferBalance || cdrs[2].Source != utils.CDRLog || cdrs[2].ToR != utils.MetaVoice || - cdrs[2].ExtraFields["DestinationBalanceID"] != "balance_dest" || - cdrs[2].ExtraFields["SourceBalanceID"] != "balance_src" { + !strings.Contains(cdrs[2].ExtraFields[utils.DestinationBalanceSummary], "\"ID\":\"balance_dest\",\"Type\":\"*monetary\",\"Initial\":10,\"Value\":14,\"Weight\":10,\"Disabled\":false") || + !strings.Contains(cdrs[2].ExtraFields[utils.SourceBalanceSummary], "\"ID\":\"balance_src\",\"Type\":\"*monetary\",\"Initial\":10,\"Value\":6,\"Weight\":20,\"Disabled\":false") { t.Errorf("unexpected cdr received: %v", utils.ToJSON(cdrs[2])) } if cdrs[2].Cost != 4 { diff --git a/utils/consts.go b/utils/consts.go index fdf59c612..7483caa6b 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -333,6 +333,8 @@ const ( NotAvailable = "N/A" Call = "call" ExtraFields = "ExtraFields" + SourceBalanceSummary = "SourceBalanceSummary" + DestinationBalanceSummary = "DestinationBalanceSummary" MetaSureTax = "*sure_tax" MetaDynamic = "*dynamic" MetaCounterEvent = "*event"