Files
cgrates/engine/eventcost_test.go
2025-10-29 19:42:40 +01:00

5027 lines
136 KiB
Go

/*
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 Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
*/
package engine
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"testing"
"time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
// testEC is used as sample through various tests
var testEC = &EventCost{
CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41",
RunID: utils.MetaDefault,
StartTime: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
Charges: []*ChargingInterval{
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: 0,
Cost: 0.1,
AccountingID: "9bdad10",
CompressFactor: 1,
},
{
Usage: time.Second,
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: 10 * time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 2,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 1,
},
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 60,
},
},
CompressFactor: 4,
},
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: 10 * time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 2,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 5,
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: "BALANCE_1",
Type: utils.MetaMonetary,
Value: 50,
Initial: 60,
Weight: 20,
Disabled: false,
Factors: ValueFactors{
"factor2": 2,
"factor3": 3,
},
},
{
UUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: "BALANCE_2",
Type: utils.MetaMonetary,
Value: 25,
Weight: 0,
Initial: 60,
Disabled: false,
Factors: ValueFactors{
"factor2": 2,
},
},
{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
ID: "BALANCE_3",
Type: utils.MetaVoice,
Value: 200,
Weight: 10,
Initial: 250,
Disabled: true,
Factors: ValueFactors{
"factor4": 4,
"factor5": 5,
},
},
},
AllowNegative: false,
Disabled: false,
},
Rating: Rating{
"3cd6425": &RatingUnit{
ConnectFee: 0.4,
RoundingMethod: "*up",
RoundingDecimals: 5,
MaxCostStrategy: utils.MetaMaxCostDisconnect,
TimingID: "7f324ab",
RatesID: "4910ecf",
RatingFiltersID: "43e77dc",
},
"c1a5ab9": &RatingUnit{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
MaxCostStrategy: utils.MetaMaxCostDisconnect,
TimingID: "7f324ab",
RatesID: "ec1a177",
RatingFiltersID: "43e77dc",
},
},
Accounting: Accounting{
"a012888": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.01,
},
"188bfa6": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.005,
},
"9bdad10": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.1,
},
"44d6c02": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
RatingID: "3cd6425",
Units: 1,
ExtraChargeID: "188bfa6",
},
"3455b83": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Units: 1,
ExtraChargeID: "*none",
},
},
RatingFilters: RatingFilters{
"43e77dc": RatingMatchedFilters{
"DestinationID": "GERMANY",
"DestinationPrefix": "+49",
"RatingPlanID": "RPL_RETAIL1",
"Subject": "*out:cgrates.org:call:*any",
},
},
Rates: ChargedRates{
"ec1a177": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateIncrement: time.Minute,
RateUnit: time.Second},
},
"4910ecf": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
&RGRate{
GroupIntervalStart: 60 * time.Second,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
},
},
Timings: ChargedTimings{
"7f324ab": &ChargedTiming{
StartTime: "00:00:00",
},
},
cache: utils.NewSecureMapStorage(),
}
func TestECClone(t *testing.T) {
ec := testEC.Clone()
if !reflect.DeepEqual(testEC, ec) {
t.Errorf("Expecting: %s, received: %s",
utils.ToJSON(testEC), utils.ToJSON(ec))
}
// making sure we don't influence the original values
ec.Usage = utils.DurationPointer(time.Second)
if testEC.Usage != nil {
t.Error("Usage is not nil")
}
ec.Cost = utils.Float64Pointer(1.0)
if testEC.Cost != nil {
t.Error("Cost is not nil")
}
ec.Charges[0].Increments[0].Cost = 1.0
if testEC.Charges[0].Increments[0].Cost == 1.0 {
t.Error("Cost is 1.0")
}
ec.AccountSummary.Disabled = true
if testEC.AccountSummary.Disabled {
t.Error("Account is disabled")
}
ec.AccountSummary.BalanceSummaries[0].Value = 5.0
if testEC.AccountSummary.BalanceSummaries[0].Value == 5.0 {
t.Error("Wrong balance summary")
}
ec.Rates["ec1a177"][0].Value = 5.0
if testEC.Rates["ec1a177"][0].Value == 5.0 {
t.Error("Wrong Value")
}
delete(ec.Rates, "ec1a177")
if _, has := testEC.Rates["ec1a177"]; !has {
t.Error("Key removed from testEC")
}
ec.Timings["7f324ab"].StartTime = "10:00:00"
if testEC.Timings["7f324ab"].StartTime == "10:00:00" {
t.Error("Wrong StartTime")
}
delete(ec.Timings, "7f324ab")
if _, has := testEC.Timings["7f324ab"]; !has {
t.Error("Key removed from testEC")
}
ec.RatingFilters["43e77dc"]["DestinationID"] = "GERMANY_MOBILE"
if testEC.RatingFilters["43e77dc"]["DestinationID"] == "GERMANY_MOBILE" {
t.Error("Wrong DestinationID")
}
delete(ec.RatingFilters, "43e77dc")
if _, has := testEC.RatingFilters["43e77dc"]; !has {
t.Error("Key removed from testEC")
}
ec.Accounting["a012888"].Units = 5.0
if testEC.Accounting["a012888"].Units == 5.0 {
t.Error("Wrong Units")
}
delete(ec.Accounting, "a012888")
if _, has := testEC.Accounting["a012888"]; !has {
t.Error("Key removed from testEC")
}
}
func TestECComputeAndReset(t *testing.T) {
ec := testEC.Clone()
eEc := testEC.Clone()
eEc.Usage = utils.DurationPointer(10 * time.Minute)
eEc.Cost = utils.Float64Pointer(3.52)
eEc.Charges[0].ecUsageIdx = utils.DurationPointer(0)
eEc.Charges[0].usage = utils.DurationPointer(time.Minute)
eEc.Charges[0].cost = utils.Float64Pointer(0.27)
eEc.Charges[1].ecUsageIdx = utils.DurationPointer(time.Minute)
eEc.Charges[1].usage = utils.DurationPointer(time.Minute)
eEc.Charges[1].cost = utils.Float64Pointer(0.6)
eEc.Charges[2].ecUsageIdx = utils.DurationPointer(5 * time.Minute)
eEc.Charges[2].usage = utils.DurationPointer(time.Minute)
eEc.Charges[2].cost = utils.Float64Pointer(0.17)
ec.Compute()
if !reflect.DeepEqual(eEc, ec) {
t.Errorf("Expecting: %s\n, received: %s", utils.ToJSON(eEc), utils.ToJSON(ec))
}
ec.ResetCounters()
if !reflect.DeepEqual(testEC, ec) {
t.Errorf("Expecting: %+v, received: %+v", testEC, ec)
}
}
func TestNewEventCostFromCallCost(t *testing.T) {
acntSummary := &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
Type: "*monetary",
Value: 50,
Disabled: false},
{
ID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Type: "*monetary",
Value: 25,
Disabled: false},
{
Type: "*voice",
Value: 200,
Disabled: false,
},
},
AllowNegative: false,
Disabled: false,
}
cc := &CallCost{
Category: "call",
Tenant: "cgrates.org",
Subject: "dan",
Account: "dan",
Destination: "+4986517174963",
ToR: utils.MetaVoice,
Cost: 0.75,
RatedUsage: 120.0,
Timespans: TimeSpans{
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
Cost: 0.15,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateUnit: time.Second,
RateIncrement: time.Minute,
},
},
},
},
DurationIndex: time.Minute,
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
RoundIncrement: &Increment{
Cost: -0.1,
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.MetaDefault,
Value: 9.9},
AccountID: "cgrates.org:dan",
},
CompressFactor: 1,
},
Increments: Increments{
&Increment{ // ConnectFee
Cost: 0.1,
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.MetaDefault,
Value: 9.9},
AccountID: "cgrates.org:dan",
},
CompressFactor: 1,
},
&Increment{ // First 30 seconds free
Duration: time.Second,
Cost: 0,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{
UUID: "9d54a9e9-d610-4c82-bcb5-a315b9a65089",
ID: "free_mins",
Value: 0,
Consumed: 1.0,
ToR: utils.MetaVoice,
},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
&Increment{ // Minutes with special price
Duration: time.Second,
Cost: 0.005,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{ // Minutes with special price
UUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: "discounted_mins",
Value: 0,
Consumed: 1.0,
ToR: utils.MetaVoice,
RateInterval: &RateInterval{
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.005,
RateUnit: time.Second,
RateIncrement: time.Second,
},
&RGRate{
GroupIntervalStart: 60 * time.Second,
Value: 0.005,
RateUnit: time.Second,
RateIncrement: time.Second,
},
},
},
},
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.MetaDefault,
Value: 9.75},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
},
},
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 20, 21, 0, time.UTC),
Cost: 0.6,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateUnit: time.Second,
RateIncrement: time.Minute,
},
},
},
},
DurationIndex: time.Minute,
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{
Cost: 0.01,
Duration: time.Second,
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.MetaDefault,
Value: 9.15},
AccountID: "cgrates.org:dan",
},
CompressFactor: 60,
},
},
},
},
AccountSummary: acntSummary,
}
eEC := &EventCost{
CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41",
RunID: utils.MetaDefault,
StartTime: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
Cost: utils.Float64Pointer(0.85),
Usage: utils.DurationPointer(2 * time.Minute),
Charges: []*ChargingInterval{
{
RatingID: "f2518464-68b8-42f4-acec-aef23d714314",
Increments: []*ChargingIncrement{
{
Usage: 0,
Cost: 0.1,
AccountingID: "44e97dec-8a7e-43d0-8b0a-736d46b5613e",
CompressFactor: 1,
},
{
Usage: time.Second,
Cost: 0,
AccountingID: "a555cde8-4bd0-408a-afbc-c3ba64888927",
CompressFactor: 30,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "906bfd0f-035c-40a3-93a8-46f71627983e",
CompressFactor: 30,
},
{
Cost: -0.1,
AccountingID: "44e97dec-8a7e-43d0-8b0a-e34a152",
CompressFactor: 1,
},
},
CompressFactor: 1,
usage: utils.DurationPointer(60 * time.Second),
cost: utils.Float64Pointer(0.15),
ecUsageIdx: utils.DurationPointer(0),
},
{
RatingID: "f2518464-68b8-42f4-acec-aef23d714314",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "c890a899-df43-497a-9979-38492713f57b",
CompressFactor: 60,
},
},
CompressFactor: 1,
usage: utils.DurationPointer(60 * time.Second),
cost: utils.Float64Pointer(0.6),
ecUsageIdx: utils.DurationPointer(60 * time.Second),
},
},
Rating: Rating{
"4607d907-02c3-4f2b-bc08-95a0dcc7222c": &RatingUnit{
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingID: "27f1e5f8-05bb-4f1c-a596-bf1010ad296c",
RatesID: "e5eb0f1c-3612-4e8c-b749-7f8f41dd90d4",
RatingFiltersID: "7e73a00d-be53-4083-a1ee-8ee0b546c62a",
},
"f2518464-68b8-42f4-acec-aef23d714314": &RatingUnit{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingID: "27f1e5f8-05bb-4f1c-a596-bf1010ad296c",
RatesID: "6504fb84-6b27-47a8-a1c6-c0d843959f89",
RatingFiltersID: "7e73a00d-be53-4083-a1ee-8ee0b546c62a",
},
},
Accounting: Accounting{
"c890a899-df43-497a-9979-38492713f57b": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.01,
},
"a894f8f1-206a-4457-99ce-df21a0c7fedc": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.005,
},
"44e97dec-8a7e-43d0-8b0a-736d46b5613e": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.1,
},
"906bfd0f-035c-40a3-93a8-46f71627983e": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
RatingID: "4607d907-02c3-4f2b-bc08-95a0dcc7222c",
Units: 1,
ExtraChargeID: "a894f8f1-206a-4457-99ce-df21a0c7fedc",
},
"a555cde8-4bd0-408a-afbc-c3ba64888927": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9d54a9e9-d610-4c82-bcb5-a315b9a65089",
Units: 1,
ExtraChargeID: "*none",
},
"44e97dec-8a7e-43d0-8b0a-e34a152": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
RatingID: "*rounding",
Units: -0.1,
ExtraChargeID: "",
},
},
RatingFilters: RatingFilters{
"7e73a00d-be53-4083-a1ee-8ee0b546c62a": RatingMatchedFilters{
"DestinationID": "GERMANY",
"DestinationPrefix": "+49",
"RatingPlanID": "RPL_RETAIL1",
"Subject": "*out:cgrates.org:call:*any",
},
},
Rates: ChargedRates{
"6504fb84-6b27-47a8-a1c6-c0d843959f89": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateIncrement: time.Minute,
RateUnit: time.Second},
},
"e5eb0f1c-3612-4e8c-b749-7f8f41dd90d4": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
&RGRate{
GroupIntervalStart: 60 * time.Second,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
},
},
Timings: ChargedTimings{
"27f1e5f8-05bb-4f1c-a596-bf1010ad296c": &ChargedTiming{
StartTime: "00:00:00",
},
},
AccountSummary: acntSummary,
}
ec := NewEventCostFromCallCost(cc, "164b0422fdc6a5117031b427439482c6a4f90e41", utils.MetaDefault)
if cost := ec.GetCost(); cost != cc.Cost {
t.Errorf("Expecting: %f, received: %f", cc.Cost, cost)
}
eUsage := time.Duration(int64(cc.RatedUsage * 1000000000))
if usage := ec.GetUsage(); usage != eUsage {
t.Errorf("Expecting: %v, received: %v", eUsage, usage)
}
if len(ec.Charges) != len(eEC.Charges) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
ec.ComputeEventCostUsageIndexes()
for i := range ec.Charges {
// Make sure main rating is correct
if cc.Timespans[i].RateInterval.Rating != nil &&
!reflect.DeepEqual(cc.Timespans[i].RateInterval.Rating.Rates,
ec.Rates[ec.Rating[ec.Charges[i].RatingID].RatesID]) {
t.Errorf("Index: %d, expecting: %+v, received: %+v",
i, utils.ToJSON(cc.Timespans[i].RateInterval.Rating.Rates),
ec.Rates[ec.Rating[ec.Charges[i].RatingID].RatesID])
}
// Make sure it matches also the expected rates
if !reflect.DeepEqual(eEC.Rates[eEC.Rating[eEC.Charges[i].RatingID].RatesID],
ec.Rates[ec.Rating[ec.Charges[i].RatingID].RatesID]) {
t.Errorf("Index: %d, expecting: %s, received: %s", i,
utils.ToJSON(eEC.Rates[eEC.Rating[eEC.Charges[i].RatingID].RatesID]),
utils.ToJSON(ec.Rates[ec.Rating[ec.Charges[i].RatingID].RatesID]))
}
if len(eEC.Charges[i].Increments) != len(ec.Charges[i].Increments) {
t.Errorf("Index %d, expecting: %+v, received: %+v",
i, eEC.Charges[i].Increments, ec.Charges[i].Increments)
}
if !reflect.DeepEqual(eEC.Charges[i].Usage(), ec.Charges[i].Usage()) {
t.Errorf("Expecting: %v, received: %v",
eEC.Charges[i].Usage(), ec.Charges[i].Usage())
}
if !reflect.DeepEqual(eEC.Charges[i].Cost(), ec.Charges[i].Cost()) {
t.Errorf("Expecting: %f, received: %f",
eEC.Charges[i].Cost(), ec.Charges[i].Cost())
}
if !reflect.DeepEqual(eEC.Charges[i].ecUsageIdx, ec.Charges[i].ecUsageIdx) {
t.Errorf("Expecting: %v, received: %v",
eEC.Charges[i].ecUsageIdx, ec.Charges[i].ecUsageIdx)
}
cIlStartTime := ec.Charges[i].StartTime(ec.StartTime)
if !cc.Timespans[i].TimeStart.Equal(cIlStartTime) {
t.Errorf("Expecting: %v, received: %v",
cc.Timespans[i].TimeStart, cIlStartTime)
}
if !cc.Timespans[i].TimeEnd.Equal(ec.Charges[i].EndTime(cIlStartTime)) {
t.Errorf("Expecting: %v, received: %v",
cc.Timespans[i].TimeStart, ec.Charges[i].EndTime(cIlStartTime))
}
}
if len(ec.Rating) != len(eEC.Rating) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
// Compare to original timestamp
if !reflect.DeepEqual(cc.Timespans[0].Increments[2].BalanceInfo.Unit.RateInterval.Rating.Rates,
ec.Rates[ec.Rating[ec.Accounting[ec.Charges[0].Increments[2].AccountingID].RatingID].RatesID]) {
t.Errorf("Expecting: %s, received: %s",
utils.ToJSON(cc.Timespans[0].Increments[2].BalanceInfo.Unit.RateInterval.Rating.Rates),
utils.ToJSON(ec.Rates[ec.Rating[ec.Accounting[ec.Charges[0].Increments[2].AccountingID].RatingID].RatesID]))
}
// Compare to expected EC
if !reflect.DeepEqual(eEC.Rates[eEC.Rating[eEC.Accounting[eEC.Charges[0].Increments[2].AccountingID].RatingID].RatesID],
ec.Rates[ec.Rating[ec.Accounting[ec.Charges[0].Increments[2].AccountingID].RatingID].RatesID]) {
t.Errorf("Expecting: %s, received: %s",
utils.ToJSON(eEC.Rates[eEC.Rating[eEC.Accounting[eEC.Charges[0].Increments[2].AccountingID].RatingID].RatesID]),
utils.ToJSON(ec.Rates[ec.Rating[ec.Accounting[ec.Charges[0].Increments[2].AccountingID].RatingID].RatesID]))
}
// Compare to expected EC
if !reflect.DeepEqual(eEC.Accounting[eEC.Charges[0].Increments[3].AccountingID],
ec.Accounting[ec.Charges[0].Increments[3].AccountingID]) {
t.Errorf("Expecting: %s, received: %s",
utils.ToJSON(eEC.Accounting[eEC.Charges[0].Increments[3].AccountingID]),
utils.ToJSON(ec.Accounting[ec.Charges[0].Increments[3].AccountingID]))
}
ec.Charges[0].Increments[3].AccountingID = eEC.Charges[0].Increments[3].AccountingID
if !reflect.DeepEqual(eEC.Charges[0].Increments[3],
ec.Charges[0].Increments[3]) {
t.Errorf("Expecting: %s, received: %s",
utils.ToJSON(eEC.Charges[0].Increments[3]),
utils.ToJSON(ec.Charges[0].Increments[3]))
}
if len(ec.Accounting) != len(eEC.Accounting) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
if len(ec.Rates) != len(eEC.Rates) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
if len(ec.Timings) != len(eEC.Timings) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
if !reflect.DeepEqual(eEC.AccountSummary, ec.AccountSummary) {
t.Errorf("Expecting: %+v, received: %+v", eEC, ec)
}
}
func TestECAsRefundIncrements(t *testing.T) {
eCD := &CallDescriptor{
CgrID: "164b0422fdc6a5117031b427439482c6a4f90e41",
RunID: utils.MetaDefault,
ToR: utils.MetaVoice,
TimeStart: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 28, 21, 0, time.UTC),
DurationIndex: 10 * time.Minute,
}
eCD.Increments = Increments{
&Increment{
Duration: 0,
Cost: 0.1,
CompressFactor: 1,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0,
CompressFactor: 10,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
},
},
&Increment{
Duration: 10 * time.Second,
Cost: 0.01,
CompressFactor: 2,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.005,
CompressFactor: 30,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
},
},
},
&Increment{
Duration: time.Second,
Cost: 0.01,
CompressFactor: 60,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.01,
CompressFactor: 60,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.01,
CompressFactor: 60,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.01,
CompressFactor: 60,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0,
CompressFactor: 10,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
},
},
&Increment{
Duration: 10 * time.Second,
Cost: 0.01,
CompressFactor: 2,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.005,
CompressFactor: 30,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
},
},
},
&Increment{
Duration: time.Second,
Cost: 0,
CompressFactor: 10,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
},
},
&Increment{
Duration: 10 * time.Second,
Cost: 0.01,
CompressFactor: 2,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.005,
CompressFactor: 30,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
},
},
},
&Increment{
Duration: time.Second,
Cost: 0,
CompressFactor: 10,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
},
},
&Increment{
Duration: 10 * time.Second,
Cost: 0.01,
CompressFactor: 2,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.005,
CompressFactor: 30,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
},
},
},
&Increment{
Duration: time.Second,
Cost: 0,
CompressFactor: 10,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
},
},
&Increment{
Duration: 10 * time.Second,
Cost: 0.01,
CompressFactor: 2,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.005,
CompressFactor: 30,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
},
},
},
&Increment{
Duration: time.Second,
Cost: 0,
CompressFactor: 10,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
},
},
&Increment{
Duration: 10 * time.Second,
Cost: 0.01,
CompressFactor: 2,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"}},
},
&Increment{
Duration: time.Second,
Cost: 0.005,
CompressFactor: 30,
BalanceInfo: &DebitInfo{
AccountID: "cgrates.org:dan",
Unit: &UnitInfo{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Factor: 1,
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
},
},
},
}
if cd := testEC.Clone().AsRefundIncrements(utils.MetaVoice); !reflect.DeepEqual(eCD, cd) {
t.Errorf("expecting: %s\n\n, received: %s", utils.ToIJSON(eCD), utils.ToIJSON(cd))
}
}
func TestECAsCallCost(t *testing.T) {
acntSummary := &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
Type: "*monetary",
Value: 50,
Disabled: false},
{
ID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Type: "*monetary",
Value: 25,
Disabled: false},
{
Type: "*voice",
Value: 200,
Disabled: false,
},
},
AllowNegative: false,
Disabled: false,
}
ec := &EventCost{
CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41",
RunID: utils.MetaDefault,
StartTime: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
Cost: utils.Float64Pointer(0.85),
Usage: utils.DurationPointer(2 * time.Minute),
Charges: []*ChargingInterval{
{
RatingID: "f2518464-68b8-42f4-acec-aef23d714314",
Increments: []*ChargingIncrement{
{
Usage: 0,
Cost: 0.1,
AccountingID: "44e97dec-8a7e-43d0-8b0a-736d46b5613e",
CompressFactor: 1,
},
{
Usage: time.Second,
Cost: 0,
AccountingID: "a555cde8-4bd0-408a-afbc-c3ba64888927",
CompressFactor: 30,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "906bfd0f-035c-40a3-93a8-46f71627983e",
CompressFactor: 30,
},
},
CompressFactor: 1,
},
{
RatingID: "f2518464-68b8-42f4-acec-aef23d714314",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "c890a899-df43-497a-9979-38492713f57b",
CompressFactor: 60,
},
},
CompressFactor: 1,
},
},
AccountSummary: acntSummary,
Rating: Rating{
"4607d907-02c3-4f2b-bc08-95a0dcc7222c": &RatingUnit{
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingID: "27f1e5f8-05bb-4f1c-a596-bf1010ad296c",
RatesID: "e5eb0f1c-3612-4e8c-b749-7f8f41dd90d4",
RatingFiltersID: "7e73a00d-be53-4083-a1ee-8ee0b546c62a",
},
"f2518464-68b8-42f4-acec-aef23d714314": &RatingUnit{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingID: "27f1e5f8-05bb-4f1c-a596-bf1010ad296c",
RatesID: "6504fb84-6b27-47a8-a1c6-c0d843959f89",
RatingFiltersID: "7e73a00d-be53-4083-a1ee-8ee0b546c62a",
},
},
Accounting: Accounting{
"c890a899-df43-497a-9979-38492713f57b": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.01,
},
"a894f8f1-206a-4457-99ce-df21a0c7fedc": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.005,
},
"44e97dec-8a7e-43d0-8b0a-736d46b5613e": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.1,
},
"906bfd0f-035c-40a3-93a8-46f71627983e": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
RatingID: "4607d907-02c3-4f2b-bc08-95a0dcc7222c",
Units: 1,
ExtraChargeID: "a894f8f1-206a-4457-99ce-df21a0c7fedc",
},
"a555cde8-4bd0-408a-afbc-c3ba64888927": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9d54a9e9-d610-4c82-bcb5-a315b9a65089",
Units: 1,
ExtraChargeID: "*none",
},
},
RatingFilters: RatingFilters{
"7e73a00d-be53-4083-a1ee-8ee0b546c62a": RatingMatchedFilters{
"DestinationID": "GERMANY",
"DestinationPrefix": "+49",
"RatingPlanID": "RPL_RETAIL1",
"Subject": "*out:cgrates.org:call:*any",
},
},
Rates: ChargedRates{
"6504fb84-6b27-47a8-a1c6-c0d843959f89": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateIncrement: time.Minute,
RateUnit: time.Second},
},
"e5eb0f1c-3612-4e8c-b749-7f8f41dd90d4": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
&RGRate{
GroupIntervalStart: 60 * time.Second,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
},
},
Timings: ChargedTimings{
"27f1e5f8-05bb-4f1c-a596-bf1010ad296c": &ChargedTiming{
StartTime: "00:00:00",
},
},
}
eCC := &CallCost{
ToR: utils.MetaVoice,
Cost: 0.85,
RatedUsage: 120000000000,
AccountSummary: acntSummary,
Timespans: TimeSpans{
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
Cost: 0.25,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
ID: "27f1e5f8-05bb-4f1c-a596-bf1010ad296c",
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateUnit: time.Second,
RateIncrement: time.Minute,
},
},
},
},
DurationIndex: time.Minute,
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{ // ConnectFee
Cost: 0.1,
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"},
AccountID: "cgrates.org:dan",
},
CompressFactor: 1,
},
&Increment{ // First 30 seconds free
Duration: time.Second,
Cost: 0,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{
UUID: "9d54a9e9-d610-4c82-bcb5-a315b9a65089",
Consumed: 1,
Factor: 1,
},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
&Increment{ // Minutes with special price
Duration: time.Second,
Cost: 0.005,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{ // Minutes with special price
UUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
Consumed: 1,
Factor: 1,
RateInterval: &RateInterval{
Timing: &RITiming{
ID: "27f1e5f8-05bb-4f1c-a596-bf1010ad296c",
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.005,
RateUnit: time.Second,
RateIncrement: time.Second,
},
&RGRate{
GroupIntervalStart: 60 * time.Second,
Value: 0.005,
RateUnit: time.Second,
RateIncrement: time.Second,
},
},
},
},
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
},
},
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 20, 21, 0, time.UTC),
Cost: 0.6,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
ID: "27f1e5f8-05bb-4f1c-a596-bf1010ad296c",
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateUnit: time.Second,
RateIncrement: time.Minute,
},
},
},
},
DurationIndex: time.Minute,
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{
Cost: 0.01,
Duration: time.Second,
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010"},
AccountID: "cgrates.org:dan",
},
CompressFactor: 60,
},
},
},
},
}
cc := ec.AsCallCost(utils.EmptyString)
if !reflect.DeepEqual(eCC, cc) {
t.Errorf("Expecting: %+v,\n received: %+v", utils.ToJSON(eCC), utils.ToJSON(cc))
}
}
func TestECAsCallCost2(t *testing.T) {
eCC := &CallCost{
ToR: utils.MetaVoice,
Cost: 0,
RatedUsage: 60000000000,
Timespans: TimeSpans{
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
Cost: 0,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: time.Duration(0),
Value: 0.01,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Minute),
},
},
},
},
DurationIndex: time.Minute,
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{ // ConnectFee
Cost: 0,
Duration: time.Minute,
BalanceInfo: &DebitInfo{},
CompressFactor: 1,
},
},
},
},
}
ec := NewEventCostFromCallCost(eCC, "cgrID", utils.MetaDefault)
for k := range ec.Timings {
eCC.Timespans[0].RateInterval.Timing.ID = k
}
cc := ec.AsCallCost(utils.EmptyString)
if !reflect.DeepEqual(eCC, cc) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eCC), utils.ToJSON(cc))
}
}
func TestECTrimZeroAndFull(t *testing.T) {
ec := testEC.Clone()
if srplsEC, err := ec.Trim(10 * time.Minute); err != nil {
t.Error(err)
} else if srplsEC != nil {
t.Errorf("Expecting nil, got: %+v", srplsEC)
}
eFullSrpls := testEC.Clone()
eFullSrpls.Usage = utils.DurationPointer(10 * time.Minute)
if srplsEC, err := ec.Trim(0); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eFullSrpls, srplsEC) {
t.Errorf("\tExpecting: %s,\n\treceived: %s",
utils.ToJSON(eFullSrpls), utils.ToJSON(srplsEC))
}
//verify the event cost
newEc := NewBareEventCost()
newEc.CGRID = eFullSrpls.CGRID
newEc.RunID = eFullSrpls.RunID
newEc.StartTime = eFullSrpls.StartTime
newEc.AccountSummary = eFullSrpls.AccountSummary.Clone()
if !reflect.DeepEqual(newEc, ec) {
t.Errorf("\tExpecting: %s,\n\treceived: %s",
utils.ToJSON(newEc), utils.ToJSON(ec))
}
}
func TestECTrimMiddle1(t *testing.T) {
// trim in the middle of increments
ec := testEC.Clone()
eEC := testEC.Clone()
eEC.Charges = []*ChargingInterval{
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: 0,
Cost: 0.1,
AccountingID: "9bdad10",
CompressFactor: 1,
},
{
Usage: time.Second,
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: 10 * time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 2,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 1,
},
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 60,
},
},
CompressFactor: 2,
},
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 10,
},
},
CompressFactor: 1,
},
}
eSrplsEC := testEC.Clone()
eSrplsEC.StartTime = time.Date(2017, 1, 9, 16, 21, 31, 0, time.UTC)
eSrplsEC.Charges = []*ChargingInterval{
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 50,
},
},
CompressFactor: 1,
},
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 60,
},
},
CompressFactor: 1,
},
{
RatingID: "c1a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: 10 * time.Second,
Cost: 0.01,
AccountingID: "a012888",
CompressFactor: 2,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 5,
},
}
reqDuration := 190 * time.Second
srplsEC, err := ec.Trim(reqDuration)
if err != nil {
t.Error(err)
}
if reqDuration != *ec.Usage {
t.Errorf("Expecting request duration: %v, received: %v", reqDuration, *ec.Usage)
}
eSrplsDur := 410 * time.Second
if srplsUsage := srplsEC.GetUsage(); srplsUsage != eSrplsDur {
t.Errorf("Expecting surplus duration: %v, received: %v", eSrplsDur, srplsUsage)
}
ec.ResetCounters()
srplsEC.ResetCounters()
if !reflect.DeepEqual(eEC, ec) {
t.Errorf("Expecting: %s\n, received: %s", utils.ToIJSON(eEC), utils.ToIJSON(ec))
}
// test surplus, which is not easy to estimate due it's different item ids
if !eSrplsEC.StartTime.Equal(srplsEC.StartTime) ||
len(eSrplsEC.Charges) != len(srplsEC.Charges) {
t.Errorf("Expecting: \n%s, received: \n%s", utils.ToIJSON(eSrplsEC), utils.ToIJSON(srplsEC))
}
}
// TestECTrimMUsage is targeting simpler testing of the durations trimmed/remainders
// using subtests so we can cover the tests with less code
func TestECTrimMUsage(t *testing.T) {
// each subtest will trim at some usage duration
testCases := []struct {
atUsage time.Duration
ecUsage time.Duration
ecCost float64
srplsUsage time.Duration
srplsCost float64
}{
{5 * time.Second, 5 * time.Second, 0.1,
595 * time.Second, 3.42},
{10 * time.Second, 10 * time.Second, 0.1,
590 * time.Second, 3.42},
{15 * time.Second, 20 * time.Second, 0.11,
580 * time.Second, 3.41},
{20 * time.Second, 20 * time.Second, 0.11,
580 * time.Second, 3.41},
{25 * time.Second, 30 * time.Second, 0.12,
570 * time.Second, 3.40},
{38 * time.Second, 38 * time.Second, 0.16,
562 * time.Second, 3.36},
{60 * time.Second, 60 * time.Second, 0.27,
540 * time.Second, 3.25},
{62 * time.Second, 62 * time.Second, 0.29,
538 * time.Second, 3.23},
{120 * time.Second, 120 * time.Second, 0.87,
480 * time.Second, 2.65},
{121 * time.Second, 121 * time.Second, 0.88,
479 * time.Second, 2.64},
{180 * time.Second, 180 * time.Second, 1.47,
420 * time.Second, 2.05},
{250 * time.Second, 250 * time.Second, 2.17,
350 * time.Second, 1.35},
{299 * time.Second, 299 * time.Second, 2.66,
301 * time.Second, 0.86},
{300 * time.Second, 300 * time.Second, 2.67,
300 * time.Second, 0.85},
{302 * time.Second, 302 * time.Second, 2.67,
298 * time.Second, 0.85},
{310 * time.Second, 310 * time.Second, 2.67,
290 * time.Second, 0.85},
{316 * time.Second, 320 * time.Second, 2.68,
280 * time.Second, 0.84},
{320 * time.Second, 320 * time.Second, 2.68,
280 * time.Second, 0.84},
{321 * time.Second, 330 * time.Second, 2.69,
270 * time.Second, 0.83},
{330 * time.Second, 330 * time.Second, 2.69,
270 * time.Second, 0.83},
{331 * time.Second, 331 * time.Second, 2.695,
269 * time.Second, 0.825},
{359 * time.Second, 359 * time.Second, 2.835,
241 * time.Second, 0.685},
{360 * time.Second, 360 * time.Second, 2.84,
240 * time.Second, 0.68},
{376 * time.Second, 380 * time.Second, 2.85,
220 * time.Second, 0.67},
{391 * time.Second, 391 * time.Second, 2.865,
209 * time.Second, 0.655},
{479 * time.Second, 479 * time.Second, 3.175,
121 * time.Second, 0.345},
{599 * time.Second, 599 * time.Second, 3.515,
time.Second, 0.005},
}
for _, tC := range testCases {
t.Run(fmt.Sprintf("AtUsage:%s", tC.atUsage), func(t *testing.T) {
var ec, srplsEC *EventCost
ec = testEC.Clone()
if srplsEC, err = ec.Trim(tC.atUsage); err != nil {
t.Fatal(err)
}
if ec.GetUsage() != tC.ecUsage {
t.Errorf("Wrongly trimmed EC: %s", utils.ToIJSON(ec))
} else if ec.GetCost() != tC.ecCost {
t.Errorf("Wrong cost for event: %s", utils.ToIJSON(ec))
}
if srplsEC.GetUsage() != tC.srplsUsage {
t.Errorf("Wrong usage: %v for surplusEC: %s", srplsEC.GetUsage(), utils.ToIJSON(srplsEC))
} else if srplsEC.GetCost() != tC.srplsCost {
t.Errorf("Wrong cost: %f in surplus: %s", srplsEC.GetCost(), utils.ToIJSON(srplsEC))
}
})
}
}
func TestECMergeGT(t *testing.T) {
// InitialEventCost
ecGT := &EventCost{
CGRID: "7636f3f1a06dffa038ba7900fb57f52d28830a24",
RunID: utils.MetaDefault,
StartTime: time.Date(2018, 7, 27, 0, 59, 21, 0, time.UTC),
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 103,
},
},
CompressFactor: 1,
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
UUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
ID: "addon_data",
Type: utils.MetaData,
Value: 10726871040},
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
ecGTUpdt := &EventCost{
CGRID: "7636f3f1a06dffa038ba7900fb57f52d28830a24",
RunID: utils.MetaDefault,
StartTime: time.Date(2018, 7, 27, 0, 59, 38, 0105472, time.UTC),
Charges: []*ChargingInterval{
{
RatingID: "6a83227",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "9288f93",
CompressFactor: 84,
},
},
CompressFactor: 1,
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
UUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
ID: "addon_data",
Type: utils.MetaData,
Value: 10718269440},
},
},
Rating: Rating{
"6a83227": &RatingUnit{
RatesID: "52f8b0f",
RatingFiltersID: "17f7216",
},
},
Accounting: Accounting{
"9288f93": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"17f7216": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"52f8b0f": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
ecGT.Merge(ecGTUpdt)
ecExpct := &EventCost{
CGRID: "7636f3f1a06dffa038ba7900fb57f52d28830a24",
RunID: utils.MetaDefault,
StartTime: time.Date(2018, 7, 27, 0, 59, 21, 0, time.UTC),
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 187,
},
},
CompressFactor: 1,
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
UUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
ID: "addon_data",
Type: utils.MetaData,
Value: 10718269440},
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
if len(ecGT.Charges) != len(ecExpct.Charges) ||
!reflect.DeepEqual(ecGT.Charges[0].TotalUsage(), ecExpct.Charges[0].TotalUsage()) ||
!reflect.DeepEqual(ecGT.Charges[0].TotalCost(), ecExpct.Charges[0].TotalCost()) {
t.Errorf("expecting: %s\n\n, received: %s",
utils.ToJSON(ecExpct), utils.ToJSON(ecGT))
}
}
func TestECAppendCIlFromEC(t *testing.T) {
// Standard compressing 1-1
ec := &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 103,
},
},
CompressFactor: 1,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
oEC := &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "6a83227",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "9288f93",
CompressFactor: 84,
},
},
CompressFactor: 1,
},
},
Rating: Rating{
"6a83227": &RatingUnit{
RatesID: "52f8b0f",
RatingFiltersID: "17f7216",
},
},
Accounting: Accounting{
"9288f93": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"17f7216": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"52f8b0f": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
ec.appendCIlFromEC(oEC, 0)
eEC := &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 187,
},
},
CompressFactor: 1,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
if !reflect.DeepEqual(eEC, ec) {
t.Errorf("expecting: %s, received: %s", utils.ToJSON(eEC), utils.ToJSON(ec))
}
// Second case, do not compress if first interval's compress factor is different than 1
ec = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 103,
},
},
CompressFactor: 2,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
oEC = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "6a83227",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "9288f93",
CompressFactor: 84,
},
},
CompressFactor: 1,
},
},
Rating: Rating{
"6a83227": &RatingUnit{
RatesID: "52f8b0f",
RatingFiltersID: "17f7216",
},
},
Accounting: Accounting{
"9288f93": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"17f7216": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"52f8b0f": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
ec.appendCIlFromEC(oEC, 0)
eEC = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 103,
},
},
CompressFactor: 2,
},
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 84,
},
},
CompressFactor: 1,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
if !reflect.DeepEqual(eEC, ec) {
t.Errorf("expecting: %s, received: %s", utils.ToJSON(eEC), utils.ToJSON(ec))
}
// Third case, split oEC
ec = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 100,
AccountingID: "0d87a64",
CompressFactor: 1,
},
},
CompressFactor: 1,
},
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 103,
},
},
CompressFactor: 1,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
oEC = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "6a83227",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "9288f93",
CompressFactor: 42,
},
{
Usage: 10240,
AccountingID: "9288f93",
CompressFactor: 20,
},
},
CompressFactor: 3,
},
},
Rating: Rating{
"6a83227": &RatingUnit{
RatesID: "52f8b0f",
RatingFiltersID: "17f7216",
},
},
Accounting: Accounting{
"9288f93": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"17f7216": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"52f8b0f": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
ec.appendCIlFromEC(oEC, 0)
eEC = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 100,
AccountingID: "0d87a64",
CompressFactor: 1,
},
},
CompressFactor: 1,
},
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 145,
},
},
CompressFactor: 1,
},
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 10240,
AccountingID: "0d87a64",
CompressFactor: 20,
},
},
CompressFactor: 1,
},
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 42,
},
{
Usage: 10240,
AccountingID: "0d87a64",
CompressFactor: 20,
},
},
CompressFactor: 2,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
if !reflect.DeepEqual(eEC, ec) {
t.Errorf("expecting: %s, received: %s", utils.ToJSON(eEC), utils.ToJSON(ec))
}
// Fourth case, increase ChargingInterval.CompressFactor
ec = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 103,
},
},
CompressFactor: 2,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
oEC = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "6a83227",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "9288f93",
CompressFactor: 103,
},
},
CompressFactor: 3,
},
},
Rating: Rating{
"6a83227": &RatingUnit{
RatesID: "52f8b0f",
RatingFiltersID: "17f7216",
},
},
Accounting: Accounting{
"9288f93": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"17f7216": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"52f8b0f": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
ec.appendCIlFromEC(oEC, 0)
eEC = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "cc68da4",
Increments: []*ChargingIncrement{
{
Usage: 102400,
AccountingID: "0d87a64",
CompressFactor: 103,
},
},
CompressFactor: 5,
},
},
Rating: Rating{
"cc68da4": &RatingUnit{
RatesID: "06dee2e",
RatingFiltersID: "216b0a5",
},
},
Accounting: Accounting{
"0d87a64": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
Units: 102400,
ExtraChargeID: utils.MetaNone,
},
},
RatingFilters: RatingFilters{
"216b0a5": RatingMatchedFilters{
"DestinationID": utils.MetaAny,
"DestinationPrefix": "42502",
"RatingPlanID": utils.MetaNone,
"Subject": "9a767726-fe69-4940-b7bd-f43de9f0f8a5",
},
},
Rates: ChargedRates{
"06dee2e": RateGroups{
&RGRate{
RateIncrement: 102400,
RateUnit: 102400},
},
},
}
if !reflect.DeepEqual(eEC, ec) {
t.Errorf("expecting: %s, received: %s", utils.ToJSON(eEC), utils.ToJSON(ec))
}
}
func TestECSyncKeys(t *testing.T) {
ec := testEC.Clone()
ec.Accounting["a012888"].RatingID = "c1a5ab9"
refEC := &EventCost{
Rating: Rating{
"21a5ab9": &RatingUnit{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
MaxCostStrategy: utils.MetaMaxCostDisconnect,
TimingID: "2f324ab",
RatesID: "2c1a177",
RatingFiltersID: "23e77dc",
},
},
Accounting: Accounting{
"2012888": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.01,
RatingID: "21a5ab9",
},
"288bfa6": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.005,
},
"24d6c02": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
RatingID: "3cd6425",
Units: 1,
ExtraChargeID: "288bfa6",
},
},
RatingFilters: RatingFilters{
"23e77dc": RatingMatchedFilters{
"DestinationID": "GERMANY",
"DestinationPrefix": "+49",
"RatingPlanID": "RPL_RETAIL1",
"Subject": "*out:cgrates.org:call:*any",
},
},
Timings: ChargedTimings{
"2f324ab": &ChargedTiming{
StartTime: "00:00:00",
},
},
Rates: ChargedRates{
"2c1a177": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateIncrement: time.Minute,
RateUnit: time.Second},
},
},
}
eEC := &EventCost{
CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41",
RunID: utils.MetaDefault,
StartTime: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
Charges: []*ChargingInterval{
{
RatingID: "21a5ab9",
Increments: []*ChargingIncrement{
{
Usage: 0,
Cost: 0.1,
AccountingID: "9bdad10",
CompressFactor: 1,
},
{
Usage: time.Second,
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: 10 * time.Second,
Cost: 0.01,
AccountingID: "2012888",
CompressFactor: 2,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 1,
},
{
RatingID: "21a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0.01,
AccountingID: "2012888",
CompressFactor: 60,
},
},
CompressFactor: 4,
},
{
RatingID: "21a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Second,
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: 10 * time.Second,
Cost: 0.01,
AccountingID: "2012888",
CompressFactor: 2,
},
{
Usage: time.Second,
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 5,
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: "BALANCE_1",
Type: utils.MetaMonetary,
Value: 50,
Initial: 60,
Weight: 20,
Disabled: false,
Factors: ValueFactors{
"factor2": 2,
"factor3": 3,
},
},
{
UUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: "BALANCE_2",
Type: utils.MetaMonetary,
Value: 25,
Initial: 60,
Weight: 0,
Disabled: false,
Factors: ValueFactors{
"factor2": 2,
},
},
{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
ID: "BALANCE_3",
Type: utils.MetaVoice,
Value: 200,
Initial: 250,
Weight: 10,
Disabled: true,
Factors: ValueFactors{
"factor4": 4,
"factor5": 5,
},
},
},
AllowNegative: false,
Disabled: false,
},
Rating: Rating{
"3cd6425": &RatingUnit{
ConnectFee: 0.4,
RoundingMethod: "*up",
RoundingDecimals: 5,
MaxCostStrategy: utils.MetaMaxCostDisconnect,
TimingID: "2f324ab",
RatesID: "4910ecf",
RatingFiltersID: "23e77dc",
},
"21a5ab9": &RatingUnit{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
MaxCostStrategy: utils.MetaMaxCostDisconnect,
TimingID: "2f324ab",
RatesID: "2c1a177",
RatingFiltersID: "23e77dc",
},
},
Accounting: Accounting{
"2012888": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.01,
RatingID: "21a5ab9",
},
"288bfa6": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.005,
},
"9bdad10": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.1,
},
"44d6c02": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
RatingID: "3cd6425",
Units: 1,
ExtraChargeID: "288bfa6",
},
"3455b83": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Units: 1,
ExtraChargeID: "*none",
},
},
RatingFilters: RatingFilters{
"23e77dc": RatingMatchedFilters{
"DestinationID": "GERMANY",
"DestinationPrefix": "+49",
"RatingPlanID": "RPL_RETAIL1",
"Subject": "*out:cgrates.org:call:*any",
},
},
Rates: ChargedRates{
"2c1a177": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.01,
RateIncrement: time.Minute,
RateUnit: time.Second},
},
"4910ecf": RateGroups{
&RGRate{
GroupIntervalStart: 0,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
&RGRate{
GroupIntervalStart: 60 * time.Second,
Value: 0.005,
RateIncrement: time.Second,
RateUnit: time.Second},
},
},
Timings: ChargedTimings{
"2f324ab": &ChargedTiming{
StartTime: "00:00:00",
},
},
cache: utils.NewSecureMapStorage(),
}
ec.SyncKeys(refEC)
if !reflect.DeepEqual(eEC, ec) {
t.Errorf("expecting: %s \nreceived: %s",
utils.ToJSON(eEC), utils.ToJSON(ec))
}
}
func TestECAsDataProvider(t *testing.T) {
ecDP := config.NewObjectDP(testEC)
if data, err := ecDP.FieldAsInterface([]string{"RunID"}); err != nil {
t.Error(err)
} else if data != utils.MetaDefault {
t.Errorf("Expecting: <%s> \nreceived: <%s>", utils.MetaDefault, data)
}
if data, err := ecDP.FieldAsInterface([]string{"AccountSummary", "ID"}); err != nil {
t.Error(err)
} else if data != "dan" {
t.Errorf("Expecting: <%s> \nreceived: <%s>", "data", data)
}
if data, err := ecDP.FieldAsInterface([]string{"AccountSummary", "BalanceSummaries[1]", "UUID"}); err != nil {
t.Error(err)
} else if data != "7a54a9e9-d610-4c82-bcb5-a315b9a65010" {
t.Errorf("Expecting: <%s> \nreceived: <%s>", "4b8b53d7-c1a1-4159-b845-4623a00a0165", data)
}
if data, err := ecDP.FieldAsInterface([]string{"AccountSummary", "BalanceSummaries[2]", "Type"}); err != nil {
t.Error(err)
} else if data != "*voice" {
t.Errorf("Expecting: <%s> \nreceived: <%s>", "*voice", data)
}
}
func TestInitCache(t *testing.T) {
eventCost := &EventCost{}
eventCost.initCache()
eOut := utils.NewSecureMapStorage()
if !reflect.DeepEqual(eOut, eventCost.cache) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eOut), utils.ToJSON(eventCost.cache))
}
}
func TestEventCostFieldAsInterface(t *testing.T) {
eventCost := &EventCost{}
eventCost.initCache()
// item found in cache
eventCost.cache = utils.NewSecureMapStorage()
eventCost.cache.Set([]string{"test"}, nil)
if rcv, err := eventCost.FieldAsInterface([]string{"test"}); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: nil, received: %+v", err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// data found in cache
eventCost.cache.Set([]string{"test"}, "test")
if rcv, err := eventCost.FieldAsInterface([]string{"test"}); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if rcv != "test" {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
}
func TestEventCostfieldAsInterface(t *testing.T) {
eventCost := &EventCost{}
// default case
if rcv, err := eventCost.fieldAsInterface([]string{utils.EmptyString}); err == nil || err.Error() != "unsupported field prefix: <>" {
t.Error(err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// case utils.Charges:
if rcv, err := eventCost.fieldAsInterface([]string{utils.Charges, utils.Charges}); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
eventCost = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "RatingID1",
},
{
RatingID: "RatingID2",
},
},
}
expectedCharges := []*ChargingInterval{
{
RatingID: "RatingID1",
},
{
RatingID: "RatingID2",
},
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Charges}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expectedCharges, rcv) {
t.Errorf("Expecting: %+v, received: %+v", expectedCharges, rcv)
}
// case utils.CGRID:
if rcv, err := eventCost.fieldAsInterface([]string{utils.CGRID, utils.CGRID}); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
eventCost = &EventCost{
CGRID: "CGRID",
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.CGRID}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual("CGRID", rcv) {
t.Errorf("Expecting: \"CGRID\", received: %+v", rcv)
}
// case utils.RunID:
if rcv, err := eventCost.fieldAsInterface([]string{utils.RunID, utils.RunID}); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
eventCost = &EventCost{
RunID: "RunID",
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.RunID}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual("RunID", rcv) {
t.Errorf("Expecting: \"RunID\", received: %+v", rcv)
}
// case utils.StartTime:
if rcv, err := eventCost.fieldAsInterface([]string{utils.StartTime, utils.StartTime}); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
eventCost = &EventCost{
StartTime: time.Date(2020, time.April, 18, 23, 0, 4, 0, time.UTC),
}
expectedStartTime := time.Date(2020, time.April, 18, 23, 0, 4, 0, time.UTC)
if rcv, err := eventCost.fieldAsInterface([]string{utils.StartTime}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expectedStartTime, rcv) {
t.Errorf("Expecting: %+v, received: %+v", expectedStartTime, rcv)
}
// case utils.Usage:
if rcv, err := eventCost.fieldAsInterface([]string{utils.Usage, utils.Usage}); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
eventCost = &EventCost{
Usage: utils.DurationPointer(5 * time.Minute),
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Usage}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(5*time.Minute, rcv) {
t.Errorf("Expecting: %+v, received: %+v", 5*time.Minute, rcv)
}
// case utils.Cost:
if rcv, err := eventCost.fieldAsInterface([]string{utils.Cost, utils.Cost}); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
eventCost = &EventCost{
Cost: utils.Float64Pointer(0.7),
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Cost}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(0.7, rcv) {
t.Errorf("Expecting: %+v, received: %+v", 0.7, rcv)
}
// case utils.AccountSummary:
eventCost = &EventCost{
AccountSummary: &AccountSummary{
ID: "IDtest",
},
}
expectedAccountSummary := &AccountSummary{ID: "IDtest"}
if rcv, err := eventCost.fieldAsInterface([]string{utils.AccountSummary}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expectedAccountSummary, rcv) {
t.Errorf("Expecting: %+v, received: %+v", expectedAccountSummary, rcv)
}
eventCost = &EventCost{
AccountSummary: &AccountSummary{
ID: "IDtest1",
Tenant: "Tenant",
},
CGRID: "test",
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.AccountSummary, utils.Tenant}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual("Tenant", rcv) {
t.Errorf("Expecting: Tenant, received: %+v", utils.ToJSON(rcv))
}
// case utils.Timings:
eventCost = &EventCost{
Timings: ChargedTimings{
"test1": &ChargedTiming{
StartTime: "StartTime",
},
},
}
eTimings := ChargedTimings{"test1": &ChargedTiming{StartTime: "StartTime"}}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Timings}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eTimings, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eTimings, rcv)
}
eChargedTiming := &ChargedTiming{
StartTime: "StartTime",
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Timings, "test1"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eChargedTiming, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eChargedTiming), utils.ToJSON(rcv))
}
// case utils.Rates:
eventCost = &EventCost{
Rates: ChargedRates{
"test1": RateGroups{
&RGRate{Value: 0.7},
},
},
}
eChargedRates := ChargedRates{
"test1": RateGroups{
&RGRate{Value: 0.7},
},
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Rates}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eChargedRates, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eChargedRates), utils.ToJSON(rcv))
}
eRateGroup := RateGroups{
&RGRate{Value: 0.7},
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Rates, "test1"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eRateGroup, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRateGroup), utils.ToJSON(rcv))
}
// case utils.RatingFilters:
eventCost = &EventCost{
RatingFilters: RatingFilters{
"test1": RatingMatchedFilters{
AccountActionsCSVContent: "AccountActionsCSVContent",
},
},
}
eRatingFilters := RatingFilters{
"test1": RatingMatchedFilters{
AccountActionsCSVContent: "AccountActionsCSVContent",
},
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.RatingFilters}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eRatingFilters, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRatingFilters), utils.ToJSON(rcv))
}
eRatingMatchedFilters := RatingMatchedFilters{
AccountActionsCSVContent: "AccountActionsCSVContent",
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.RatingFilters, "test1"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eRatingMatchedFilters, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRatingMatchedFilters), utils.ToJSON(rcv))
}
// case utils.Accounting:
eventCost = &EventCost{
Accounting: Accounting{
"test1": &BalanceCharge{
AccountID: "AccountID",
},
},
}
eAccounting := Accounting{
"test1": &BalanceCharge{
AccountID: "AccountID",
},
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Accounting}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eAccounting, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eAccounting), utils.ToJSON(rcv))
}
eBalanceCharge := &BalanceCharge{
AccountID: "AccountID",
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Accounting, "test1"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eBalanceCharge, rcv) {
t.Errorf("Expecting: %+v, \nreceived: %+v", utils.ToJSON(eBalanceCharge), utils.ToJSON(rcv))
}
// case utils.Rating:
eventCost = &EventCost{
Rating: Rating{
"test1": &RatingUnit{
ConnectFee: 0.7,
},
},
}
eRating := Rating{
"test1": &RatingUnit{
ConnectFee: 0.7,
},
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Rating}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eRating, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRating), utils.ToJSON(rcv))
}
eRateUnit := &RatingUnit{
ConnectFee: 0.7,
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Rating, "test1"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eRateUnit, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRateUnit), utils.ToJSON(rcv))
}
//default case, utils.Charges
eventCost = &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "RatingID",
},
},
}
eCharges := []*ChargingInterval{{RatingID: "RatingID"}}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Charges}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCharges, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eCharges), utils.ToJSON(rcv))
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Charges + "[0]"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCharges[0], rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eCharges[0]), utils.ToJSON(rcv))
}
if rcv, err := eventCost.fieldAsInterface([]string{utils.Charges + "[1]"}); err == nil || err != utils.ErrNotFound {
t.Error(err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
}
func TestEventCostgetChargesForPath(t *testing.T) {
eventCost := &EventCost{}
chargingInterval := &ChargingInterval{
RatingID: "RatingID",
}
// chr == nil
if rcv, err := eventCost.getChargesForPath(nil, nil); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// len(fldPath) == 0
eChargingInterval := &ChargingInterval{
RatingID: "RatingID",
}
if rcv, err := eventCost.getChargesForPath([]string{}, chargingInterval); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eChargingInterval, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eChargingInterval, rcv)
}
// fldPath[0] == utils.CompressFactor
chargingInterval = &ChargingInterval{
RatingID: "RatingID",
CompressFactor: 7,
}
if rcv, err := eventCost.getChargesForPath([]string{utils.CompressFactor}, chargingInterval); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if rcv != 7 {
t.Errorf("Expecting: 7, received: %+v", rcv)
}
if rcv, err := eventCost.getChargesForPath([]string{utils.CompressFactor, "mustFail"}, chargingInterval); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// fldPath[0] == utils.Rating
eventCost = &EventCost{
Rates: ChargedRates{
"RatingID": RateGroups{&RGRate{Value: 0.8}}},
}
if rcv, err := eventCost.getChargesForPath([]string{utils.Rating}, chargingInterval); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
eventCost = &EventCost{
Rating: Rating{"RatingID": &RatingUnit{}},
Rates: ChargedRates{
"RatingID": RateGroups{&RGRate{Value: 0.8}}},
}
if rcv, err := eventCost.getChargesForPath([]string{utils.Rating, "unsupportedfield"}, chargingInterval); err == nil || err.Error() != "unsupported field prefix: <unsupportedfield>" {
t.Errorf("Expecting: unsupported field prefix: <unsupportedfield>, received: %+v", err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
chargingInterval = &ChargingInterval{
RatingID: "RatingID",
CompressFactor: 7,
}
eventCost = &EventCost{
Rating: Rating{"RatingID": &RatingUnit{
RatesID: "RatesID",
}},
Rates: ChargedRates{"RatesID": RateGroups{&RGRate{Value: 0.8}}},
}
RateGroups := RateGroups{&RGRate{Value: 0.8}}
if rcv, err := eventCost.getChargesForPath([]string{utils.Rating, utils.Rates}, chargingInterval); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(RateGroups, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(RateGroups), utils.ToJSON(rcv))
t.Errorf("Expecting: %+v, received: %+v", RateGroups, rcv)
}
// opath != utils.Increments
if rcv, err := eventCost.getChargesForPath([]string{"unsupportedfield"}, chargingInterval); err == nil || err.Error() != "unsupported field prefix: <unsupportedfield>" {
t.Errorf("Expecting: unsupported field prefix: <unsupportedfield>, received: %+v", err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// utils.Increments
eventCost = &EventCost{}
chargingInterval = &ChargingInterval{
Increments: []*ChargingIncrement{
{
AccountingID: "AccountingID",
},
},
}
eChargingIncrement := &ChargingIncrement{
AccountingID: "AccountingID",
}
if rcv, err := eventCost.getChargesForPath([]string{"Increments[0]"}, chargingInterval); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eChargingIncrement, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eChargingIncrement, rcv)
}
eIncrements := []*ChargingIncrement{
{
AccountingID: "AccountingID",
},
}
// indx == nil
if rcv, err := eventCost.getChargesForPath([]string{"Increments"}, chargingInterval); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eIncrements, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eIncrements, utils.ToJSON(rcv))
}
// len(fldPath) != 1
if rcv, err := eventCost.getChargesForPath([]string{"Increments", utils.Accounting}, chargingInterval); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// fldPath[1] == utils.Accounting
eventCost = &EventCost{
Accounting: Accounting{
"AccountingID": &BalanceCharge{
AccountID: "AccountID",
},
},
}
eBalanceCharge := &BalanceCharge{AccountID: "AccountID"}
if rcv, err := eventCost.getChargesForPath([]string{"Increments[0]", utils.Accounting}, chargingInterval); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eBalanceCharge, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eBalanceCharge, rcv)
}
}
func TestEventCostgetRatingForPath(t *testing.T) {
eventCost := &EventCost{}
ratingUnit := &RatingUnit{}
// rating == nil
if rcv, err := eventCost.getRatingForPath(nil, nil); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// len(fldPath) == 0
eratingUnit := &RatingUnit{}
if rcv, err := eventCost.getRatingForPath([]string{}, ratingUnit); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eratingUnit, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eratingUnit, rcv)
}
// case utils.Rates:
eventCost = &EventCost{
Rates: ChargedRates{
"RatesID": RateGroups{
&RGRate{Value: 0.7},
},
},
}
eChargedRates := RateGroups{
&RGRate{Value: 0.7},
}
// !has || rts == nil
ratingUnit = &RatingUnit{
RatesID: "notfound",
}
if rcv, err := eventCost.getRatingForPath([]string{utils.Rates}, ratingUnit); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// len(fldPath) != 1
ratingUnit = &RatingUnit{
RatesID: "RatesID",
}
if rcv, err := eventCost.getRatingForPath([]string{utils.Rates, utils.Rates}, ratingUnit); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
//normal case
if rcv, err := eventCost.getRatingForPath([]string{utils.Rates}, ratingUnit); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eChargedRates, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eChargedRates), utils.ToJSON(rcv))
}
// case utils.Timing:
eventCost = &EventCost{
Timings: ChargedTimings{
"test1": &ChargedTiming{
StartTime: "StartTime",
},
},
}
eTimings := &ChargedTiming{
StartTime: "StartTime",
}
// !has || tmg == nil
ratingUnit = &RatingUnit{
TimingID: "notfound",
}
if rcv, err := eventCost.getRatingForPath([]string{utils.Timing}, ratingUnit); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// len(fldPath) == 1
ratingUnit = &RatingUnit{
TimingID: "test1",
}
if rcv, err := eventCost.getRatingForPath([]string{utils.Timing}, ratingUnit); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eTimings, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eTimings), utils.ToJSON(rcv))
}
//normal case
eventCost = &EventCost{
Timings: ChargedTimings{
"test1": &ChargedTiming{
Months: utils.Months{time.April},
StartTime: "StartTime",
},
},
}
eMonths := utils.Months{time.April}
if rcv, err := eventCost.getRatingForPath([]string{utils.Timing, utils.MonthsFieldName}, ratingUnit); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eMonths, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eMonths), utils.ToJSON(rcv))
}
// case utils.RatingFilter:
eventCost = &EventCost{
RatingFilters: RatingFilters{
"RatingFilters1": RatingMatchedFilters{
"test1": "test1",
},
},
}
eRatingMatchedFilters := RatingMatchedFilters{
"test1": "test1",
}
// !has || tmg == nil
ratingUnit = &RatingUnit{
TimingID: "notfound",
}
if rcv, err := eventCost.getRatingForPath([]string{utils.RatingFilter}, ratingUnit); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// len(fldPath) == 1
ratingUnit = &RatingUnit{
RatingFiltersID: "RatingFilters1",
}
if rcv, err := eventCost.getRatingForPath([]string{utils.RatingFilter}, ratingUnit); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eRatingMatchedFilters, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eRatingMatchedFilters, rcv)
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRatingMatchedFilters), utils.ToJSON(rcv))
}
//normal case
eventCost = &EventCost{
RatingFilters: RatingFilters{
"RatingFilters1": RatingMatchedFilters{
"test1": "test-1",
},
},
}
if rcv, err := eventCost.getRatingForPath([]string{utils.RatingFilter, "test1"}, ratingUnit); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual("test-1", rcv) {
t.Errorf("Expecting: test-1, received: %+v", utils.ToJSON(rcv))
}
//default case
eventCost = &EventCost{
Rates: ChargedRates{
"RatesID": RateGroups{
&RGRate{Value: 0.7},
},
"RatesID2": RateGroups{
&RGRate{Value: 0.7},
},
},
}
if rcv, err := eventCost.getRatingForPath([]string{
"unsupportedprefix"}, ratingUnit); err == nil || err.Error() != "unsupported field prefix: <unsupportedprefix>" {
t.Errorf("Expecting: 'unsupported field prefix: <unsupportedprefix>', received: %+v", err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", utils.ToJSON(rcv))
}
ratingUnit = &RatingUnit{
RatesID: "RatesID",
}
eRate := &RGRate{Value: 0.7}
if rcv, err := eventCost.getRatingForPath([]string{"Rates[0]"}, ratingUnit); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eRate, rcv) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eRate), utils.ToJSON(rcv))
}
ratingUnit = &RatingUnit{}
if rcv, err := eventCost.getRatingForPath([]string{"Rates[1]"}, ratingUnit); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
}
func TestEventCostgetAcountingForPath(t *testing.T) {
eventCost := &EventCost{}
balanceCharge := &BalanceCharge{}
// bc == nil
if rcv, err := eventCost.getAcountingForPath(nil, nil); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// len(fldPath) == 0
eBalanceCharge := &BalanceCharge{}
if rcv, err := eventCost.getAcountingForPath([]string{}, balanceCharge); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eBalanceCharge, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eBalanceCharge, rcv)
}
// fldPath[0] == utils.Balance
eventCost = &EventCost{
AccountSummary: &AccountSummary{
BalanceSummaries: BalanceSummaries{
{
ID: "ID",
},
},
},
}
eBalanceSummaries := &BalanceSummary{
ID: "ID",
}
//len(fldPath) == 1
if rcv, err := eventCost.getAcountingForPath([]string{utils.BalanceField}, balanceCharge); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual(eBalanceSummaries, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eBalanceSummaries, rcv)
}
// bl == nil
eventCost = &EventCost{AccountSummary: &AccountSummary{}}
if rcv, err := eventCost.getAcountingForPath([]string{utils.BalanceField}, balanceCharge); err == nil || err != utils.ErrNotFound {
t.Errorf("Expecting: %+v, received: %+v", utils.ErrNotFound, err)
} else if rcv != nil {
t.Errorf("Expecting: nil, received: %+v", rcv)
}
// len(fldPath) != 1
eventCost = &EventCost{
AccountSummary: &AccountSummary{
BalanceSummaries: BalanceSummaries{
{
ID: "ID",
},
},
},
}
if rcv, err := eventCost.getAcountingForPath([]string{utils.BalanceField, "ID"}, balanceCharge); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual("ID", rcv) {
t.Errorf("Expecting: \"ID\", received: %+v", rcv)
}
// fldPath[0] != utils.Balance
balanceCharge = &BalanceCharge{
AccountID: "AccountID",
}
if rcv, err := eventCost.getAcountingForPath([]string{utils.AccountID}, balanceCharge); err != nil {
t.Errorf("Expecting: nil, received: %+v", err)
} else if !reflect.DeepEqual("AccountID", rcv) {
t.Errorf("Expecting: \"AccountID\", received: %+v", rcv)
}
}
func TestEventCostString(t *testing.T) {
eventCost := &EventCost{}
eOut := `{"CGRID":"","RunID":"","StartTime":"0001-01-01T00:00:00Z","Usage":null,"Cost":null,"Charges":null,"AccountSummary":null,"Rating":null,"Accounting":null,"RatingFilters":null,"Rates":null,"Timings":null}`
if rcv := eventCost.String(); !reflect.DeepEqual(eOut, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eOut, rcv)
}
eventCost = &EventCost{
AccountSummary: &AccountSummary{
BalanceSummaries: BalanceSummaries{
&BalanceSummary{
ID: "ID",
},
},
},
}
eOut = `{"CGRID":"","RunID":"","StartTime":"0001-01-01T00:00:00Z","Usage":null,"Cost":null,"Charges":null,"AccountSummary":{"Tenant":"","ID":"","BalanceSummaries":[{"UUID":"","ID":"ID","Type":"","Initial":0,"Value":0,"Disabled":false}],"AllowNegative":false,"Disabled":false},"Rating":null,"Accounting":null,"RatingFilters":null,"Rates":null,"Timings":null}`
if rcv := eventCost.String(); !reflect.DeepEqual(eOut, rcv) {
t.Errorf("Expecting: %+v, received: %+v", eOut, rcv)
}
}
func TestEventCostFieldAsString(t *testing.T) {
eventCost := &EventCost{
CGRID: "CGRID",
}
eventCost.initCache()
if rcv, err := eventCost.FieldAsString([]string{utils.CGRID}); err != nil {
t.Error(err)
} else if rcv != "CGRID" {
t.Errorf("Expecting: CGRID, received: %+v", rcv)
}
if rcv, err := eventCost.FieldAsString([]string{"err"}); err == nil || err.Error() != "unsupported field prefix: <err>" {
t.Error(err)
} else if !reflect.DeepEqual(rcv, utils.EmptyString) {
t.Errorf("Expecting: EmptyString, received: %+v", rcv)
}
}
func TestECAsCallCost3(t *testing.T) {
eCC := &CallCost{
Category: "call",
Tenant: "cgrates.org",
Subject: "dan",
Account: "dan",
Destination: "+4986517174963",
ToR: utils.MetaVoice,
Cost: 0.85,
RatedUsage: 120.0,
Timespans: TimeSpans{
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
Cost: 0.25,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: time.Duration(0),
Value: 0.01,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Minute),
},
},
},
},
DurationIndex: time.Duration(1 * time.Minute),
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{ // ConnectFee
Cost: 0.1,
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.MetaDefault,
Value: 9.9},
AccountID: "cgrates.org:dan",
},
CompressFactor: 1,
},
&Increment{ // First 30 seconds free
Duration: time.Duration(1 * time.Second),
Cost: 0,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{
UUID: "9d54a9e9-d610-4c82-bcb5-a315b9a65089",
ID: "free_mins",
Value: 0,
Consumed: 1.0,
ToR: utils.MetaVoice,
},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
&Increment{ // Minutes with special price
Duration: time.Duration(1 * time.Second),
Cost: 0.005,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{ // Minutes with special price
UUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: "discounted_mins",
Value: 0,
Consumed: 1.0,
ToR: utils.MetaVoice,
RateInterval: &RateInterval{
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: time.Duration(0),
Value: 0.005,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Second),
},
&RGRate{
GroupIntervalStart: time.Duration(60 * time.Second),
Value: 0.005,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Second),
},
},
},
},
},
Monetary: &MonetaryInfo{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.MetaDefault,
Value: 9.75},
AccountID: "cgrates.org:dan",
},
CompressFactor: 30,
},
},
},
&TimeSpan{
TimeStart: time.Date(2017, 1, 9, 16, 19, 21, 0, time.UTC),
TimeEnd: time.Date(2017, 1, 9, 16, 20, 21, 0, time.UTC),
Cost: 0.6,
RateInterval: &RateInterval{ // standard rating
Timing: &RITiming{
StartTime: "00:00:00",
},
Rating: &RIRate{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
Rates: RateGroups{
&RGRate{
GroupIntervalStart: time.Duration(0),
Value: 0.01,
RateUnit: time.Duration(1 * time.Second),
RateIncrement: time.Duration(1 * time.Minute),
},
},
},
},
DurationIndex: time.Duration(1 * time.Minute),
MatchedSubject: "*out:cgrates.org:call:*any",
MatchedPrefix: "+49",
MatchedDestId: "GERMANY",
RatingPlanId: "RPL_RETAIL1",
CompressFactor: 1,
Increments: Increments{
&Increment{
Cost: 0.01,
Duration: time.Duration(1 * time.Second),
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
ID: utils.MetaDefault,
Value: 9.15},
AccountID: "cgrates.org:dan",
},
CompressFactor: 60,
},
},
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
Type: utils.MetaMonetary,
Value: 50,
Disabled: false},
{
ID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Type: utils.MetaMonetary,
Value: 25,
Disabled: false},
{
Type: utils.MetaVoice,
Value: 200,
Disabled: false,
},
},
AllowNegative: false,
Disabled: false,
},
}
eEC := &EventCost{
CGRID: "164b0422fdc6a5117031b427439482c6a4f90e41",
RunID: utils.MetaDefault,
StartTime: time.Date(2017, 1, 9, 16, 18, 21, 0, time.UTC),
Charges: []*ChargingInterval{
{
RatingID: "21a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Duration(0),
Cost: 0.1,
AccountingID: "9bdad10",
CompressFactor: 1,
},
{
Usage: time.Duration(1 * time.Second),
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: time.Duration(10 * time.Second),
Cost: 0.01,
AccountingID: "2012888",
CompressFactor: 2,
},
{
Usage: time.Duration(1 * time.Second),
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 1,
},
{
RatingID: "21a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Duration(1 * time.Second),
Cost: 0.01,
AccountingID: "2012888",
CompressFactor: 60,
},
},
CompressFactor: 4,
},
{
RatingID: "21a5ab9",
Increments: []*ChargingIncrement{
{
Usage: time.Duration(1 * time.Second),
Cost: 0,
AccountingID: "3455b83",
CompressFactor: 10,
},
{
Usage: time.Duration(10 * time.Second),
Cost: 0.01,
AccountingID: "2012888",
CompressFactor: 2,
},
{
Usage: time.Duration(1 * time.Second),
Cost: 0.005,
AccountingID: "44d6c02",
CompressFactor: 30,
},
},
CompressFactor: 5,
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "dan",
BalanceSummaries: []*BalanceSummary{
{
UUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Type: utils.MetaMonetary,
Value: 50,
Disabled: false},
{
UUID: "7a54a9e9-d610-4c82-bcb5-a315b9a65010",
Type: utils.MetaMonetary,
Value: 25,
Disabled: false},
{
UUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Type: utils.MetaVoice,
Value: 200,
Disabled: false,
},
},
AllowNegative: false,
Disabled: false,
},
Rating: Rating{
"3cd6425": &RatingUnit{
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingID: "2f324ab",
RatesID: "4910ecf",
RatingFiltersID: "23e77dc",
},
"21a5ab9": &RatingUnit{
ConnectFee: 0.1,
RoundingMethod: "*up",
RoundingDecimals: 5,
TimingID: "2f324ab",
RatesID: "2c1a177",
RatingFiltersID: "23e77dc",
},
},
Accounting: Accounting{
"2012888": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.01,
RatingID: "21a5ab9",
},
"288bfa6": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.005,
},
"9bdad10": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
Units: 0.1,
},
"44d6c02": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
RatingID: "3cd6425",
Units: 1,
ExtraChargeID: "288bfa6",
},
"3455b83": &BalanceCharge{
AccountID: "cgrates.org:dan",
BalanceUUID: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
Units: 1,
ExtraChargeID: "*none",
},
},
RatingFilters: RatingFilters{
"23e77dc": RatingMatchedFilters{
"DestinationID": "GERMANY",
"DestinationPrefix": "+49",
"RatingPlanID": "RPL_RETAIL1",
"Subject": "*out:cgrates.org:call:*any",
},
},
Rates: ChargedRates{
"2c1a177": RateGroups{
&RGRate{
GroupIntervalStart: time.Duration(0),
Value: 0.01,
RateIncrement: time.Duration(1 * time.Minute),
RateUnit: time.Duration(1 * time.Second)},
},
"4910ecf": RateGroups{
&RGRate{
GroupIntervalStart: time.Duration(0),
Value: 0.005,
RateIncrement: time.Duration(1 * time.Second),
RateUnit: time.Duration(1 * time.Second)},
&RGRate{
GroupIntervalStart: time.Duration(60 * time.Second),
Value: 0.005,
RateIncrement: time.Duration(1 * time.Second),
RateUnit: time.Duration(1 * time.Second)},
},
},
Timings: ChargedTimings{
"2f324ab": &ChargedTiming{
StartTime: "00:00:00",
},
},
cache: utils.NewSecureMapStorage(),
}
ec := NewEventCostFromCallCost(eCC, "cgrID", utils.MetaDefault)
eEC.SyncKeys(ec)
ec.Merge(eEC)
if _, err := ec.Trim(time.Second); err != nil {
t.Fatal(err)
}
}
func TestECAsDataProvider2(t *testing.T) {
ecDP := testEC
if data, err := ecDP.FieldAsInterface([]string{"RunID"}); err != nil {
t.Error(err)
} else if data != utils.MetaDefault {
t.Errorf("Expecting: <%s> \nreceived: <%s>", utils.MetaDefault, data)
}
if data, err := ecDP.FieldAsInterface([]string{"AccountSummary", "ID"}); err != nil {
t.Error(err)
} else if data != "dan" {
t.Errorf("Expecting: <%s> \nreceived: <%s>", "data", data)
}
if data, err := ecDP.FieldAsInterface([]string{"AccountSummary", "BalanceSummaries[1]", "UUID"}); err != nil {
t.Error(err)
} else if data != "7a54a9e9-d610-4c82-bcb5-a315b9a65010" {
t.Errorf("Expecting: <%s> \nreceived: <%s>", "4b8b53d7-c1a1-4159-b845-4623a00a0165", data)
}
if data, err := ecDP.FieldAsInterface([]string{"AccountSummary", "BalanceSummaries[2]", "Type"}); err != nil {
t.Error(err)
} else if data != "*voice" {
t.Errorf("Expecting: <%s> \nreceived: <%s>", "*voice", data)
}
ecDP = &EventCost{AccountSummary: &AccountSummary{}}
ecDP.initCache()
if _, err := ecDP.FieldAsInterface([]string{"AccountSummary", "BalanceSummaries[0]", "Type"}); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Errorf("Unexpected error:%v", err)
}
if _, err := ecDP.FieldAsInterface([]string{"Charges[0]", "Increments"}); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Errorf("Unexpected error:%v", err)
}
ecDP.Charges = []*ChargingInterval{{}}
if _, err := ecDP.FieldAsInterface([]string{"Charges[0]", "Increments[0]"}); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Errorf("Unexpected error:%v", err)
}
ecDP.Rating = Rating{"": {}}
ecDP.Rates = ChargedRates{"": {}, "b": {}}
if _, err := ecDP.FieldAsInterface([]string{"Charges[0]", "Rating", "Rates[0]"}); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Errorf("Unexpected error:%v", err)
}
if _, err := ecDP.FieldAsInterface([]string{"Rates", "b[0]"}); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Errorf("Unexpected error:%v", err)
}
}
func TestECAsDataProvider3(t *testing.T) {
ecDP := testEC
testDPs := []struct {
name string
fields []string
exp any
}{
{
name: "StartTime",
fields: []string{"Charges[0]", "Rating", "Timing", "StartTime"},
exp: "00:00:00",
},
{
name: "RateIncrement",
fields: []string{"Charges[0]", "Rating", "Rates[0]", "RateIncrement"},
exp: "1m0s",
},
{
name: "DestinationID",
fields: []string{"Charges[0]", "Rating", "RatingFilter", "DestinationID"},
exp: "GERMANY",
},
{
name: "Units",
fields: []string{"Charges[0]", "Increments[0]", "Accounting", "Units"},
exp: "0.1",
},
{
name: "Subject",
fields: []string{"Charges[0]", "Rating", "RatingFilter", "Subject"},
exp: "*out:cgrates.org:call:*any",
},
{
name: "Value",
fields: []string{"Charges[2]", "Increments[2]", "Accounting", "Balance", "Value"},
exp: "200",
},
{
name: "Type",
fields: []string{"Charges[1]", "Increments[0]", "Accounting", "Balance", "Type"},
exp: "*monetary",
},
{
name: "UUID",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Balance", "UUID"},
exp: "4b8b53d7-c1a1-4159-b845-4623a00a0165",
},
{
name: "ID",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Balance", "ID"},
exp: "BALANCE_3",
},
{
name: "Initial",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Balance", "Initial"},
exp: "250",
},
{
name: "Disabled",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Balance", "Disabled"},
exp: "true",
},
{
name: "Weight",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Balance", "Weight"},
exp: "10",
},
{
name: "Factors map",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Balance", "Factors"},
exp: `{"factor4":4,"factor5":5}`,
},
{
name: "Factors value",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Balance", "Factors", "factor4"},
exp: "4",
},
{
name: "IncrementCost",
fields: []string{"Charges[0]", "Increments[2]", "Cost"},
exp: "0.01",
},
{
name: "DestinationPrefix",
fields: []string{"Charges[2]", "Rating", "RatingFilter", "DestinationPrefix"},
exp: "+49",
},
{
name: "RatingPlanID",
fields: []string{"Charges[2]", "Rating", "RatingFilter", "RatingPlanID"},
exp: "RPL_RETAIL1",
},
{
name: "AccountID",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "AccountID"},
exp: "cgrates.org:dan",
},
{
name: "RateValue",
fields: []string{"Charges[1]", "Rating", "Rates[0]", "Value"},
exp: "0.01",
},
{
name: "RateUnit",
fields: []string{"Charges[2]", "Rating", "Rates[0]", "RateUnit"},
exp: "1s",
},
{
name: "BalanceFactor",
fields: []string{"Charges[0]", "Increments[1]", "Accounting", "BalanceFactor"},
exp: "1",
},
{
name: "ExtraCharge",
fields: []string{"Charges[0]", "Increments[1]", "Accounting", "ExtraChargeID"},
exp: "*none",
},
{
name: "AccountSummary",
fields: []string{"AccountSummary", "BalanceSummaries[1]", "Value"},
exp: "25",
},
{
name: "RoundingMethod",
fields: []string{"AccountSummary", "AllowNegative"},
exp: "false",
},
{
name: "CompressFactor",
fields: []string{"Charges[0]", "CompressFactor"},
exp: "1",
},
{
name: "ConnectFee through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "ConnectFee"},
exp: "0.4",
},
{
name: "RoundingMethod through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "RoundingMethod"},
exp: utils.MetaRoundingUp,
},
{
name: "RoundingDecimals through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "RoundingDecimals"},
exp: "5",
},
{
name: "MaxCost through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "MaxCost"},
exp: "0",
},
{
name: "MaxCostStrategy through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "MaxCostStrategy"},
exp: utils.MetaMaxCostDisconnect,
},
{
name: "TimingID through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "TimingID"},
exp: "7f324ab",
},
{
name: "RatesID through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "RatesID"},
exp: "4910ecf",
},
{
name: "RatingFiltersID through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "RatingFiltersID"},
exp: "43e77dc",
},
{
name: "ConnectFee",
fields: []string{"Charges[0]", "Rating", "ConnectFee"},
exp: "0.1",
},
{
name: "RoundingMethod",
fields: []string{"Charges[0]", "Rating", "RoundingMethod"},
exp: utils.MetaRoundingUp,
},
{
name: "RoundingDecimals",
fields: []string{"Charges[0]", "Rating", "RoundingDecimals"},
exp: "5",
},
{
name: "MaxCost",
fields: []string{"Charges[0]", "Rating", "MaxCost"},
exp: "0",
},
{
name: "MaxCostStrategy",
fields: []string{"Charges[0]", "Rating", "MaxCostStrategy"},
exp: utils.MetaMaxCostDisconnect,
},
{
name: "TimingID",
fields: []string{"Charges[0]", "Rating", "TimingID"},
exp: "7f324ab",
},
{
name: "RatesID",
fields: []string{"Charges[0]", "Rating", "RatesID"},
exp: "ec1a177",
},
{
name: "RatingFiltersID",
fields: []string{"Charges[0]", "Rating", "RatingFiltersID"},
exp: "43e77dc",
},
{
name: "DestinationID through Accounting",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "Rating", "RatingFilter", "DestinationID"},
exp: "GERMANY",
},
{
name: "Value through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "Value"},
exp: "50",
},
{
name: "Type through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "Type"},
exp: utils.MetaMonetary,
},
{
name: "UUID through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "UUID"},
exp: "8c54a9e9-d610-4c82-bcb5-a315b9a65010",
},
{
name: "ID through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "ID"},
exp: "BALANCE_1",
},
{
name: "Initial through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "Initial"},
exp: "60",
},
{
name: "Disabled through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "Disabled"},
exp: "false",
},
{
name: "Weight through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "Weight"},
exp: "20",
},
{
name: "Factors map through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "Factors"},
exp: `{"factor2":2,"factor3":3}`,
},
{
name: "Factors value through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Balance", "Factors", "factor3"},
exp: "3",
},
{
name: "AccountID through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "AccountID"},
exp: "cgrates.org:dan",
},
{
name: "Units through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "Units"},
exp: "0.005",
},
{
name: "BalanceFactor through ExtraCharge",
fields: []string{"Charges[0]", "Increments[3]", "Accounting", "ExtraCharge", "BalanceFactor"},
exp: "1",
},
// ~*ec.Charges[0].Increments[3].Accounting.Rating.ConnectFee
// ~*ec.Charges[0].Rating.ConnectFee
// ~*ec.Charges[0].Increments[0].Accounting.Rating.RatingFilter.DestinationID
}
for _, testDp := range testDPs {
t.Run(testDp.name, func(t *testing.T) {
if val, err := ecDP.FieldAsString(testDp.fields); err != nil {
t.Error(err)
} else if testDp.exp != val {
t.Errorf("Expecting: <%s> \nreceived: <%s>", testDp.exp, val)
}
})
}
}
func TestECFieldAsInterfaceNilEventCost(t *testing.T) {
dft := config.NewDefaultCGRConfig()
cdr, err := NewMapEvent(map[string]any{}).AsCDR(dft, "cgrates.org", "UTC")
if err != nil {
t.Fatal(err)
}
nM := cdr.AsMapStorage()
if _, err := nM.FieldAsInterface([]string{"*ec", "Charges[0]", "Increments[0]", "Accounting", "Balance", "ID"}); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Fatalf("Expected error:%s, received: %v", utils.ErrNotFound.Error(), err)
}
if _, err := nM.FieldAsInterface([]string{"*req", "CostDetails", "Charges[0]", "Increments[0]", "Accounting", "Balance", "ID"}); err == nil || err.Error() != utils.ErrNotFound.Error() {
t.Fatalf("Expected error:%s, received: %v", utils.ErrNotFound.Error(), err)
}
}
func TestECnewChargingIncrementMissingBalanceInfo(t *testing.T) {
ec := &EventCost{}
incr := &Increment{}
rf := make(RatingMatchedFilters)
exp := &ChargingIncrement{
Usage: incr.Duration,
Cost: incr.Cost,
CompressFactor: incr.CompressFactor,
}
rcv := ec.newChargingIncrement(incr, rf, false, false)
if !reflect.DeepEqual(rcv, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}
func TestECnewChargingIncrementWithUnitInfo(t *testing.T) {
ec := &EventCost{
Accounting: Accounting{},
}
incr := &Increment{
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{},
Monetary: &MonetaryInfo{},
},
}
rf := make(RatingMatchedFilters)
exp := &ChargingIncrement{
Usage: incr.Duration,
Cost: incr.Cost,
CompressFactor: incr.CompressFactor,
AccountingID: utils.MetaPause,
}
rcv := ec.newChargingIncrement(incr, rf, false, true)
if !reflect.DeepEqual(rcv, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}
func TestECnewChargingIncrementNoUnitInfo(t *testing.T) {
ec := &EventCost{
Accounting: Accounting{},
}
incr := &Increment{
BalanceInfo: &DebitInfo{
Monetary: &MonetaryInfo{},
},
}
rf := make(RatingMatchedFilters)
exp := &ChargingIncrement{
Usage: incr.Duration,
Cost: incr.Cost,
CompressFactor: incr.CompressFactor,
AccountingID: utils.MetaPause,
}
expEC := &EventCost{
Accounting: Accounting{
utils.MetaPause: &BalanceCharge{},
},
}
rcv := ec.newChargingIncrement(incr, rf, false, true)
if !reflect.DeepEqual(rcv, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
if !reflect.DeepEqual(ec, expEC) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", expEC, ec)
}
}
func TestECAsRefundIncrementsNoCharges(t *testing.T) {
ec := &EventCost{
Charges: []*ChargingInterval{},
CGRID: "asdfgh",
RunID: "runID",
StartTime: time.Date(2021, 4, 13, 17, 0, 0, 0, time.UTC),
Usage: utils.DurationPointer(time.Hour),
Cost: utils.Float64Pointer(10),
}
exp := &CallDescriptor{
CgrID: "asdfgh",
RunID: "runID",
ToR: utils.MetaVoice,
TimeStart: time.Date(2021, 4, 13, 17, 0, 0, 0, time.UTC),
TimeEnd: time.Date(2021, 4, 13, 18, 0, 0, 0, time.UTC),
DurationIndex: time.Hour,
}
rcv := ec.AsRefundIncrements(utils.MetaVoice)
if !reflect.DeepEqual(rcv, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}
func TestECAsRefundIncrements2(t *testing.T) {
ec := &EventCost{
Charges: []*ChargingInterval{
{
cost: utils.Float64Pointer(10),
CompressFactor: 1,
Increments: []*ChargingIncrement{
{
Cost: 5,
Usage: 2 * time.Second,
AccountingID: "accID",
CompressFactor: 1,
},
},
},
},
CGRID: "asdfgh",
RunID: "runID",
StartTime: time.Date(2021, 4, 13, 17, 0, 0, 0, time.UTC),
Usage: utils.DurationPointer(time.Hour),
Cost: utils.Float64Pointer(10),
Accounting: Accounting{
"accID": &BalanceCharge{
AccountID: "bcAccID",
BalanceUUID: "bcUUID",
ExtraChargeID: "extrachargeID",
},
"extrachargeID": &BalanceCharge{
AccountID: "extraAccID",
BalanceUUID: "extraBcUUID",
},
},
AccountSummary: &AccountSummary{
BalanceSummaries: BalanceSummaries{
{
UUID: "bcUUID",
Type: utils.MetaSMS,
},
{
UUID: "extraBcUUID",
Type: utils.MetaSMS,
},
},
},
}
exp := &CallDescriptor{
CgrID: "asdfgh",
RunID: "runID",
ToR: utils.MetaVoice,
TimeStart: time.Date(2021, 4, 13, 17, 0, 0, 0, time.UTC),
TimeEnd: time.Date(2021, 4, 13, 18, 0, 0, 0, time.UTC),
DurationIndex: time.Hour,
Increments: Increments{
{
Duration: 2 * time.Second,
Cost: 5,
BalanceInfo: &DebitInfo{
Unit: &UnitInfo{
UUID: "extraBcUUID",
Factor: 1,
},
AccountID: "bcAccID",
},
CompressFactor: 1,
},
},
}
rcv := ec.AsRefundIncrements(utils.MetaVoice)
if !reflect.DeepEqual(rcv, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}
func TestECratingGetIDFromEventCostPause(t *testing.T) {
ec := &EventCost{
Timings: ChargedTimings{
utils.MetaPause: &ChargedTiming{},
},
RatingFilters: RatingFilters{
utils.MetaPause: RatingMatchedFilters{},
},
Rates: ChargedRates{
utils.MetaPause: RateGroups{},
},
Rating: Rating{
utils.MetaPause: &RatingUnit{},
},
}
oEC := &EventCost{
Rating: Rating{
utils.MetaPause: &RatingUnit{
ConnectFee: 0.4,
RoundingMethod: "*up",
RoundingDecimals: 4,
MaxCost: 100,
MaxCostStrategy: "*disconnect",
TimingID: "TM_NOON",
},
},
Timings: ChargedTimings{
utils.MetaPause: &ChargedTiming{
Years: utils.Years{2010, 2011},
Months: utils.Months{1, 2},
MonthDays: utils.MonthDays{24, 25},
WeekDays: utils.WeekDays{2},
StartTime: "00:00:00",
},
},
}
oRatingID := utils.MetaPause
exp := utils.MetaPause
rcv := ec.ratingGetIDFromEventCost(oEC, oRatingID)
if rcv != exp {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}
func TestECaccountingGetIDFromEventCostPause(t *testing.T) {
ec := &EventCost{
Timings: ChargedTimings{
utils.MetaPause: &ChargedTiming{},
},
RatingFilters: RatingFilters{
utils.MetaPause: RatingMatchedFilters{},
},
Rates: ChargedRates{
utils.MetaPause: RateGroups{},
},
Rating: Rating{
utils.MetaPause: &RatingUnit{},
},
Accounting: Accounting{
utils.MetaPause: &BalanceCharge{},
},
}
oEC := &EventCost{
Accounting: Accounting{
utils.MetaPause: &BalanceCharge{
AccountID: "1001",
BalanceUUID: "asdfg",
RatingID: utils.MetaPause,
Units: 10,
ExtraChargeID: "extra",
},
},
Rating: Rating{
utils.MetaPause: &RatingUnit{
ConnectFee: 0.4,
RoundingMethod: "*up",
RoundingDecimals: 4,
MaxCost: 100,
MaxCostStrategy: "*disconnect",
TimingID: "TM_NOON",
},
},
}
oAccountingID := utils.MetaPause
exp := utils.MetaPause
rcv := ec.accountingGetIDFromEventCost(oEC, oAccountingID)
if rcv != exp {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}
func TestECappendChargingIntervalFromEventCost(t *testing.T) {
ec := &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "RT_ID",
CompressFactor: 1,
},
},
}
oEC := &EventCost{
Charges: []*ChargingInterval{
{},
{
RatingID: "RT_ID",
},
},
}
cIlIdx := 1
exp := &EventCost{
Charges: []*ChargingInterval{
{
RatingID: "RT_ID",
CompressFactor: 2,
},
},
}
ec.appendChargingIntervalFromEventCost(oEC, cIlIdx)
if !reflect.DeepEqual(ec, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", exp, ec)
}
}
func TestECratingIDForRateIntervalPause(t *testing.T) {
ec := &EventCost{
RatingFilters: RatingFilters{},
Rating: Rating{},
Rates: ChargedRates{},
}
ri := &RateInterval{
Rating: &RIRate{
ConnectFee: 0.4,
RoundingMethod: "*up",
MaxCost: 100,
MaxCostStrategy: "*disconnect",
RoundingDecimals: 4,
Rates: RateGroups{
{
RateIncrement: 60,
RateUnit: 60,
Value: 10,
GroupIntervalStart: 1,
},
},
},
}
rf := RatingMatchedFilters{
"key": "filter",
}
exp := utils.MetaPause
expEC := &EventCost{
Rating: Rating{
utils.MetaPause: &RatingUnit{
ConnectFee: 0.4,
RoundingMethod: "*up",
MaxCost: 100,
MaxCostStrategy: "*disconnect",
RoundingDecimals: 4,
RatesID: utils.MetaPause,
RatingFiltersID: utils.MetaPause,
},
},
RatingFilters: RatingFilters{
utils.MetaPause: RatingMatchedFilters{
"key": "filter",
},
},
Rates: ChargedRates{
utils.MetaPause: RateGroups{
{
RateIncrement: 60,
RateUnit: 60,
Value: 10,
GroupIntervalStart: 1,
},
},
},
}
rcv := ec.ratingIDForRateInterval(ri, rf, true)
if rcv != exp {
t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
if !reflect.DeepEqual(ec, expEC) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", expEC, ec)
}
}
func TestECnewIntervalFromCharge(t *testing.T) {
ec := &EventCost{
Charges: []*ChargingInterval{
{
Increments: []*ChargingIncrement{
{
Usage: 100,
Cost: 10,
AccountingID: "accID1",
CompressFactor: 1,
},
{
Usage: 150,
Cost: 15,
AccountingID: "accID2",
CompressFactor: 1,
},
},
},
},
Accounting: Accounting{
"accID1": &BalanceCharge{
RatingID: utils.MetaRounding,
BalanceUUID: "asdfgh1",
AccountID: "1001",
},
"accID2": &BalanceCharge{
RatingID: utils.MetaRounding,
BalanceUUID: "asdfgh2",
AccountID: "1001",
},
},
Rating: Rating{
utils.MetaRounding: &RatingUnit{
ConnectFee: 0.4,
RoundingMethod: "*up",
RoundingDecimals: 4,
MaxCost: 100,
MaxCostStrategy: "*disconnect",
RatesID: "RT_ID",
TimingID: "TM_NOON",
},
},
Timings: ChargedTimings{
"TM_NOON": &ChargedTiming{
StartTime: "00:00:00",
},
},
AccountSummary: &AccountSummary{
Tenant: "cgrates.org",
ID: "1001",
AllowNegative: true,
BalanceSummaries: BalanceSummaries{
&BalanceSummary{
UUID: "asdfgh1",
ID: "bsID",
Type: utils.MetaData,
Initial: 0,
Value: 10,
Disabled: true,
},
},
},
}
cInc := &ChargingIncrement{
AccountingID: "accID1",
}
exp := &Increment{
BalanceInfo: &DebitInfo{
AccountID: "1001",
Unit: &UnitInfo{
UUID: "asdfgh1",
Factor: 1,
RateInterval: &RateInterval{
Rating: &RIRate{
RoundingDecimals: 4,
RoundingMethod: "*up",
ConnectFee: 0.4,
MaxCost: 100,
MaxCostStrategy: "*disconnect",
},
Timing: &RITiming{
ID: "TM_NOON",
StartTime: "00:00:00",
},
},
},
},
}
rcv := ec.newIntervalFromCharge(cInc)
if !reflect.DeepEqual(rcv, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(rcv))
}
}
func TestECRemoveStaleReferences(t *testing.T) {
ec := &EventCost{
Rating: Rating{
"unusedKey1": &RatingUnit{
ConnectFee: 0.4,
RoundingMethod: "*up",
RoundingDecimals: 4,
MaxCost: 100,
MaxCostStrategy: "*disconnect",
TimingID: "TM_MORNING",
RatesID: "RT_ID",
RatingFiltersID: "RF_ID",
},
},
RatingFilters: RatingFilters{
"unusedKey2": RatingMatchedFilters{},
},
Rates: ChargedRates{
"unusedKey3": RateGroups{
{
RateIncrement: 60,
RateUnit: 60,
Value: 10,
},
},
},
Timings: ChargedTimings{
"unusedKey4": &ChargedTiming{
StartTime: "00:00:00",
},
},
}
exp := &EventCost{
Rating: Rating{},
RatingFilters: RatingFilters{},
Rates: ChargedRates{},
Timings: ChargedTimings{
"unusedKey4": &ChargedTiming{
StartTime: "00:00:00",
},
},
}
ec.RemoveStaleReferences()
if !reflect.DeepEqual(ec, exp) {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(ec))
}
}
func TestECTrimUnreachableLastChargingInterval(t *testing.T) {
ec := &EventCost{
Usage: utils.DurationPointer(30 * time.Second),
AccountSummary: &AccountSummary{},
Charges: []*ChargingInterval{
{
RatingID: "RT_ID",
cost: utils.Float64Pointer(10),
ecUsageIdx: utils.DurationPointer(1),
},
},
}
atUsage := 15 * time.Second
experr := "cannot find last active ChargingInterval"
rcv, err := ec.Trim(atUsage)
if err == nil || err.Error() != experr {
t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err)
}
if rcv != nil {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
}
}
func TestECTrimNoActiveIncrement(t *testing.T) {
ec := &EventCost{
Usage: utils.DurationPointer(30 * time.Second),
AccountSummary: &AccountSummary{},
Charges: []*ChargingInterval{
{
RatingID: "RT_ID",
cost: utils.Float64Pointer(10),
ecUsageIdx: utils.DurationPointer(1 * time.Second),
CompressFactor: 4,
usage: utils.DurationPointer(45 * time.Second),
},
},
}
atUsage := 15 * time.Second
experr := "no active increment found"
rcv, err := ec.Trim(atUsage)
if err == nil || err.Error() != experr {
t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err)
}
if rcv != nil {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
}
}
func TestECTrimUnableToDetectLastActiveChargingInterval(t *testing.T) {
ec := &EventCost{
Usage: utils.DurationPointer(30 * time.Second),
AccountSummary: &AccountSummary{},
Charges: []*ChargingInterval{
{
RatingID: "RT_ID1",
cost: utils.Float64Pointer(10),
ecUsageIdx: utils.DurationPointer(30 * time.Second),
CompressFactor: 0,
usage: utils.DurationPointer(45 * time.Second),
},
{
RatingID: "RT_ID2",
cost: utils.Float64Pointer(10),
ecUsageIdx: utils.DurationPointer(25 * time.Second),
CompressFactor: 4,
usage: utils.DurationPointer(45 * time.Second),
},
},
}
atUsage := 15 * time.Second
experr := "failed detecting last active ChargingInterval"
rcv, err := ec.Trim(atUsage)
if err == nil || err.Error() != experr {
t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err)
}
if rcv != nil {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
}
}
func TestECFieldAsInterfaceEmptyFieldPath(t *testing.T) {
ec := &EventCost{}
fldPath := []string{}
experr := "empty field path"
rcv, err := ec.FieldAsInterface(fldPath)
if err == nil || err.Error() != experr {
t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err)
}
if rcv != nil {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
}
}
func TestECfieldAsInterfaceNilECUsage(t *testing.T) {
ec := &EventCost{}
fldPath := []string{utils.Usage}
rcv, err := ec.fieldAsInterface(fldPath)
if err != nil {
t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", nil, err)
}
if rcv != nil {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
}
}
func TestECfieldAsInterfaceNilECCost(t *testing.T) {
ec := &EventCost{}
fldPath := []string{utils.Cost}
rcv, err := ec.fieldAsInterface(fldPath)
if err != nil {
t.Fatalf("\nexpected: <%+v>, \nreceived: <%+v>", nil, err)
}
if rcv != nil {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, rcv)
}
}
func TestEventCostSet(t *testing.T) {
ec := &EventCost{}
testCases := []struct {
name string
fldPath []string
val interface{}
wantErr error
}{
{
name: "cgrates",
fldPath: []string{"field1"},
val: "value1",
wantErr: utils.ErrNotImplemented,
},
{
name: "cgrates2",
fldPath: []string{"field2", "subfield"},
val: 123,
wantErr: utils.ErrNotImplemented,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := ec.Set(tc.fldPath, tc.val)
if err != tc.wantErr {
t.Errorf("Set() error = %v, wantErr %v", err, tc.wantErr)
}
})
}
}
func TestEventCostRemove(t *testing.T) {
ec := &EventCost{}
testCases := []struct {
name string
fldPath []string
wantErr error
}{
{
name: "cgrates",
fldPath: []string{"field1"},
wantErr: utils.ErrNotImplemented,
},
{
name: "cgrates2",
fldPath: []string{"field2", "subfield"},
wantErr: utils.ErrNotImplemented,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := ec.Remove(tc.fldPath)
if err != tc.wantErr {
t.Errorf("Remove() error = %v, wantErr %v", err, tc.wantErr)
}
})
}
}
func TestEventCostGetKeys(t *testing.T) {
ec := &EventCost{}
testCases := []struct {
name string
nested bool
nestedLimit int
prefix string
expectedKeys []string
}{
{
name: "cgrates",
nested: true,
nestedLimit: 3,
prefix: "prefix",
expectedKeys: nil,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
keys := ec.GetKeys(tc.nested, tc.nestedLimit, tc.prefix)
if !reflect.DeepEqual(keys, tc.expectedKeys) {
t.Errorf("GetKeys() returned %+v, expected %+v", keys, tc.expectedKeys)
}
})
}
}
func TestEvenCostProcessEventCostField(t *testing.T) {
testCases := []struct {
name string
fldPath []string
cd interface{}
event map[string]interface{}
expectedValue interface{}
expectedErr error
}{
{
name: "cgrates",
fldPath: []string{"field1"},
cd: nil,
event: make(map[string]interface{}),
expectedValue: nil,
expectedErr: errors.New("unsupported field prefix: <field1>"),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
val, err := processEventCostField(tc.fldPath, tc.cd, tc.event)
if !reflect.DeepEqual(val, tc.expectedValue) {
t.Errorf("ProcessEventCostField() returned %+v, expected %+v", val, tc.expectedValue)
}
if (err == nil && tc.expectedErr != nil) || (err != nil && tc.expectedErr == nil) || (err != nil && tc.expectedErr != nil && err.Error() != tc.expectedErr.Error()) {
t.Errorf("ProcessEventCostField() error = %v, expected error = %v", err, tc.expectedErr)
}
})
}
}
func TestConvertToEventCost(t *testing.T) {
eventCost := &EventCost{
CGRID: "cgrid",
RunID: "run_id",
StartTime: time.Now(),
}
convertedEventCost, err := ConvertToEventCost(eventCost)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if convertedEventCost != eventCost {
t.Error("Expected identical EventCost objects")
}
eventCostJSON, _ := json.Marshal(eventCost)
convertedEventCost, err = ConvertToEventCost(string(eventCostJSON))
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
tStruct := struct {
CGRID string `json:"CGRID"`
RunID string `json:"RunID"`
}{
CGRID: "cgrid",
RunID: "run_id",
}
convertedEventCost, err = ConvertToEventCost(tStruct)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if convertedEventCost.CGRID != "cgrid" || convertedEventCost.RunID != "run_id" {
t.Error("Expected correct values for CGRID and RunID")
}
_, err = ConvertToEventCost(123)
if err == nil {
t.Error("Expected error for invalid input type")
}
invalidJSON := []byte("invalid_json")
_, err = ConvertToEventCost(invalidJSON)
if err == nil {
t.Error("Expected error for invalid JSON")
}
}