mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-20 14:48:43 +05:00
Merge branch 'master' of https://github.com/cgrates/cgrates
This commit is contained in:
@@ -84,6 +84,7 @@ func executeCommand(command string) {
|
||||
param = param.(*console.StringWrapper).Item
|
||||
}
|
||||
//log.Printf("Param: %+v", param)
|
||||
|
||||
if rpcErr := client.Call(cmd.RpcMethod(), param, res); rpcErr != nil {
|
||||
fmt.Println("Error executing command: " + rpcErr.Error())
|
||||
} else {
|
||||
|
||||
@@ -749,7 +749,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
lcrCD.Category = category
|
||||
lcrCD.Account = supplier
|
||||
lcrCD.Subject = supplier
|
||||
var asrMean, acdMean float64
|
||||
var asrMean, acdMean, accMean, tccMean float64
|
||||
var qosSortParams []string
|
||||
if lcrCost.Entry.Strategy == LCR_STRATEGY_QOS || lcrCost.Entry.Strategy == LCR_STRATEGY_QOS_THRESHOLD {
|
||||
rpfKey := utils.ConcatenatedKey(ratingProfileSearchKey, supplier)
|
||||
@@ -766,6 +766,8 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
}
|
||||
var asrValues sort.Float64Slice
|
||||
var acdValues sort.Float64Slice
|
||||
var accValues sort.Float64Slice
|
||||
var tccValues sort.Float64Slice
|
||||
for _, qId := range cdrStatsQueueIds {
|
||||
statValues := make(map[string]float64)
|
||||
if err := stats.GetValues(qId, &statValues); err != nil {
|
||||
@@ -777,18 +779,28 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
if acd, exists := statValues[ACD]; exists {
|
||||
acdValues = append(acdValues, acd)
|
||||
}
|
||||
if acc, exists := statValues[ACC]; exists {
|
||||
accValues = append(accValues, acc)
|
||||
}
|
||||
if tcc, exists := statValues[TCC]; exists {
|
||||
tccValues = append(tccValues, tcc)
|
||||
}
|
||||
}
|
||||
asrValues.Sort()
|
||||
acdValues.Sort()
|
||||
accValues.Sort()
|
||||
tccValues.Sort()
|
||||
asrMean = utils.Avg(asrValues)
|
||||
acdMean = utils.Avg(acdValues)
|
||||
accMean = utils.Avg(accValues)
|
||||
tccMean = utils.Avg(tccValues)
|
||||
//log.Print(asrValues, acdValues)
|
||||
if lcrCost.Entry.Strategy == LCR_STRATEGY_QOS_THRESHOLD || lcrCost.Entry.Strategy == LCR_STRATEGY_QOS {
|
||||
qosSortParams = lcrCost.Entry.GetParams()
|
||||
}
|
||||
if lcrCost.Entry.Strategy == LCR_STRATEGY_QOS_THRESHOLD {
|
||||
// filter suppliers by qos thresholds
|
||||
asrMin, asrMax, acdMin, acdMax := lcrCost.Entry.GetQOSLimits()
|
||||
asrMin, asrMax, acdMin, acdMax, accMin, accMax, tccMin, tccMax := lcrCost.Entry.GetQOSLimits()
|
||||
//log.Print(asrMin, asrMax, acdMin, acdMax)
|
||||
// skip current supplier if off limits
|
||||
if asrMin > 0 && len(asrValues) != 0 && asrValues[0] < asrMin {
|
||||
@@ -803,6 +815,18 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
if acdMax > 0 && len(acdValues) != 0 && acdValues[len(acdValues)-1] > acdMax.Seconds() {
|
||||
continue
|
||||
}
|
||||
if accMin > 0 && len(accValues) != 0 && accValues[0] < accMin {
|
||||
continue
|
||||
}
|
||||
if accMax > 0 && len(accValues) != 0 && accValues[len(accValues)-1] > accMax {
|
||||
continue
|
||||
}
|
||||
if tccMin > 0 && len(tccValues) != 0 && tccValues[0] < tccMin {
|
||||
continue
|
||||
}
|
||||
if tccMax > 0 && len(tccValues) != 0 && tccValues[len(tccValues)-1] > tccMax {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -830,7 +854,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
Duration: cc.GetDuration(),
|
||||
}
|
||||
if utils.IsSliceMember([]string{LCR_STRATEGY_QOS, LCR_STRATEGY_QOS_THRESHOLD}, lcrCost.Entry.Strategy) {
|
||||
supplCost.QOS = map[string]float64{"ASR": asrMean, "ACD": acdMean}
|
||||
supplCost.QOS = map[string]float64{ASR: asrMean, ACD: acdMean, ACC: accMean, TCC: tccMean}
|
||||
supplCost.qosSortParams = qosSortParams
|
||||
}
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, supplCost)
|
||||
|
||||
@@ -91,10 +91,11 @@ func (lcr *LCR) Sort() {
|
||||
sort.Sort(lcr)
|
||||
}
|
||||
|
||||
func (le *LCREntry) GetQOSLimits() (minASR, maxASR float64, minACD, maxACD time.Duration) {
|
||||
// MIN_ASR;MAX_ASR;MIN_ACD;MAX_ACD
|
||||
func (le *LCREntry) GetQOSLimits() (minASR, maxASR float64, minACD, maxACD time.Duration, minACC, maxACC, minTCC, maxTCC float64) {
|
||||
// MIN_ASR;MAX_ASR;MIN_ACD;MAX_ACD;MIN_ACC;MAX_ACC;MIN_TCC;MAX_TCC
|
||||
minASR, maxASR, minACD, maxACD, minACC, maxACC, minTCC, maxTCC = -1, -1, -1, -1, -1, -1, -1, -1
|
||||
params := strings.Split(le.StrategyParams, utils.INFIELD_SEP)
|
||||
if len(params) == 4 {
|
||||
if len(params) == 8 {
|
||||
var err error
|
||||
if minASR, err = strconv.ParseFloat(params[0], 64); err != nil {
|
||||
minASR = -1
|
||||
@@ -108,6 +109,18 @@ func (le *LCREntry) GetQOSLimits() (minASR, maxASR float64, minACD, maxACD time.
|
||||
if maxACD, err = time.ParseDuration(params[3]); err != nil {
|
||||
maxACD = -1
|
||||
}
|
||||
if minACC, err = strconv.ParseFloat(params[4], 64); err != nil {
|
||||
minACC = -1
|
||||
}
|
||||
if maxACC, err = strconv.ParseFloat(params[5], 64); err != nil {
|
||||
maxACC = -1
|
||||
}
|
||||
if minTCC, err = strconv.ParseFloat(params[6], 64); err != nil {
|
||||
minTCC = -1
|
||||
}
|
||||
if maxTCC, err = strconv.ParseFloat(params[7], 64); err != nil {
|
||||
maxTCC = -1
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -124,7 +137,7 @@ func (le *LCREntry) GetParams() []string {
|
||||
}
|
||||
}
|
||||
if len(cleanParams) == 0 && le.Strategy == LCR_STRATEGY_QOS {
|
||||
return []string{ASR, ACD} // Default QoS stats if none configured
|
||||
return []string{ASR, ACD, ACC, TCC} // Default QoS stats if none configured
|
||||
}
|
||||
return cleanParams
|
||||
}
|
||||
|
||||
@@ -90,33 +90,39 @@ func TestLcrQOSSorterOACD(t *testing.T) {
|
||||
|
||||
func TestLcrGetQosLimitsAll(t *testing.T) {
|
||||
le := &LCREntry{
|
||||
StrategyParams: "1.2;2.3;45s;67m",
|
||||
StrategyParams: "1.2;2.3;45s;67m;8.9;10.11;12.13;14.15",
|
||||
}
|
||||
minAsr, maxAsr, minAcd, maxAcd := le.GetQOSLimits()
|
||||
minAsr, maxAsr, minAcd, maxAcd, minAcc, maxAcc, minTcc, maxTcc := le.GetQOSLimits()
|
||||
if minAsr != 1.2 || maxAsr != 2.3 ||
|
||||
minAcd != 45*time.Second || maxAcd != 67*time.Minute {
|
||||
t.Error("Wrong qos limits parsed: ", minAsr, maxAsr, minAcd, maxAcd)
|
||||
minAcd != 45*time.Second || maxAcd != 67*time.Minute ||
|
||||
minAcc != 8.9 || maxAcc != 10.11 ||
|
||||
minTcc != 12.13 || maxTcc != 14.15 {
|
||||
t.Error("Wrong qos limits parsed: ", minAsr, maxAsr, minAcd, maxAcd, minAcc, maxAcc, minTcc, maxTcc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLcrGetQosLimitsSome(t *testing.T) {
|
||||
le := &LCREntry{
|
||||
StrategyParams: "1.2;;;67m",
|
||||
StrategyParams: "1.2;;;67m;1;;3;",
|
||||
}
|
||||
minAsr, maxAsr, minAcd, maxAcd := le.GetQOSLimits()
|
||||
minAsr, maxAsr, minAcd, maxAcd, minAcc, maxAcc, minTcc, maxTcc := le.GetQOSLimits()
|
||||
if minAsr != 1.2 || maxAsr != -1 ||
|
||||
minAcd != -1 || maxAcd != 67*time.Minute {
|
||||
minAcd != -1 || maxAcd != 67*time.Minute ||
|
||||
minAcc != 1 || maxAcc != -1 ||
|
||||
minTcc != 3 || maxTcc != -1 {
|
||||
t.Error("Wrong qos limits parsed: ", minAsr, maxAsr, minAcd, maxAcd)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLcrGetQosLimitsNone(t *testing.T) {
|
||||
le := &LCREntry{
|
||||
StrategyParams: ";;;",
|
||||
StrategyParams: ";;;;;;;",
|
||||
}
|
||||
minAsr, maxAsr, minAcd, maxAcd := le.GetQOSLimits()
|
||||
minAsr, maxAsr, minAcd, maxAcd, minAcc, maxAcc, minTcc, maxTcc := le.GetQOSLimits()
|
||||
if minAsr != -1 || maxAsr != -1 ||
|
||||
minAcd != -1 || maxAcd != -1 {
|
||||
minAcd != -1 || maxAcd != -1 ||
|
||||
minAcc != -1 || maxAcc != -1 ||
|
||||
minTcc != -1 || maxTcc != -1 {
|
||||
t.Error("Wrong qos limits parsed: ", minAsr, maxAsr, minAcd, maxAcd)
|
||||
}
|
||||
}
|
||||
@@ -127,7 +133,7 @@ func TestLcrGetQosSortParamsNone(t *testing.T) {
|
||||
StrategyParams: "",
|
||||
}
|
||||
sort := le.GetParams()
|
||||
if sort[0] != ASR || sort[1] != ACD {
|
||||
if sort[0] != ASR || sort[1] != ACD || sort[2] != ACC || sort[3] != TCC {
|
||||
t.Error("Wrong qos sort params parsed: ", sort)
|
||||
}
|
||||
}
|
||||
@@ -135,10 +141,10 @@ func TestLcrGetQosSortParamsNone(t *testing.T) {
|
||||
func TestLcrGetQosSortParamsEmpty(t *testing.T) {
|
||||
le := &LCREntry{
|
||||
Strategy: LCR_STRATEGY_QOS,
|
||||
StrategyParams: ";",
|
||||
StrategyParams: ";;;",
|
||||
}
|
||||
sort := le.GetParams()
|
||||
if sort[0] != ASR || sort[1] != ACD {
|
||||
if sort[0] != ASR || sort[1] != ACD || sort[2] != ACC || sort[3] != TCC {
|
||||
t.Error("Wrong qos sort params parsed: ", sort)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ func TestGetLCR(t *testing.T) {
|
||||
}
|
||||
}
|
||||
danStatsId := "dan12_stats"
|
||||
rsponder.Stats.AddQueue(&CdrStats{Id: danStatsId, Supplier: []string{"dan12"}, Metrics: []string{ASR, ACD}}, nil)
|
||||
rsponder.Stats.AddQueue(&CdrStats{Id: danStatsId, Supplier: []string{"dan12"}, Metrics: []string{ASR, ACD, ACC, TCC}}, nil)
|
||||
danRpfl := &RatingProfile{Id: "*out:tenant12:call:dan12",
|
||||
RatingPlanActivations: RatingPlanActivations{&RatingPlanActivation{
|
||||
ActivationTime: time.Date(2015, 01, 01, 8, 0, 0, 0, time.UTC),
|
||||
@@ -292,7 +292,7 @@ func TestGetLCR(t *testing.T) {
|
||||
}},
|
||||
}
|
||||
rifStatsId := "rif12_stats"
|
||||
rsponder.Stats.AddQueue(&CdrStats{Id: rifStatsId, Supplier: []string{"rif12"}, Metrics: []string{ASR, ACD}}, nil)
|
||||
rsponder.Stats.AddQueue(&CdrStats{Id: rifStatsId, Supplier: []string{"rif12"}, Metrics: []string{ASR, ACD, ACC, TCC}}, nil)
|
||||
rifRpfl := &RatingProfile{Id: "*out:tenant12:call:rif12",
|
||||
RatingPlanActivations: RatingPlanActivations{&RatingPlanActivation{
|
||||
ActivationTime: time.Date(2015, 01, 01, 8, 0, 0, 0, time.UTC),
|
||||
@@ -302,7 +302,7 @@ func TestGetLCR(t *testing.T) {
|
||||
}},
|
||||
}
|
||||
ivoStatsId := "ivo12_stats"
|
||||
rsponder.Stats.AddQueue(&CdrStats{Id: ivoStatsId, Supplier: []string{"ivo12"}, Metrics: []string{ASR, ACD}}, nil)
|
||||
rsponder.Stats.AddQueue(&CdrStats{Id: ivoStatsId, Supplier: []string{"ivo12"}, Metrics: []string{ASR, ACD, ACC, TCC}}, nil)
|
||||
ivoRpfl := &RatingProfile{Id: "*out:tenant12:call:ivo12",
|
||||
RatingPlanActivations: RatingPlanActivations{&RatingPlanActivation{
|
||||
ActivationTime: time.Date(2015, 01, 01, 8, 0, 0, 0, time.UTC),
|
||||
@@ -339,7 +339,7 @@ func TestGetLCR(t *testing.T) {
|
||||
&LCRActivation{
|
||||
ActivationTime: time.Date(2015, 01, 01, 8, 0, 0, 0, time.UTC),
|
||||
Entries: []*LCREntry{
|
||||
&LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;4m;", Weight: 10.0}},
|
||||
&LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;4m;;;;;", Weight: 10.0}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -456,7 +456,7 @@ func TestGetLCR(t *testing.T) {
|
||||
Subject: "dan",
|
||||
}
|
||||
eQTLcr := &LCRCost{
|
||||
Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;4m;", Weight: 10.0},
|
||||
Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;4m;;;;;", Weight: 10.0},
|
||||
}
|
||||
var lcrQT LCRCost
|
||||
if err := rsponder.GetLCR(cdQosThreshold, &lcrQT); err != nil {
|
||||
@@ -467,15 +467,15 @@ func TestGetLCR(t *testing.T) {
|
||||
} else if !reflect.DeepEqual(eQTLcr.SupplierCosts, lcrQT.SupplierCosts) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eQTLcr.SupplierCosts, lcrQT.SupplierCosts)
|
||||
}
|
||||
cdr := &StoredCdr{Supplier: "rif12", AnswerTime: time.Now(), Usage: 3 * time.Minute}
|
||||
cdr := &StoredCdr{Supplier: "rif12", AnswerTime: time.Now(), Usage: 3 * time.Minute, Cost: 1}
|
||||
rsponder.Stats.AppendCDR(cdr, nil)
|
||||
cdr = &StoredCdr{Supplier: "dan12", AnswerTime: time.Now(), Usage: 5 * time.Minute}
|
||||
cdr = &StoredCdr{Supplier: "dan12", AnswerTime: time.Now(), Usage: 5 * time.Minute, Cost: 2}
|
||||
rsponder.Stats.AppendCDR(cdr, nil)
|
||||
eQTLcr = &LCRCost{
|
||||
Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;4m;", Weight: 10.0},
|
||||
Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS_THRESHOLD, StrategyParams: "35;;4m;;;;;", Weight: 10.0},
|
||||
SupplierCosts: []*LCRSupplierCost{
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second,
|
||||
QOS: map[string]float64{ACD: 300, ASR: 100}, qosSortParams: []string{"35", "4m"}},
|
||||
QOS: map[string]float64{ACD: 300, ASR: 100, ACC: 2, TCC: 2}, qosSortParams: []string{"35", "4m"}},
|
||||
},
|
||||
}
|
||||
if err := rsponder.GetLCR(cdQosThreshold, &lcrQT); err != nil {
|
||||
@@ -501,9 +501,9 @@ func TestGetLCR(t *testing.T) {
|
||||
eQosLcr := &LCRCost{
|
||||
Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_QOS, Weight: 10.0},
|
||||
SupplierCosts: []*LCRSupplierCost{
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 300, ASR: 100}, qosSortParams: []string{ASR, ACD}},
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:rif12", Cost: 0.4, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 180, ASR: 100}, qosSortParams: []string{ASR, ACD}},
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 0, ASR: 0}, qosSortParams: []string{ASR, ACD}},
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 300, ASR: 100, ACC: 2, TCC: 2}, qosSortParams: []string{ASR, ACD, ACC, TCC}},
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:rif12", Cost: 0.4, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 180, ASR: 100, ACC: 1, TCC: 1}, qosSortParams: []string{ASR, ACD, ACC, TCC}},
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 0, Duration: 60 * time.Second, QOS: map[string]float64{ACD: 0, ASR: 0, ACC: 0, TCC: 0}, qosSortParams: []string{ASR, ACD, ACC, TCC}},
|
||||
},
|
||||
}
|
||||
var lcrQ LCRCost
|
||||
@@ -513,7 +513,7 @@ func TestGetLCR(t *testing.T) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eQosLcr.Entry, lcrQ.Entry)
|
||||
|
||||
} else if !reflect.DeepEqual(eQosLcr.SupplierCosts, lcrQ.SupplierCosts) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eQosLcr.SupplierCosts[0], lcrQ.SupplierCosts[0])
|
||||
t.Errorf("Expecting: %+v, received: %+v", eQosLcr.SupplierCosts[1], lcrQ.SupplierCosts[1])
|
||||
for _, sc := range lcrQ.SupplierCosts {
|
||||
log.Printf("%+v", sc)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ type Metric interface {
|
||||
const ASR = "ASR"
|
||||
const ACD = "ACD"
|
||||
const ACC = "ACC"
|
||||
const TCC = "TCC"
|
||||
|
||||
func CreateMetric(metric string) Metric {
|
||||
switch metric {
|
||||
@@ -42,6 +43,8 @@ func CreateMetric(metric string) Metric {
|
||||
return &ACDMetric{}
|
||||
case ACC:
|
||||
return &ACCMetric{}
|
||||
case TCC:
|
||||
return &TCCMetric{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -132,3 +135,25 @@ func (acc *ACCMetric) GetValue() float64 {
|
||||
val := acc.sum / acc.count
|
||||
return utils.Round(val, globalRoundingDecimals, utils.ROUNDING_MIDDLE)
|
||||
}
|
||||
|
||||
// TCC – Total Call Cost
|
||||
// the sum of cost of answered calls
|
||||
type TCCMetric struct {
|
||||
sum float64
|
||||
}
|
||||
|
||||
func (tcc *TCCMetric) AddCdr(cdr *QCdr) {
|
||||
if !cdr.AnswerTime.IsZero() && cdr.Cost >= 0 {
|
||||
tcc.sum += cdr.Cost
|
||||
}
|
||||
}
|
||||
|
||||
func (tcc *TCCMetric) RemoveCdr(cdr *QCdr) {
|
||||
if !cdr.AnswerTime.IsZero() && cdr.Cost >= 0 {
|
||||
tcc.sum -= cdr.Cost
|
||||
}
|
||||
}
|
||||
|
||||
func (tcc *TCCMetric) GetValue() float64 {
|
||||
return utils.Round(tcc.sum, globalRoundingDecimals, utils.ROUNDING_MIDDLE)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ var METRIC_TRIGGER_MAP = map[string]string{
|
||||
"*max_acd": ACD,
|
||||
"*min_acc": ACC,
|
||||
"*max_acc": ACC,
|
||||
"*min_tcc": ACC,
|
||||
"*max_tcc": ACC,
|
||||
}
|
||||
|
||||
// Simplified cdr structure containing only the necessary info
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestStatsQueueInit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatsValue(t *testing.T) {
|
||||
sq := NewStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, ACC}})
|
||||
sq := NewStatsQueue(&CdrStats{Metrics: []string{ASR, ACD, ACC, TCC}})
|
||||
cdr := &StoredCdr{
|
||||
AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
Usage: 10 * time.Second,
|
||||
@@ -47,7 +47,8 @@ func TestStatsValue(t *testing.T) {
|
||||
s := sq.GetStats()
|
||||
if s[ASR] != 100 ||
|
||||
s[ACD] != 10 ||
|
||||
s[ACC] != 2 {
|
||||
s[ACC] != 2 ||
|
||||
s[TCC] != 6 {
|
||||
t.Errorf("Error getting stats: %+v", s)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user