refactor profile sorting for chargers

This commit is contained in:
ionutboangiu
2025-03-24 16:02:52 +02:00
committed by Dan Christian Bogos
parent 0b26559d1f
commit b00b2f07ae
7 changed files with 40 additions and 69 deletions

View File

@@ -47,7 +47,7 @@ func (cS *ChargerS) V1ProcessEvent(ctx *context.Context, args *utils.CGREvent,
// V1GetChargersForEvent exposes the list of ordered matching ChargingProfiles for an event
func (cS *ChargerS) V1GetChargersForEvent(ctx *context.Context, args *utils.CGREvent,
rply *utils.ChargerProfiles) (err error) {
rply *[]*utils.ChargerProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = cS.cfg.GeneralCfg().DefaultTenant

View File

@@ -19,6 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package chargers
import (
"cmp"
"slices"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
@@ -40,7 +43,7 @@ func NewChargerService(dm *engine.DataManager, filterS *engine.FilterS,
}
// matchingChargingProfilesForEvent returns ordered list of matching chargers which are active by the time of the function call
func (cS *ChargerS) matchingChargerProfilesForEvent(ctx *context.Context, tnt string, cgrEv *utils.CGREvent) (cPs utils.ChargerProfiles, err error) {
func (cS *ChargerS) matchingChargerProfilesForEvent(ctx *context.Context, tnt string, cgrEv *utils.CGREvent) (cPs []*utils.ChargerProfile, err error) {
evNm := utils.MapStorage{
utils.MetaReq: cgrEv.Event,
utils.MetaOpts: cgrEv.APIOpts,
@@ -58,6 +61,8 @@ func (cS *ChargerS) matchingChargerProfilesForEvent(ctx *context.Context, tnt st
if err != nil {
return nil, err
}
weights := make(map[string]float64) // stores sorting weights by profile ID
for cpID := range cpIDs {
cP, err := cS.dm.GetChargerProfile(ctx, tnt, cpID, true, true, utils.NonTransactional)
if err != nil {
@@ -76,13 +81,18 @@ func (cS *ChargerS) matchingChargerProfilesForEvent(ctx *context.Context, tnt st
if err != nil {
return nil, err
}
cP.ApplySortingWeight(weight)
weights[cP.ID] = weight
cPs = append(cPs, cP)
}
if len(cPs) == 0 {
return nil, utils.ErrNotFound
}
cPs.Sort()
// Sort by weight (higher values first).
slices.SortFunc(cPs, func(a, b *utils.ChargerProfile) int {
return cmp.Compare(weights[b.ID], weights[a.ID])
})
for i, cp := range cPs {
var blocker bool
if blocker, err = engine.BlockerFromDynamics(ctx, cp.Blockers, cS.fltrS, tnt, evNm); err != nil {
@@ -104,8 +114,8 @@ type ChrgSProcessEventReply struct {
}
func (cS *ChargerS) processEvent(ctx *context.Context, tnt string, cgrEv *utils.CGREvent) (rply []*ChrgSProcessEventReply, err error) {
var cPs utils.ChargerProfiles
if cPs, err = cS.matchingChargerProfilesForEvent(ctx, tnt, cgrEv); err != nil {
cPs, err := cS.matchingChargerProfilesForEvent(ctx, tnt, cgrEv)
if err != nil {
return nil, err
}

View File

@@ -761,7 +761,7 @@ func testChargersSetGetChargerProfileEvent(t *testing.T) {
}
func testChargersGetChargersForEvent(t *testing.T) {
expected := &utils.ChargerProfiles{
expected := []*utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "TEST_CHARGERS_IT_TEST",
@@ -783,7 +783,7 @@ func testChargersGetChargersForEvent(t *testing.T) {
},
APIOpts: map[string]any{},
}
reply := &utils.ChargerProfiles{}
var reply []*utils.ChargerProfile
if err := chargersRPC.Call(context.Background(), utils.ChargerSv1GetChargersForEvent,
cgrEv, &reply); err != nil {
t.Error(err)
@@ -956,7 +956,7 @@ func testChargersBlockerGetChargersForEvent(t *testing.T) {
},
APIOpts: map[string]any{},
}
expected := utils.ChargerProfiles{
expected := []*utils.ChargerProfile{
{
ID: "CHARGER_TEST_1",
Tenant: "cgrates.org",
@@ -1001,7 +1001,7 @@ func testChargersBlockerGetChargersForEvent(t *testing.T) {
RunID: "run2",
},
}
var reply utils.ChargerProfiles
var reply utils.ChargerProfile
if err := chargersRPC.Call(context.Background(), utils.ChargerSv1GetChargersForEvent, args, &reply); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(reply, expected) {

View File

@@ -34,8 +34,8 @@ import (
func TestChargerSetChargerProfiles(t *testing.T) {
var dmCharger *engine.DataManager
cPPs := utils.ChargerProfiles{
&utils.ChargerProfile{
cPPs := []*utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_1",
FilterIDs: []string{"FLTR_CP_1", "FLTR_CP_4", "*string:~*opts.*subsys:*chargers", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -47,7 +47,7 @@ func TestChargerSetChargerProfiles(t *testing.T) {
},
},
},
&utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_2",
FilterIDs: []string{"FLTR_CP_2", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -59,7 +59,7 @@ func TestChargerSetChargerProfiles(t *testing.T) {
},
},
},
&utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_3",
FilterIDs: []string{"FLTR_CP_3", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -152,8 +152,8 @@ func TestChargerMatchingChargerProfilesForEvent(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
var chargerSrv *ChargerS
var dmCharger *engine.DataManager
cPPs := utils.ChargerProfiles{
&utils.ChargerProfile{
cPPs := []*utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_1",
FilterIDs: []string{"FLTR_CP_1", "FLTR_CP_4", "*string:~*opts.*subsys:*chargers", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -165,7 +165,7 @@ func TestChargerMatchingChargerProfilesForEvent(t *testing.T) {
},
},
},
&utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_2",
FilterIDs: []string{"FLTR_CP_2", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -177,7 +177,7 @@ func TestChargerMatchingChargerProfilesForEvent(t *testing.T) {
},
},
},
&utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_3",
FilterIDs: []string{"FLTR_CP_3", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -322,8 +322,8 @@ func TestChargerProcessEvent(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
var chargerSrv *ChargerS
var dmCharger *engine.DataManager
cPPs := utils.ChargerProfiles{
&utils.ChargerProfile{
cPPs := []*utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_1",
FilterIDs: []string{"FLTR_CP_1", "FLTR_CP_4", "*string:~*opts.*subsys:*chargers", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -335,7 +335,7 @@ func TestChargerProcessEvent(t *testing.T) {
},
},
},
&utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_2",
FilterIDs: []string{"FLTR_CP_2", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -347,7 +347,7 @@ func TestChargerProcessEvent(t *testing.T) {
},
},
},
&utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_3",
FilterIDs: []string{"FLTR_CP_3", "*ai:~*req.AnswerTime:2014-07-14T14:25:00Z"},
@@ -461,7 +461,6 @@ func TestChargerProcessEvent(t *testing.T) {
}
//verify each charger from cache
for _, cp := range cPPs {
cp.ApplySortingWeight(20) // cached ChargerProfiles have weight==20
if tempCp, err := dmCharger.GetChargerProfile(context.Background(), cp.Tenant, cp.ID,
true, false, utils.NonTransactional); err != nil {
t.Errorf("Error: %+v", err)
@@ -886,7 +885,7 @@ func TestChargersmatchingChargerProfilesForEventBlockerTrue(t *testing.T) {
},
}
exp := utils.ChargerProfiles{
exp := []*utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "CPP_2",
@@ -1445,9 +1444,9 @@ func TestChargersV1GetChargersForEventNilErr(t *testing.T) {
utils.AccountField: "1001",
},
}
reply := &utils.ChargerProfiles{}
var reply []*utils.ChargerProfile
exp := &utils.ChargerProfiles{
exp := []*utils.ChargerProfile{
{
Tenant: "cgrates.org",
ID: "1001",
@@ -1455,7 +1454,7 @@ func TestChargersV1GetChargersForEventNilErr(t *testing.T) {
RunID: "*default",
},
}
err := cS.V1GetChargersForEvent(context.Background(), args, reply)
err := cS.V1GetChargersForEvent(context.Background(), args, &reply)
if err != nil {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", nil, err)
@@ -1495,11 +1494,10 @@ func TestChargersV1GetChargersForEventErr(t *testing.T) {
utils.AccountField: "1001",
},
}
reply := &utils.ChargerProfiles{}
exp := &utils.ChargerProfiles{}
var reply []*utils.ChargerProfile
var exp []*utils.ChargerProfile
experr := fmt.Sprintf("SERVER_ERROR: %s", utils.ErrNotImplemented)
err := cS.V1GetChargersForEvent(context.Background(), args, reply)
err := cS.V1GetChargersForEvent(context.Background(), args, &reply)
if err == nil || err.Error() != experr {
t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", experr, err)

View File

@@ -59,6 +59,6 @@ func (self *CmdGetChargersForEvent) PostprocessRpcParams() error {
}
func (self *CmdGetChargersForEvent) RpcResult() any {
var atr utils.ChargerProfiles
var atr []*utils.ChargerProfile
return &atr
}

View File

@@ -18,18 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package utils
import (
"sort"
)
// ChargerProfiles is a sortable list of Charger profiles
type ChargerProfiles []*ChargerProfile
// Sort is part of sort interface, sort based on Weight.
func (cp ChargerProfiles) Sort() {
sort.Slice(cp, func(i, j int) bool { return cp[i].weight > cp[j].weight })
}
// ChargerProfile defines the configuration of a Charger.
type ChargerProfile struct {
Tenant string
@@ -39,12 +27,6 @@ type ChargerProfile struct {
Blockers DynamicBlockers
RunID string
AttributeIDs []string // perform data aliasing based on these Attributes
weight float64
}
// ApplySortingWeight assigns a weight value used for sorting ChargerProfiles.
func (cp *ChargerProfile) ApplySortingWeight(weight float64) {
cp.weight = weight
}
// TenantID returns the concatenated tenant and ID.

View File

@@ -71,25 +71,6 @@ func TestChargerProfileSet(t *testing.T) {
}
}
func TestChargerProfilesSort(t *testing.T) {
cp := ChargerProfiles{{}, {Weights: DynamicWeights{
{
Weight: 20,
},
},
weight: 20}}
exp := ChargerProfiles{{Weights: DynamicWeights{
{
Weight: 20,
},
},
weight: 20}, {}}
cp.Sort()
if !reflect.DeepEqual(exp, cp) {
t.Errorf("Expected %v \n but received \n %v", ToJSON(exp), ToJSON(cp))
}
}
func TestChargerProfileAsInterface(t *testing.T) {
cp := ChargerProfile{
Tenant: "cgrates.org",