From 23fb7b64f73b640f44b43a319bdb332f9e976ae9 Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 27 Sep 2017 12:33:02 +0300 Subject: [PATCH 1/4] Add PDD metric and test for it --- engine/libstats.go | 19 ++++ engine/statmetrics.go | 86 +++++++++++++++++- engine/statmetrics_test.go | 176 +++++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 1 deletion(-) diff --git a/engine/libstats.go b/engine/libstats.go index 50280cef6..fbef8395f 100755 --- a/engine/libstats.go +++ b/engine/libstats.go @@ -109,6 +109,25 @@ func (se StatEvent) Cost(timezone string) (cs float64, err error) { return strconv.ParseFloat(csStr, 64) } +// Pdd returns the Pdd of StatEvent +func (se StatEvent) Pdd(timezone string) (pdd time.Duration, err error) { + pddIf, has := se.Fields[utils.PDD] + if !has { + return pdd, utils.ErrNotFound + } + if pdd, canCast := pddIf.(time.Duration); canCast { + return pdd, nil + } + if pdd, canCast := pddIf.(float64); canCast { + return time.Duration(int64(pdd)), nil + } + pddStr, canCast := pddIf.(string) + if !canCast { + return pdd, errors.New("cannot cast to string") + } + return utils.ParseDurationWithSecs(pddStr) +} + // NewStoredStatQueue initiates a StoredStatQueue out of StatQueue func NewStoredStatQueue(sq *StatQueue, ms Marshaler) (sSQ *StoredStatQueue, err error) { sSQ = &StoredStatQueue{ diff --git a/engine/statmetrics.go b/engine/statmetrics.go index d4392aacc..9a7d46214 100644 --- a/engine/statmetrics.go +++ b/engine/statmetrics.go @@ -35,6 +35,7 @@ func NewStatMetric(metricID string) (sm StatMetric, err error) { utils.MetaTCD: NewTCD, utils.MetaACC: NewACC, utils.MetaTCC: NewTCC, + utils.MetaPDD: NewPDD, } if _, has := metrics[metricID]; !has { return nil, fmt.Errorf("unsupported metric: %s", metricID) @@ -368,7 +369,7 @@ func (acc *StatACC) RemEvent(evTenantID string) (err error) { if !has { return utils.ErrNotFound } - if cost != 0 { + if cost >= 0 { acc.Sum -= cost } acc.Count -= 1 @@ -465,3 +466,86 @@ func (tcc *StatTCC) Marshal(ms Marshaler) (marshaled []byte, err error) { func (tcc *StatTCC) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) { return ms.Unmarshal(marshaled, tcc) } + +func NewPDD() (StatMetric, error) { + return &StatPDD{Events: make(map[string]time.Duration)}, nil +} + +// ACD implements AverageCallDuration metric +type StatPDD struct { + Sum time.Duration + Count int64 + Events map[string]time.Duration // map[EventTenantID]Duration + val *time.Duration // cached PDD value +} + +// getValue returns pdd.val +func (pdd *StatPDD) getValue() time.Duration { + if pdd.val == nil { + if pdd.Count == 0 { + pdd.val = utils.DurationPointer(time.Duration((-1) * time.Nanosecond)) + } else { + pdd.val = utils.DurationPointer(time.Duration(pdd.Sum.Nanoseconds() / pdd.Count)) + } + } + return *pdd.val +} + +func (pdd *StatPDD) GetStringValue(fmtOpts string) (val string) { + if pdd.Count == 0 { + return utils.NOT_AVAILABLE + } + return fmt.Sprintf("%+v", pdd.getValue()) +} + +func (pdd *StatPDD) GetValue() (v interface{}) { + return pdd.getValue() +} + +func (pdd *StatPDD) GetFloat64Value() (v float64) { + if pdd.Count == 0 { + return -1.0 + } + return pdd.getValue().Seconds() +} + +func (pdd *StatPDD) AddEvent(ev *StatEvent) (err error) { + var value time.Duration + if at, err := ev.AnswerTime(config.CgrConfig().DefaultTimezone); err != nil && + err != utils.ErrNotFound { + return err + } else if !at.IsZero() { + if duration, err := ev.Pdd(config.CgrConfig().DefaultTimezone); err != nil && + err != utils.ErrNotFound { + return err + } else { + value = duration + pdd.Sum += duration + } + } + pdd.Events[ev.TenantID()] = value + pdd.Count += 1 + pdd.val = nil + return +} + +func (pdd *StatPDD) RemEvent(evTenantID string) (err error) { + duration, has := pdd.Events[evTenantID] + if !has { + return utils.ErrNotFound + } + if duration != 0 { + pdd.Sum -= duration + } + pdd.Count -= 1 + delete(pdd.Events, evTenantID) + pdd.val = nil + return +} + +func (pdd *StatPDD) Marshal(ms Marshaler) (marshaled []byte, err error) { + return ms.Marshal(pdd) +} +func (pdd *StatPDD) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) { + return ms.Unmarshal(marshaled, pdd) +} diff --git a/engine/statmetrics_test.go b/engine/statmetrics_test.go index 4e9d2f250..8e96c4c0f 100644 --- a/engine/statmetrics_test.go +++ b/engine/statmetrics_test.go @@ -656,3 +656,179 @@ func TestTCCGetValue(t *testing.T) { t.Errorf("wrong tcc value: %v", strVal) } } + +func TestPDDGetStringValue(t *testing.T) { + pdd, _ := NewPDD() + ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1", + Fields: map[string]interface{}{ + utils.USAGE: time.Duration(10 * time.Second), + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + utils.PDD: time.Duration(5 * time.Second), + }} + if strVal := pdd.GetStringValue(""); strVal != utils.NOT_AVAILABLE { + t.Errorf("wrong pdd value: %s", strVal) + } + pdd.AddEvent(ev) + if strVal := pdd.GetStringValue(""); strVal != "5s" { + t.Errorf("wrong pdd value: %s", strVal) + } + ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"} + ev3 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_3"} + pdd.AddEvent(ev2) + pdd.AddEvent(ev3) + if strVal := pdd.GetStringValue(""); strVal != "1.666666666s" { + t.Errorf("wrong pdd value: %s", strVal) + } + pdd.RemEvent(ev3.TenantID()) + if strVal := pdd.GetStringValue(""); strVal != "2.5s" { + t.Errorf("wrong pdd value: %s", strVal) + } + pdd.RemEvent(ev.TenantID()) + if strVal := pdd.GetStringValue(""); strVal != "0s" { + t.Errorf("wrong pdd value: %s", strVal) + } + ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4", + Fields: map[string]interface{}{ + "Usage": time.Duration(1 * time.Minute), + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + utils.PDD: time.Duration(10 * time.Second), + }, + } + ev5 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_5", + Fields: map[string]interface{}{ + utils.PDD: time.Duration(10 * time.Second), + }, + } + pdd.AddEvent(ev4) + if strVal := pdd.GetStringValue(""); strVal != "5s" { + t.Errorf("wrong pdd value: %s", strVal) + } + pdd.AddEvent(ev5) + if strVal := pdd.GetStringValue(""); strVal != "3.333333333s" { + t.Errorf("wrong pdd value: %s", strVal) + } + pdd.RemEvent(ev2.TenantID()) + if strVal := pdd.GetStringValue(""); strVal != "5s" { + t.Errorf("wrong pdd value: %s", strVal) + } + pdd.RemEvent(ev5.TenantID()) + pdd.RemEvent(ev4.TenantID()) + pdd.RemEvent(ev5.TenantID()) + if strVal := pdd.GetStringValue(""); strVal != utils.NOT_AVAILABLE { + t.Errorf("wrong pdd value: %s", strVal) + } +} + +func TestPDDGetFloat64Value(t *testing.T) { + pdd, _ := NewPDD() + ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1", + Fields: map[string]interface{}{ + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + "Usage": time.Duration(10 * time.Second), + utils.PDD: time.Duration(5 * time.Second)}} + pdd.AddEvent(ev) + if v := pdd.GetFloat64Value(); v != 5.0 { + t.Errorf("wrong pdd value: %v", v) + } + ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"} + pdd.AddEvent(ev2) + if v := pdd.GetFloat64Value(); v != 2.5 { + t.Errorf("wrong pdd value: %v", v) + } + ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4", + Fields: map[string]interface{}{ + "Usage": time.Duration(1 * time.Minute), + "AnswerTime": time.Date(2015, 7, 14, 14, 25, 0, 0, time.UTC), + utils.PDD: time.Duration(10 * time.Second), + }, + } + ev5 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_5", + Fields: map[string]interface{}{ + "Usage": time.Duration(1*time.Minute + 30*time.Second), + "AnswerTime": time.Date(2015, 7, 14, 14, 25, 0, 0, time.UTC), + }, + } + pdd.AddEvent(ev4) + if strVal := pdd.GetFloat64Value(); strVal != 5 { + t.Errorf("wrong pdd value: %v", strVal) + } + pdd.AddEvent(ev5) + if strVal := pdd.GetFloat64Value(); strVal != 3.75 { + t.Errorf("wrong pdd value: %v", strVal) + } + pdd.RemEvent(ev2.TenantID()) + if strVal := pdd.GetFloat64Value(); strVal != 5 { + t.Errorf("wrong pdd value: %v", strVal) + } + pdd.RemEvent(ev4.TenantID()) + if strVal := pdd.GetFloat64Value(); strVal != 2.5 { + t.Errorf("wrong pdd value: %v", strVal) + } + pdd.RemEvent(ev.TenantID()) + if strVal := pdd.GetFloat64Value(); strVal != 0 { + t.Errorf("wrong pdd value: %v", strVal) + } + pdd.RemEvent(ev5.TenantID()) + if strVal := pdd.GetFloat64Value(); strVal != -1.0 { + t.Errorf("wrong pdd value: %v", strVal) + } +} + +func TestPDDGetValue(t *testing.T) { + pdd, _ := NewPDD() + ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1", + Fields: map[string]interface{}{ + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + "Usage": time.Duration(10 * time.Second), + utils.PDD: time.Duration(9 * time.Second)}} + pdd.AddEvent(ev) + if v := pdd.GetValue(); v != time.Duration(9*time.Second) { + t.Errorf("wrong pdd value: %+v", v) + } + ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2", + Fields: map[string]interface{}{ + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + "Usage": time.Duration(8 * time.Second), + utils.PDD: time.Duration(10 * time.Second)}} + ev3 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_3"} + pdd.AddEvent(ev2) + pdd.AddEvent(ev3) + if v := pdd.GetValue(); v != time.Duration(6333333333*time.Nanosecond) { + t.Errorf("wrong pdd value: %+v", v) + } + pdd.RemEvent(ev.TenantID()) + if v := pdd.GetValue(); v != time.Duration(5*time.Second) { + t.Errorf("wrong pdd value: %+v", v) + } + pdd.RemEvent(ev2.TenantID()) + if v := pdd.GetValue(); v != time.Duration(0*time.Second) { + t.Errorf("wrong pdd value: %+v", v) + } + ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4", + Fields: map[string]interface{}{ + "Usage": time.Duration(1 * time.Minute), + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + utils.PDD: time.Duration(8 * time.Second), + }, + } + ev5 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_5", + Fields: map[string]interface{}{ + "Usage": time.Duration(4*time.Minute + 30*time.Second), + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + }, + } + pdd.AddEvent(ev4) + pdd.AddEvent(ev5) + if v := pdd.GetValue(); v != time.Duration(2666666666*time.Nanosecond) { + t.Errorf("wrong pdd value: %+v", v) + } + pdd.RemEvent(ev5.TenantID()) + pdd.RemEvent(ev4.TenantID()) + if v := pdd.GetValue(); v != time.Duration(0*time.Second) { + t.Errorf("wrong pdd value: %+v", v) + } + pdd.RemEvent(ev3.TenantID()) + if v := pdd.GetValue(); v != time.Duration((-1)*time.Nanosecond) { + t.Errorf("wrong pdd value: %+v", v) + } +} From 75123911d13a6fb425f0aeee196c3231e345d5e6 Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 27 Sep 2017 12:49:19 +0300 Subject: [PATCH 2/4] Updated some comments --- engine/statmetrics.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/statmetrics.go b/engine/statmetrics.go index 9a7d46214..1f9b6440d 100644 --- a/engine/statmetrics.go +++ b/engine/statmetrics.go @@ -471,7 +471,7 @@ func NewPDD() (StatMetric, error) { return &StatPDD{Events: make(map[string]time.Duration)}, nil } -// ACD implements AverageCallDuration metric +// PDD implements Post Dial Delay (average) metric type StatPDD struct { Sum time.Duration Count int64 From 9a36cb5bb5a5e2d9ae7284f3795e837870024cee Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 27 Sep 2017 13:37:52 +0300 Subject: [PATCH 3/4] Add *pdd metric in stats_it_test.go and add a new test(GetStatsAfterRestart) --- apier/v1/stats_it_test.go | 34 ++++++++++++++++++++++++++++- data/tariffplans/testtp/Stats.csv | 2 +- data/tariffplans/tutorial/Stats.csv | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/apier/v1/stats_it_test.go b/apier/v1/stats_it_test.go index d2cd04336..7701ed179 100644 --- a/apier/v1/stats_it_test.go +++ b/apier/v1/stats_it_test.go @@ -77,6 +77,7 @@ var sTestsStatSV1 = []func(t *testing.T){ testV1STSRpcConn, testV1STSFromFolder, testV1STSGetStats, + testV1STSGetStatsAfterRestart, testV1STSProcessEvent, testV1STSSetStatQueueProfile, testV1STSUpdateStatQueueProfile, @@ -157,6 +158,7 @@ func testV1STSGetStats(t *testing.T) { utils.MetaTCC: utils.NOT_AVAILABLE, utils.MetaTCD: utils.NOT_AVAILABLE, utils.MetaACC: utils.NOT_AVAILABLE, + utils.MetaPDD: utils.NOT_AVAILABLE, } if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: expectedIDs[0]}, &metrics); err != nil { @@ -166,6 +168,34 @@ func testV1STSGetStats(t *testing.T) { } } +func testV1STSGetStatsAfterRestart(t *testing.T) { + var reply []string + expectedIDs := []string{"STATS_1"} + //get stats before restart + if err := stsV1Rpc.Call("StatSV1.GetQueueIDs", "cgrates.org", &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedIDs, reply) { + t.Errorf("expecting: %+v, received reply: %s", expectedIDs, reply) + } + if _, err := engine.StopStartEngine(stsV1CfgPath, statsDelay); err != nil { + t.Fatal(err) + } + var err error + stsV1Rpc, err = jsonrpc.Dial("tcp", stsV1Cfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal("Could not connect to rater: ", err.Error()) + } + //get stats after restart + var reply2 []string + expectedIDs2 := []string{"STATS_1"} + if err := stsV1Rpc.Call("StatSV1.GetQueueIDs", "cgrates.org", &reply2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedIDs2, reply2) { + t.Errorf("expecting: %+v, received reply: %s", expectedIDs2, reply2) + } + time.Sleep(time.Duration(1 * time.Second)) +} + func testV1STSProcessEvent(t *testing.T) { var reply string ev1 := engine.StatEvent{ @@ -175,7 +205,8 @@ func testV1STSProcessEvent(t *testing.T) { utils.ACCOUNT: "1001", utils.ANSWER_TIME: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), utils.USAGE: time.Duration(135 * time.Second), - utils.COST: 123.0}} + utils.COST: 123.0, + utils.PDD: time.Duration(12 * time.Second)}} if err := stsV1Rpc.Call("StatSV1.ProcessEvent", &ev1, &reply); err != nil { t.Error(err) } else if reply != utils.OK { @@ -211,6 +242,7 @@ func testV1STSProcessEvent(t *testing.T) { utils.MetaACC: "61.5", utils.MetaTCD: "3m0s", utils.MetaTCC: "123", + utils.MetaPDD: "4s", } var metrics map[string]string if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "STATS_1"}, &metrics); err != nil { diff --git a/data/tariffplans/testtp/Stats.csv b/data/tariffplans/testtp/Stats.csv index 8cc037dab..20fd89d20 100755 --- a/data/tariffplans/testtp/Stats.csv +++ b/data/tariffplans/testtp/Stats.csv @@ -1,2 +1,2 @@ #Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],Thresholds[12] -cgrates.org,Stats1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acd;*acc;*tcd;*tcc,true,true,20,THRESH1;THRESH2 +cgrates.org,Stats1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acd;*acc;*tcd;*tcc;*pdd,true,true,20,THRESH1;THRESH2 diff --git a/data/tariffplans/tutorial/Stats.csv b/data/tariffplans/tutorial/Stats.csv index db4cccbad..43ba6ff3c 100755 --- a/data/tariffplans/tutorial/Stats.csv +++ b/data/tariffplans/tutorial/Stats.csv @@ -1,2 +1,2 @@ #Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],Thresholds[12] -cgrates.org,STATS_1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acc;*tcc;*acd;*tcd,true,true,20,THRESH1;THRESH2 +cgrates.org,STATS_1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acc;*tcc;*acd;*tcd;*pdd,true,true,20,THRESH1;THRESH2 From b27e5038be163b32d0aa7a258bcdc7819f1b43ab Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 27 Sep 2017 14:06:12 +0300 Subject: [PATCH 4/4] Update GetStatsAfterReset in stats_it_test.go --- apier/v1/stats_it_test.go | 72 +++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/apier/v1/stats_it_test.go b/apier/v1/stats_it_test.go index 7701ed179..a25483f9a 100644 --- a/apier/v1/stats_it_test.go +++ b/apier/v1/stats_it_test.go @@ -77,8 +77,8 @@ var sTestsStatSV1 = []func(t *testing.T){ testV1STSRpcConn, testV1STSFromFolder, testV1STSGetStats, - testV1STSGetStatsAfterRestart, testV1STSProcessEvent, + testV1STSGetStatsAfterRestart, testV1STSSetStatQueueProfile, testV1STSUpdateStatQueueProfile, testV1STSRemoveStatQueueProfile, @@ -168,34 +168,6 @@ func testV1STSGetStats(t *testing.T) { } } -func testV1STSGetStatsAfterRestart(t *testing.T) { - var reply []string - expectedIDs := []string{"STATS_1"} - //get stats before restart - if err := stsV1Rpc.Call("StatSV1.GetQueueIDs", "cgrates.org", &reply); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expectedIDs, reply) { - t.Errorf("expecting: %+v, received reply: %s", expectedIDs, reply) - } - if _, err := engine.StopStartEngine(stsV1CfgPath, statsDelay); err != nil { - t.Fatal(err) - } - var err error - stsV1Rpc, err = jsonrpc.Dial("tcp", stsV1Cfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed - if err != nil { - t.Fatal("Could not connect to rater: ", err.Error()) - } - //get stats after restart - var reply2 []string - expectedIDs2 := []string{"STATS_1"} - if err := stsV1Rpc.Call("StatSV1.GetQueueIDs", "cgrates.org", &reply2); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expectedIDs2, reply2) { - t.Errorf("expecting: %+v, received reply: %s", expectedIDs2, reply2) - } - time.Sleep(time.Duration(1 * time.Second)) -} - func testV1STSProcessEvent(t *testing.T) { var reply string ev1 := engine.StatEvent{ @@ -252,6 +224,48 @@ func testV1STSProcessEvent(t *testing.T) { } } +func testV1STSGetStatsAfterRestart(t *testing.T) { + expectedMetrics := map[string]string{ + utils.MetaASR: "66.66667%", + utils.MetaACD: "1m30s", + utils.MetaACC: "61.5", + utils.MetaTCD: "3m0s", + utils.MetaTCC: "123", + utils.MetaPDD: "4s", + } + var metrics map[string]string + //get stats metrics before restart + if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "STATS_1"}, &metrics); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics, metrics) { + t.Errorf("expecting: %+v, received reply: %s", expectedMetrics, metrics) + } + if _, err := engine.StopStartEngine(stsV1CfgPath, statsDelay); err != nil { + t.Fatal(err) + } + var err error + stsV1Rpc, err = jsonrpc.Dial("tcp", stsV1Cfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal("Could not connect to rater: ", err.Error()) + } + //get stats metrics after restart + expectedMetrics2 := map[string]string{ + utils.MetaASR: "66.66667%", + utils.MetaACD: "1m30s", + utils.MetaACC: "61.5", + utils.MetaTCD: "3m0s", + utils.MetaTCC: "123", + utils.MetaPDD: "4s", + } + var metrics2 map[string]string + if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "STATS_1"}, &metrics2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics2, metrics2) { + t.Errorf("expecting: %+v, received reply: %s", expectedMetrics2, metrics2) + } + time.Sleep(time.Duration(1 * time.Second)) +} + func testV1STSSetStatQueueProfile(t *testing.T) { var reply *engine.StatQueueProfile if err := stsV1Rpc.Call("ApierV1.GetStatQueueProfile",