github.com/google/cloudprober@v0.11.3/metrics/eventmetrics_test.go (about)

     1  // Copyright 2017 The Cloudprober Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package metrics
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  	"time"
    21  )
    22  
    23  func newEventMetrics(sent, rcvd, rtt int64, respCodes map[string]int64) *EventMetrics {
    24  	respCodesVal := NewMap("code", NewInt(0))
    25  	for k, v := range respCodes {
    26  		respCodesVal.IncKeyBy(k, NewInt(v))
    27  	}
    28  	em := NewEventMetrics(time.Now()).
    29  		AddMetric("sent", NewInt(sent)).
    30  		AddMetric("rcvd", NewInt(rcvd)).
    31  		AddMetric("rtt", NewInt(rtt)).
    32  		AddMetric("resp-code", respCodesVal)
    33  	return em
    34  }
    35  
    36  func verifyOrder(em *EventMetrics, names ...string) error {
    37  	keys := em.MetricsKeys()
    38  	for i := range names {
    39  		if keys[i] != names[i] {
    40  			return fmt.Errorf("Metrics not in order. At Index: %d, Expected: %s, Got: %s", i, names[i], keys[i])
    41  		}
    42  	}
    43  	return nil
    44  }
    45  
    46  func verifyEventMetrics(t *testing.T, m *EventMetrics, sent, rcvd, rtt int64, respCodes map[string]int64) {
    47  	// Verify that metrics are ordered correctly.
    48  	if err := verifyOrder(m, "sent", "rcvd", "rtt", "resp-code"); err != nil {
    49  		t.Error(err)
    50  	}
    51  
    52  	expectedMetrics := map[string]int64{
    53  		"sent": sent,
    54  		"rcvd": rcvd,
    55  		"rtt":  rtt,
    56  	}
    57  	for k, eVal := range expectedMetrics {
    58  		if m.Metric(k).(NumValue).Int64() != eVal {
    59  			t.Errorf("Unexpected metric value. Expected: %d, Got: %d", eVal, m.Metric(k).(*Int).Int64())
    60  		}
    61  	}
    62  	for k, eVal := range respCodes {
    63  		if m.Metric("resp-code").(*Map).GetKey(k).Int64() != eVal {
    64  			t.Errorf("Unexpected metric value. Expected: %d, Got: %d", eVal, m.Metric("resp-code").(*Map).GetKey(k).Int64())
    65  		}
    66  	}
    67  }
    68  
    69  func TestEventMetricsUpdate(t *testing.T) {
    70  	rttVal := NewInt(0)
    71  	rttVal.Str = func(i int64) string {
    72  		return fmt.Sprintf("%.3f", float64(i)/1000)
    73  	}
    74  	m := newEventMetrics(0, 0, 0, make(map[string]int64))
    75  	m.AddLabel("ptype", "http")
    76  
    77  	m2 := newEventMetrics(32, 22, 220100, map[string]int64{
    78  		"200": 22,
    79  	})
    80  	m.Update(m2)
    81  	// We'll verify later that mClone is un-impacted by further updates.
    82  	mClone := m.Clone()
    83  
    84  	// Verify that "m" has been updated correctly.
    85  	verifyEventMetrics(t, m, 32, 22, 220100, map[string]int64{
    86  		"200": 22,
    87  	})
    88  
    89  	m3 := newEventMetrics(30, 30, 300100, map[string]int64{
    90  		"200": 22,
    91  		"204": 8,
    92  	})
    93  	m.Update(m3)
    94  
    95  	// Verify that "m" has been updated correctly.
    96  	verifyEventMetrics(t, m, 62, 52, 520200, map[string]int64{
    97  		"200": 44,
    98  		"204": 8,
    99  	})
   100  
   101  	// Verify that even though "m" has changed, mClone is as m was after first update
   102  	verifyEventMetrics(t, mClone, 32, 22, 220100, map[string]int64{
   103  		"200": 22,
   104  	})
   105  
   106  	// Log metrics in string format
   107  	// t.Log(m.String())
   108  
   109  	expectedString := fmt.Sprintf("%d labels=ptype=http sent=62 rcvd=52 rtt=520200 resp-code=map:code,200:44,204:8", m.Timestamp.Unix())
   110  	s := m.String()
   111  	if s != expectedString {
   112  		t.Errorf("em.String()=%s, want=%s", s, expectedString)
   113  	}
   114  }
   115  
   116  func TestEventMetricsSubtractCounters(t *testing.T) {
   117  	rttVal := NewInt(0)
   118  	rttVal.Str = func(i int64) string {
   119  		return fmt.Sprintf("%.3f", float64(i)/1000)
   120  	}
   121  	m := newEventMetrics(10, 10, 1000, make(map[string]int64))
   122  	m.AddLabel("ptype", "http")
   123  
   124  	// First run
   125  	m2 := newEventMetrics(32, 22, 220100, map[string]int64{
   126  		"200": 22,
   127  	})
   128  	gEM, err := m2.SubtractLast(m)
   129  	if err != nil {
   130  		t.Fatalf("Unexpected error: %v", err)
   131  	}
   132  	verifyEventMetrics(t, gEM, 22, 12, 219100, map[string]int64{
   133  		"200": 22,
   134  	})
   135  
   136  	// Second run
   137  	m3 := newEventMetrics(42, 31, 300100, map[string]int64{
   138  		"200": 24,
   139  		"204": 8,
   140  	})
   141  
   142  	gEM, err = m3.SubtractLast(m2)
   143  	if err != nil {
   144  		t.Fatalf("Unexpected error: %v", err)
   145  	}
   146  	verifyEventMetrics(t, gEM, 10, 9, 80000, map[string]int64{
   147  		"200": 2,
   148  		"204": 8,
   149  	})
   150  
   151  	// Third run, expect reset
   152  	m4 := newEventMetrics(10, 8, 1100, map[string]int64{
   153  		"200": 8,
   154  	})
   155  	gEM, err = m4.SubtractLast(m3)
   156  	if err != nil {
   157  		t.Fatalf("Unexpected error: %v", err)
   158  	}
   159  	verifyEventMetrics(t, gEM, 10, 8, 1100, map[string]int64{
   160  		"200": 8,
   161  	})
   162  }
   163  
   164  func TestKey(t *testing.T) {
   165  	m := newEventMetrics(42, 31, 300100, map[string]int64{
   166  		"200": 24,
   167  		"204": 8,
   168  	}).AddLabel("probe", "google-homepage")
   169  
   170  	key := m.Key()
   171  	wantKey := "sent,rcvd,rtt,resp-code,probe=google-homepage"
   172  
   173  	if key != wantKey {
   174  		t.Errorf("Got key: %s, wanted: %s", key, wantKey)
   175  	}
   176  }
   177  
   178  func BenchmarkEventMetricsStringer(b *testing.B) {
   179  	em := newEventMetrics(32, 22, 220100, map[string]int64{
   180  		"200": 22,
   181  		"404": 4500,
   182  		"403": 4500,
   183  	})
   184  	// run the em.String() function b.N times
   185  	for n := 0; n < b.N; n++ {
   186  		em.String()
   187  	}
   188  }
   189  
   190  func TestAllocsPerRun(t *testing.T) {
   191  	respCodesVal := NewMap("code", NewInt(0))
   192  	for k, v := range map[string]int64{
   193  		"200": 22,
   194  		"404": 4500,
   195  		"403": 4500,
   196  	} {
   197  		respCodesVal.IncKeyBy(k, NewInt(v))
   198  	}
   199  
   200  	var em *EventMetrics
   201  	newAvg := testing.AllocsPerRun(100, func() {
   202  		em = NewEventMetrics(time.Now()).
   203  			AddMetric("sent", NewInt(32)).
   204  			AddMetric("rcvd", NewInt(22)).
   205  			AddMetric("rtt", NewInt(220100)).
   206  			AddMetric("resp-code", respCodesVal)
   207  	})
   208  
   209  	stringAvg := testing.AllocsPerRun(100, func() {
   210  		_ = em.String()
   211  	})
   212  
   213  	t.Logf("Average allocations per run: ForNew=%v, ForString=%v", newAvg, stringAvg)
   214  }