Update QOS strategy to take the average of metrics

This commit is contained in:
TeoV
2019-02-28 11:06:31 +02:00
committed by Dan Christian Bogos
parent 8f7f414d0c
commit cc818b0199
3 changed files with 97 additions and 559 deletions

View File

@@ -20,11 +20,9 @@ package engine
import (
"fmt"
"net"
"sort"
"strings"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
@@ -95,29 +93,21 @@ func (sSpls *SortedSuppliers) SortHighestCost() {
// SortQOS is part of sort interface,
// sort based on Stats
func (sSpls *SortedSuppliers) SortQOS(params []string) {
//sort the metrics before sorting the suppliers
for _, val := range sSpls.SortedSuppliers {
for _, iface := range val.SortingData {
if castedVal, canCast := iface.(SplStatMetrics); canCast {
castedVal.Sort()
}
}
}
//sort suppliers
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
for _, param := range params {
//in case we have the same value for the current param we skip to the next one
if sSpls.SortedSuppliers[i].SortingData[param].(SplStatMetrics)[0].MetricValue == sSpls.SortedSuppliers[j].SortingData[param].(SplStatMetrics)[0].MetricValue {
if sSpls.SortedSuppliers[i].SortingData[param].(float64) == sSpls.SortedSuppliers[j].SortingData[param].(float64) {
continue
}
switch sSpls.SortedSuppliers[i].SortingData[param].(SplStatMetrics)[0].metricType {
switch param {
default:
if sSpls.SortedSuppliers[i].SortingData[param].(SplStatMetrics)[0].MetricValue > sSpls.SortedSuppliers[j].SortingData[param].(SplStatMetrics)[0].MetricValue {
if sSpls.SortedSuppliers[i].SortingData[param].(float64) > sSpls.SortedSuppliers[j].SortingData[param].(float64) {
return true
}
return false
case utils.MetaPDD: //in case of pdd the smalles value if the best
if sSpls.SortedSuppliers[i].SortingData[param].(SplStatMetrics)[0].MetricValue < sSpls.SortedSuppliers[j].SortingData[param].(SplStatMetrics)[0].MetricValue {
if sSpls.SortedSuppliers[i].SortingData[param].(float64) < sSpls.SortedSuppliers[j].SortingData[param].(float64) {
return true
}
return false
@@ -191,98 +181,3 @@ func (ssd SupplierSortDispatcher) SortSuppliers(prflID, strategy string,
}
return sd.SortSuppliers(prflID, suppls, suplEv, extraOpts)
}
//StatMetric used to store the statID and the metric value
type SplStatMetric struct {
StatID string
MetricValue float64
metricType string
}
//StatMetrics is a sortable list of StatMetric
type SplStatMetrics []*SplStatMetric
// Sort is part of sort interface, sort based on Weight
func (sm SplStatMetrics) Sort() {
sort.Slice(sm, func(i, j int) bool {
switch sm[i].metricType {
default:
return sm[i].MetricValue < sm[j].MetricValue
case utils.MetaPDD: // in case of PDD we take the greater value
return sm[i].MetricValue > sm[j].MetricValue
}
})
}
// newSplDataProvider constructs a DataProvider
func newSplDataProvider(event, sortingData map[string]interface{}) (dP config.DataProvider) {
for _, iface := range sortingData {
if castedVal, canCast := iface.(SplStatMetrics); canCast {
castedVal.Sort()
}
}
dP = &supplierDP{event: config.NewNavigableMap(event), sortingData: sortingData, cache: config.NewNavigableMap(nil)}
return
}
// supplierDP implements engine.DataProvider
type supplierDP struct {
event *config.NavigableMap
sortingData map[string]interface{}
cache *config.NavigableMap
}
// String is part of engine.DataProvider interface
// when called, it will display the already parsed values out of cache
func (sDP *supplierDP) String() string {
return ""
}
// FieldAsInterface is part of engine.DataProvider interface
func (sDP *supplierDP) FieldAsInterface(fldPath []string) (data interface{}, err error) {
if data, err = sDP.cache.FieldAsInterface(fldPath); err != nil {
if err != utils.ErrNotFound { // item found in cache
return
}
err = nil // cancel previous err
} else {
return // data found in cache
}
switch fldPath[0] {
default:
return nil, fmt.Errorf("unsupported field prefix: <%s>", fldPath[0])
case utils.MetaReq:
data, err = sDP.event.FieldAsInterface(fldPath[1:])
case utils.MetaVars:
if _, canCast := sDP.sortingData[fldPath[1]].(SplStatMetrics); canCast {
data = sDP.sortingData[fldPath[1]].(SplStatMetrics)[0].MetricValue
} else {
data = sDP.sortingData[fldPath[1]]
}
}
sDP.cache.Set(fldPath, data, false, false)
return
}
// FieldAsString is part of engine.DataProvider interface
func (sDP *supplierDP) FieldAsString(fldPath []string) (data string, err error) {
var valIface interface{}
valIface, err = sDP.FieldAsInterface(fldPath)
if err != nil {
return
}
data, err = utils.IfaceAsString(valIface)
return
}
// AsNavigableMap is part of engine.DataProvider interface
func (sDP *supplierDP) AsNavigableMap([]*config.FCTemplate) (
nm *config.NavigableMap, err error) {
return nil, utils.ErrNotImplemented
}
// RemoteHost is part of engine.DataProvider interface
func (sDP *supplierDP) RemoteHost() net.Addr {
return nil
}

View File

@@ -279,204 +279,38 @@ func TestLibSuppliersSortHighestCost(t *testing.T) {
}
}
func TestLibSuppliersStatMetricSort(t *testing.T) {
sm := SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 10.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 23.1},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 10.0},
}
sm.Sort()
exp := SplStatMetrics{
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 10.0},
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 10.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 23.1},
}
if !reflect.DeepEqual(exp, sm) {
t.Errorf("Expecting: %s, received: %s",
utils.ToJSON(exp), utils.ToJSON(sm))
}
}
func TestLibSuppliersStatMetricSort2(t *testing.T) {
sm := SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaPDD,
MetricValue: 10.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaPDD,
MetricValue: 23.1},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaPDD,
MetricValue: 10.0},
}
sm.Sort()
exp := SplStatMetrics{
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaPDD,
MetricValue: 23.1},
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaPDD,
MetricValue: 10.1},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaPDD,
MetricValue: 10.0},
}
if !reflect.DeepEqual(exp, sm) {
t.Errorf("Expecting: %s, received: %s",
utils.ToJSON(exp), utils.ToJSON(sm))
}
}
func TestLibSuppliersSplDataProvide(t *testing.T) {
//simulatedData simulate sortingData
simulatedData := map[string]interface{}{
utils.Cost: 12.45,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{
StatID: utils.META_NONE,
metricType: utils.MetaACD,
MetricValue: 9.0},
&SplStatMetric{
StatID: utils.META_NONE,
metricType: utils.MetaACD,
MetricValue: 10.0},
},
utils.MetaPDD: SplStatMetrics{
&SplStatMetric{
StatID: utils.META_NONE,
metricType: utils.MetaPDD,
MetricValue: 12.0},
&SplStatMetric{
StatID: utils.META_NONE,
metricType: utils.MetaPDD,
MetricValue: 5.0},
},
}
ev := map[string]interface{}{
utils.Account: "1001",
}
sDP := newSplDataProvider(ev, simulatedData)
exp := "1001"
if rcv, err := sDP.FieldAsInterface([]string{utils.MetaReq, utils.Account}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(rcv, exp) {
t.Errorf("Expecting: %+v, received: %+v", exp, rcv)
}
exp2 := 12.45
if rcv, err := sDP.FieldAsInterface([]string{utils.MetaVars, utils.Cost}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(rcv, exp2) {
t.Errorf("Expecting: %+v, received: %+v", exp2, rcv)
}
exp3 := 9.0
if rcv, err := sDP.FieldAsInterface([]string{utils.MetaVars, utils.MetaACD}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(rcv, exp3) {
t.Errorf("Expecting: %+v, received: %+v", exp3, rcv)
}
exp4 := 12.0
if rcv, err := sDP.FieldAsInterface([]string{utils.MetaVars, utils.MetaPDD}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(rcv, exp4) {
t.Errorf("Expecting: %+v, received: %+v", exp4, rcv)
}
}
//sort based on *acd and *tcd
func TestLibSuppliersSortQOS(t *testing.T) {
sSpls := &SortedSuppliers{
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
//the worst value for supplier1 for *acd is 0.5 , *tcd 1.1
//the average value for supplier1 for *acd is 0.5 , *tcd 1.1
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.Cost: 0.5,
utils.Weight: 10.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.5},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 23.1},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 10.0},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 1.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaTCD,
MetricValue: 12.1},
},
utils.Cost: 0.5,
utils.Weight: 10.0,
utils.MetaACD: 0.5,
utils.MetaTCD: 1.1,
},
},
&SortedSupplier{
//the worst value for supplier2 for *acd is 0.5 , *tcd 4.1
//the average value for supplier2 for *acd is 0.5 , *tcd 4.1
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.Cost: 0.1,
utils.Weight: 15.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 1.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 12.1},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 0.5},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 12.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaTCD,
MetricValue: 4.1},
},
utils.Cost: 0.1,
utils.Weight: 15.0,
utils.MetaACD: 0.5,
utils.MetaTCD: 4.1,
},
},
&SortedSupplier{
//the worst value for supplier3 for *acd is 0.4 , *tcd 5.1
//the average value for supplier3 for *acd is 0.4 , *tcd 5.1
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.Cost: 1.1,
utils.Weight: 17.8,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.4},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 2.1},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 0.5},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 6.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaTCD,
MetricValue: 5.1},
},
utils.Cost: 1.1,
utils.Weight: 17.8,
utils.MetaACD: 0.4,
utils.MetaTCD: 5.1,
},
},
},
@@ -501,29 +335,12 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
sSpls := &SortedSuppliers{
SortedSuppliers: []*SortedSupplier{
&SortedSupplier{
//the worst value for supplier1 for *acd is 0.5 , *tcd 1.1
//the average value for supplier1 for *acd is 0.5 , *tcd 1.1
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.Weight: 10.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.5},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 0.7},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 0.6},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 1.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaTCD,
MetricValue: 12.1},
},
utils.Weight: 10.0,
utils.MetaACD: 0.5,
utils.MetaTCD: 1.1,
},
},
&SortedSupplier{
@@ -532,50 +349,19 @@ func TestLibSuppliersSortQOS2(t *testing.T) {
//will be sorted based on weight
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.Weight: 17.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.5},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 0.5},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 0.5},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 1.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaTCD,
MetricValue: 12.1},
},
utils.Weight: 17.0,
utils.MetaACD: 0.5,
utils.MetaTCD: 1.1,
},
},
&SortedSupplier{
//the worst value for supplier1 for *acd is 0.5 , *tcd 1.1
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.Cost: 0.5,
utils.Weight: 10.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.5},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 0.5},
&SplStatMetric{StatID: "SampleStat3",
metricType: utils.MetaACD,
MetricValue: 0.5},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 1.2},
},
utils.Cost: 0.5,
utils.Weight: 10.0,
utils.MetaACD: 0.7,
utils.MetaTCD: 1.1,
},
},
},
@@ -603,60 +389,27 @@ func TestLibSuppliersSortQOS3(t *testing.T) {
//will be sorted based on weight
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.Weight: 15.0,
utils.MetaPDD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaPDD,
MetricValue: 0.5},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 0.7},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 1.1},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaTCD,
MetricValue: 12.1},
},
utils.Weight: 15.0,
utils.MetaPDD: 0.7,
utils.MetaTCD: 1.1,
},
},
&SortedSupplier{
//the worst value for supplier2 for *pdd is 1.2, *tcd 1.1
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.Weight: 10.0,
utils.MetaPDD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaPDD,
MetricValue: 0.9},
&SplStatMetric{StatID: "SampleStat2",
metricType: utils.MetaACD,
MetricValue: 1.2},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 1.1},
},
utils.Weight: 10.0,
utils.MetaPDD: 1.2,
utils.MetaTCD: 1.1,
},
},
&SortedSupplier{
//the worst value for supplier3 for *pdd is 0.7, *tcd 10.1
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.Weight: 10.0,
utils.MetaPDD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaPDD,
MetricValue: 0.7},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 10.1},
},
utils.Weight: 10.0,
utils.MetaPDD: 0.7,
utils.MetaTCD: 10.1,
},
},
},
@@ -680,61 +433,25 @@ func TestLibSuppliersSortQOS4(t *testing.T) {
&SortedSupplier{
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.2},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 15.0},
},
utils.MetaASR: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaASR,
MetricValue: 1.2},
},
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
utils.MetaASR: 1.2,
},
},
&SortedSupplier{
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.2},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 20.0},
},
utils.MetaASR: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaASR,
MetricValue: -1.0},
},
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
utils.MetaASR: -1.0,
},
},
&SortedSupplier{
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.1},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 10.0},
},
utils.MetaASR: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaASR,
MetricValue: 1.2},
},
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
utils.MetaASR: 1.2,
},
},
},
@@ -758,76 +475,28 @@ func TestLibSuppliersSortQOS5(t *testing.T) {
&SortedSupplier{
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.2},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 15.0},
},
utils.MetaASR: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaASR,
MetricValue: -1.0},
},
utils.MetaTCC: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCC,
MetricValue: 10.1},
},
utils.MetaACD: 0.2,
utils.MetaTCD: 15.0,
utils.MetaASR: -1.0,
utils.MetaTCC: 10.1,
},
},
&SortedSupplier{
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.2},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 20.0},
},
utils.MetaASR: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaASR,
MetricValue: 1.2},
},
utils.MetaTCC: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCC,
MetricValue: 10.1},
},
utils.MetaACD: 0.2,
utils.MetaTCD: 20.0,
utils.MetaASR: 1.2,
utils.MetaTCC: 10.1,
},
},
&SortedSupplier{
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.1},
},
utils.MetaTCD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCD,
MetricValue: 10.0},
},
utils.MetaASR: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaASR,
MetricValue: 1.2},
},
utils.MetaTCC: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaTCC,
MetricValue: 10.1},
},
utils.MetaACD: 0.1,
utils.MetaTCD: 10.0,
utils.MetaASR: 1.2,
utils.MetaTCC: 10.1,
},
},
},
@@ -851,34 +520,22 @@ func TestLibSuppliersSortQOS6(t *testing.T) {
&SortedSupplier{
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.Weight: 15.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.2},
},
utils.Weight: 15.0,
utils.MetaACD: 0.2,
},
},
&SortedSupplier{
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.Weight: 25.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.2},
},
utils.Weight: 25.0,
utils.MetaACD: 0.2,
},
},
&SortedSupplier{
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.Weight: 20.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 0.1},
},
utils.Weight: 20.0,
utils.MetaACD: 0.1,
},
},
},
@@ -902,34 +559,22 @@ func TestLibSuppliersSortQOS7(t *testing.T) {
&SortedSupplier{
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.Weight: 15.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: -1.0},
},
utils.Weight: 15.0,
utils.MetaACD: -1.0,
},
},
&SortedSupplier{
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.Weight: 25.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: -1.0},
},
utils.Weight: 25.0,
utils.MetaACD: -1.0,
},
},
&SortedSupplier{
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.Weight: 20.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: -1.0},
},
utils.Weight: 20.0,
utils.MetaACD: -1.0,
},
},
},
@@ -953,35 +598,22 @@ func TestLibSuppliersSortQOS8(t *testing.T) {
&SortedSupplier{
SupplierID: "supplier1",
SortingData: map[string]interface{}{
utils.Weight: 15.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: -1.0},
},
utils.Weight: 15.0,
utils.MetaACD: -1.0,
},
},
&SortedSupplier{
SupplierID: "supplier2",
SortingData: map[string]interface{}{
utils.Weight: 25.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: -1.0},
},
utils.Weight: 25.0,
utils.MetaACD: -1.0,
},
SupplierParameters: "param2",
},
&SortedSupplier{
SupplierID: "supplier3",
SortingData: map[string]interface{}{
utils.Weight: 20.0,
utils.MetaACD: SplStatMetrics{
&SplStatMetric{StatID: "SampleStat",
metricType: utils.MetaACD,
MetricValue: 10.0},
},
utils.Weight: 20.0,
utils.MetaACD: 10.0,
},
},
},

View File

@@ -253,8 +253,9 @@ func (spS *SupplierService) costForEvent(ev *utils.CGREvent,
// statMetrics will query a list of statIDs and return composed metric values
// first metric found is always returned
func (spS *SupplierService) statMetrics(statIDs []string, tenant string) (stsMetric map[string]SplStatMetrics, err error) {
stsMetric = make(map[string]SplStatMetrics)
func (spS *SupplierService) statMetrics(statIDs []string, tenant string) (stsMetric map[string]float64, err error) {
stsMetric = make(map[string]float64)
provStsMetrics := make(map[string][]float64)
if spS.statS != nil {
for _, statID := range statIDs {
var metrics map[string]float64
@@ -265,9 +266,17 @@ func (spS *SupplierService) statMetrics(statIDs []string, tenant string) (stsMet
fmt.Sprintf("<SupplierS> error: %s getting statMetrics for stat : %s", err.Error(), statID))
}
for key, val := range metrics {
stsMetric[key] = append(stsMetric[key], &SplStatMetric{StatID: statID, metricType: key, MetricValue: val})
//add value of metric in a slice in case that we get the same metric from different stat
provStsMetrics[key] = append(provStsMetrics[key], val)
}
}
for metric, slice := range provStsMetrics {
sum := 0.0
for _, val := range slice {
sum += val
}
stsMetric[metric] = sum / float64(len(slice))
}
}
return
}
@@ -348,9 +357,9 @@ func (spS *SupplierService) populateSortingData(ev *utils.CGREvent, spl *Supplie
if _, hasMetric := metricSupp[metric]; !hasMetric {
switch metric {
default:
sortedSpl.SortingData[metric] = SplStatMetrics{&SplStatMetric{StatID: utils.META_NONE, metricType: metric, MetricValue: -1.0}}
sortedSpl.SortingData[metric] = -1.0
case utils.MetaPDD:
sortedSpl.SortingData[metric] = SplStatMetrics{&SplStatMetric{StatID: utils.META_NONE, metricType: metric, MetricValue: 10000000.0}}
sortedSpl.SortingData[metric] = 10000000.0
}
}
}
@@ -373,10 +382,12 @@ func (spS *SupplierService) populateSortingData(ev *utils.CGREvent, spl *Supplie
//filter the supplier
if len(spl.FilterIDs) != 0 {
//construct the DP and pass it to filterS
sDP := newSplDataProvider(ev.Event, sortedSpl.SortingData)
nM := config.NewNavigableMap(nil)
nM.Set([]string{utils.MetaReq}, ev.Event, false, false)
nM.Set([]string{utils.MetaVars}, sortedSpl.SortingData, false, false)
if pass, err = spS.filterS.Pass(ev.Tenant, spl.FilterIDs,
sDP); err != nil {
nM); err != nil {
return nil, false, err
} else if !pass {
return nil, false, nil