diff --git a/apier/v2/cdrs_it_test.go b/apier/v2/cdrs_it_test.go index 292607896..be6d826ee 100644 --- a/apier/v2/cdrs_it_test.go +++ b/apier/v2/cdrs_it_test.go @@ -332,7 +332,7 @@ func testV2CDRsGetCdrs2(t *testing.T) { } else if len(cdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(cdrs)) } else { - if cdrs[0].Cost != 0.0102 { + if cdrs[0].Cost != 0.0198 { t.Errorf("Unexpected cost for CDR: %f", cdrs[0].Cost) } } diff --git a/engine/cdrs.go b/engine/cdrs.go index ace8233f0..8adc09270 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -337,7 +337,7 @@ func (cdrS *CDRServer) refundEventCost(ec *EventCost, reqType, tor string) (rfnd return // non refundable } cd := ec.AsRefundIncrements(tor) - if cd == nil || len(cd.Increments) == 0 { + if len(cd.Increments) == 0 { return } var acnt Account @@ -738,6 +738,9 @@ func (cdrS *CDRServer) processEvents(evs []*utils.CGREvent, args *cdrProcessingA } if args.ralS { for i, cdr := range cdrs { + if !utils.AccountableRequestTypes.Has(cdr.RequestType) { + cdr.CostDetails = nil + } for j, rtCDR := range cdrS.rateCDRWithErr( &CDRWithAPIOpts{ CDR: cdr, diff --git a/general_tests/rerate_cdrs_it_test.go b/general_tests/rerate_cdrs_it_test.go index 9c3271fa3..8f4041e09 100644 --- a/general_tests/rerate_cdrs_it_test.go +++ b/general_tests/rerate_cdrs_it_test.go @@ -312,3 +312,113 @@ func TestRerateCDRs(t *testing.T) { } }) } + +func TestRerateCDRsNoRefund(t *testing.T) { + var cfgDir string + switch *utils.DBType { + case utils.MetaInternal: + cfgDir = "rerate_cdrs_internal" + case utils.MetaMySQL: + cfgDir = "rerate_cdrs_mysql" + case utils.MetaMongo: + cfgDir = "rerate_cdrs_mongo" + case utils.MetaPostgres: + t.SkipNow() + default: + t.Fatal("Unknown Database type") + } + ng := engine.TestEngine{ + ConfigPath: path.Join(*utils.DataDir, "conf", "samples", cfgDir), + TpPath: path.Join(*utils.DataDir, "tariffplans", "reratecdrs"), + } + client, _ := ng.Run(t) + CGRID := utils.GenUUID() + t.Run("ProcessFirstCDR", func(t *testing.T) { + var reply string + err := client.Call(context.Background(), utils.CDRsV1ProcessEvent, + &engine.ArgV1ProcessEvent{ + Flags: []string{utils.MetaRALs}, + CGREvent: utils.CGREvent{ + Tenant: "cgrates.org", + ID: "event1", + Event: map[string]any{ + utils.RunID: "run_1", + utils.CGRID: CGRID, + utils.Tenant: "cgrates.org", + utils.Category: "call", + utils.ToR: utils.MetaVoice, + utils.OriginID: "processCDR1", + utils.OriginHost: "OriginHost1", + utils.RequestType: utils.MetaRated, + utils.AccountField: "1001", + utils.Destination: "1002", + utils.SetupTime: time.Date(2021, time.February, 2, 16, 14, 50, 0, time.UTC), + utils.AnswerTime: time.Date(2021, time.February, 2, 16, 15, 0, 0, time.UTC), + utils.Usage: 2 * time.Minute, + }, + }, + }, &reply) + if err != nil { + t.Fatal(err) + } + + var cdrs []*engine.CDR + err = client.Call(context.Background(), utils.CDRsV1GetCDRs, &utils.RPCCDRsFilterWithAPIOpts{ + RPCCDRsFilter: &utils.RPCCDRsFilter{ + RunIDs: []string{"run_1"}, + }}, &cdrs) + if err != nil { + t.Fatal(err) + } + if cdrs[0].Usage != 2*time.Minute { + t.Errorf("expected usage to be <%+v>, received <%+v>", 2*time.Minute, cdrs[0].Usage) + } else if cdrs[0].Cost != 1.2 { + t.Errorf("expected cost to be <%+v>, received <%+v>", 0.6, cdrs[0].Cost) + } + }) + t.Run("UpdateTariffplans", func(t *testing.T) { + newtpFiles := map[string]string{ + utils.RatesCsv: `#Id,ConnectFee,Rate,RateUnit,RateIncrement,GroupIntervalStart +RT_ANY,0,1.7,60s,1s,0s`, + utils.DestinationRatesCsv: `#Id,DestinationId,RatesTag,RoundingMethod,RoundingDecimals,MaxCost,MaxCostStrategy +DR_ANY,*any,RT_ANY,*up,2,0,`, + utils.RatingPlansCsv: `#Id,DestinationRatesId,TimingTag,Weight +RP_ANY,DR_ANY,*any,10`, + } + engine.LoadCSVs(t, client, "", newtpFiles) + + var reply string + if err := client.Call(context.Background(), utils.CacheSv1Clear, &utils.AttrCacheIDsWithAPIOpts{}, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Calling CacheSv1.ReloadCache got reply: ", reply) + } + }) + + t.Run("RerateCDRs", func(t *testing.T) { + var reply string + if err := client.Call(context.Background(), utils.CDRsV1RateCDRs, &engine.ArgRateCDRs{ + Flags: []string{utils.MetaRerate}, + RPCCDRsFilter: utils.RPCCDRsFilter{ + OrderBy: utils.AnswerTime, + CGRIDs: []string{CGRID}, + }}, &reply); err != nil { + t.Fatal(err) + } + + var cdrs []*engine.CDR + err := client.Call(context.Background(), utils.CDRsV1GetCDRs, &utils.RPCCDRsFilterWithAPIOpts{ + RPCCDRsFilter: &utils.RPCCDRsFilter{ + CGRIDs: []string{CGRID}, + OrderBy: utils.AnswerTime, + }}, &cdrs) + if err != nil { + t.Fatal(err) + } + + if cdrs[0].Cost != 3.4 { + t.Errorf("expected cost to be <%+v>, received <%+v>", 3.4, cdrs[0].Cost) + } + }) + +} diff --git a/general_tests/sessions_race_test.go b/general_tests/sessions_race_test.go deleted file mode 100644 index 94f84d312..000000000 --- a/general_tests/sessions_race_test.go +++ /dev/null @@ -1,185 +0,0 @@ -//go:build race -// +build race - -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package general_tests - -import ( - "fmt" - "testing" - "time" - - "github.com/cgrates/birpc" - "github.com/cgrates/birpc/context" - v1 "github.com/cgrates/cgrates/apier/v1" - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/sessions" - "github.com/cgrates/cgrates/utils" -) - -var ( - sS *sessions.SessionS - cfg *config.CGRConfig - chrS *engine.ChargerService - filterS *engine.FilterS - connMgr *engine.ConnManager - dm *engine.DataManager - resp *engine.Responder -) - -// this structure will iplement birpc.ClientConnector -// and will read forever the Event map -type raceConn struct{} - -func (_ raceConn) Call(_ *context.Context, serviceMethod string, args any, reply any) (err error) { - cgrev := args.(*utils.CGREvent) - for { - for k := range cgrev.Event { - if _, has := cgrev.Event[k]; !has { - fmt.Println(1) - } - } - } -} - -// small test to detect races in sessions -func TestSessionSRace(t *testing.T) { - // config - var err error - cfg = config.NewDefaultCGRConfig() - cfg.SessionSCfg().Enabled = true - cfg.SessionSCfg().ThreshSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)} - cfg.SessionSCfg().ChargerSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers)} - cfg.SessionSCfg().RALsConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder)} - cfg.SessionSCfg().DebitInterval = 10 - cfg.ChargerSCfg().Enabled = true - - cfg.CacheCfg().Partitions[utils.CacheChargerProfiles].Limit = -1 - cfg.CacheCfg().Partitions[utils.CacheAccounts].Limit = -1 - // cfg.GeneralCfg().ReplyTimeout = 30 * time.Second - - utils.Logger.SetLogLevel(7) - // connManager - raceChan := make(chan birpc.ClientConnector, 1) - chargerSChan := make(chan birpc.ClientConnector, 1) - respChan := make(chan birpc.ClientConnector, 1) - raceChan <- new(raceConn) - connMgr = engine.NewConnManager(cfg, map[string]chan birpc.ClientConnector{ - utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds): raceChan, - utils.ConcatenatedKey(utils.MetaInternal, utils.MetaChargers): chargerSChan, - utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResponder): respChan, - }) - - // dataManager - db := engine.NewInternalDB(nil, nil, true, cfg.DataDbCfg().Items) - dm := engine.NewDataManager(db, cfg.CacheCfg(), connMgr) - engine.SetDataStorage(dm) - - // resp - resp = &engine.Responder{ - ShdChan: utils.NewSyncedChan(), - MaxComputedUsage: cfg.RalsCfg().MaxComputedUsage, - } - respChan <- resp - - // filterS - filterS = engine.NewFilterS(cfg, connMgr, dm) - - // chargerS - chrS = engine.NewChargerService(dm, filterS, cfg, connMgr) - - chargerSChan <- v1.NewChargerSv1(chrS) - - // addCharger - if err = dm.SetChargerProfile(&engine.ChargerProfile{ - Tenant: "cgrates.org", - ID: "Default", - RunID: utils.MetaDefault, - AttributeIDs: []string{"*none"}, - Weight: 20, - }, true); err != nil { - t.Fatal(err) - } - - // set account - if err = dm.SetAccount(&engine.Account{ - ID: utils.ConcatenatedKey("cgrates.org", "1001"), - // AllowNegative: true, - BalanceMap: map[string]engine.Balances{utils.MetaVoice: {{Value: float64(0 * time.Second), Weight: 10}}}}); err != nil { - t.Fatal(err) - } - - // sessionS - sS = sessions.NewSessionS(cfg, dm, connMgr) - - // the race2 - rply := new(sessions.V1InitSessionReply) - if err = sS.BiRPCv1InitiateSession(context.Background(), - &sessions.V1InitSessionArgs{ - InitSession: true, - ProcessThresholds: true, - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "testSSv1ItProcessEventInitiateSession", - Event: map[string]any{ - utils.Tenant: "cgrates.org", - utils.ToR: utils.MetaVoice, - utils.OriginID: "testSSv1ItProcessEvent", - utils.RequestType: utils.MetaPrepaid, - utils.AccountField: "1001", - // utils.RatingSubject: "*zero1ms", - // utils.CGRDebitInterval: 10, - utils.Destination: "1002", - utils.SetupTime: time.Date(2018, time.January, 7, 16, 60, 0, 0, time.UTC), - utils.AnswerTime: time.Date(2018, time.January, 7, 16, 60, 10, 0, time.UTC), - utils.Usage: 0, - }, - }, - }, rply); err != utils.ErrPartiallyExecuted { - t.Fatal(err) - } - // the race1 - rply2 := new(sessions.V1ProcessEventReply) - if err = sS.BiRPCv1ProcessEvent(context.Background(), - &sessions.V1ProcessEventArgs{ - Flags: []string{utils.ConcatenatedKey(utils.MetaRALs, utils.MetaInitiate), - utils.MetaThresholds}, - CGREvent: &utils.CGREvent{ - Tenant: "cgrates.org", - ID: "testSSv1ItProcessEventInitiateSession", - Event: map[string]any{ - utils.Tenant: "cgrates.org", - utils.ToR: utils.MetaVoice, - utils.OriginID: "testSSv1ItProcessEvent", - utils.RequestType: utils.MetaPrepaid, - utils.AccountField: "1001", - // utils.RatingSubject: "*zero1ms", - // utils.CGRDebitInterval: 10, - utils.Destination: "1002", - utils.SetupTime: time.Date(2018, time.January, 7, 16, 60, 0, 0, time.UTC), - utils.AnswerTime: time.Date(2018, time.January, 7, 16, 60, 10, 0, time.UTC), - utils.Usage: 0, - }, - }, - }, rply2); err != utils.ErrPartiallyExecuted { - t.Fatal(err) - } -}