github.com/GoogleCloudPlatform/testgrid@v0.0.174/util/metrics/logmetrics/log_test.go (about)

     1  /*
     2  Copyright 2021 The TestGrid Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package logmetrics
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/sirupsen/logrus"
    25  )
    26  
    27  func TestInt64Set(t *testing.T) {
    28  	cases := []struct {
    29  		name   string
    30  		fields []string
    31  		sets   []map[int64][]string
    32  		want   map[string]map[string]interface{}
    33  	}{
    34  		{
    35  			name: "zero",
    36  			want: map[string]map[string]interface{}{},
    37  		},
    38  		{
    39  			name:   "basic",
    40  			fields: []string{"component"},
    41  			sets: []map[int64][]string{
    42  				{64: {"updater"}},
    43  			},
    44  			want: map[string]map[string]interface{}{
    45  				"component": {
    46  					"updater": mean{[]int64{64}},
    47  				},
    48  			},
    49  		},
    50  		{
    51  			name:   "fields",
    52  			fields: []string{"component", "source"},
    53  			sets: []map[int64][]string{
    54  				{64: {"updater", "prow"}},
    55  			},
    56  			want: map[string]map[string]interface{}{
    57  				"component": {
    58  					"updater": mean{[]int64{64}},
    59  				},
    60  				"source": {
    61  					"prow": mean{[]int64{64}},
    62  				},
    63  			},
    64  		},
    65  		{
    66  			name:   "values",
    67  			fields: []string{"component"},
    68  			sets: []map[int64][]string{
    69  				{64: {"updater"}},
    70  				{32: {"updater"}},
    71  			},
    72  			want: map[string]map[string]interface{}{
    73  				"component": {
    74  					"updater": mean{[]int64{64, 32}},
    75  				},
    76  			},
    77  		},
    78  		{
    79  			name:   "fields and values",
    80  			fields: []string{"component", "source"},
    81  			sets: []map[int64][]string{
    82  				{64: {"updater", "prow"}},
    83  				{32: {"updater", "prow"}},
    84  			},
    85  			want: map[string]map[string]interface{}{
    86  				"component": {
    87  					"updater": mean{[]int64{64, 32}},
    88  				},
    89  				"source": {
    90  					"prow": mean{[]int64{64, 32}},
    91  				},
    92  			},
    93  		},
    94  		{
    95  			name:   "complex",
    96  			fields: []string{"component", "source"},
    97  			sets: []map[int64][]string{
    98  				{64: {"updater", "prow"}},
    99  				{66: {"updater", "google"}},
   100  				{32: {"summarizer", "google"}},
   101  			},
   102  			want: map[string]map[string]interface{}{
   103  				"component": {
   104  					"updater":    mean{[]int64{64, 66}},
   105  					"summarizer": mean{[]int64{32}},
   106  				},
   107  				"source": {
   108  					"prow":   mean{[]int64{64}},
   109  					"google": mean{[]int64{66, 32}},
   110  				},
   111  			},
   112  		},
   113  	}
   114  
   115  	for _, tc := range cases {
   116  		t.Run(tc.name, func(t *testing.T) {
   117  			var r Reporter
   118  			m := r.Int64("fake metric", "fake desc", logrus.WithField("name", tc.name), tc.fields...)
   119  			for _, set := range tc.sets {
   120  				for n, fields := range set {
   121  					m.Set(n, fields...)
   122  				}
   123  			}
   124  			got := m.(Valuer).Values()
   125  			if diff := cmp.Diff(tc.want, got, cmp.AllowUnexported(mean{}, gauge{})); diff != "" {
   126  				t.Errorf("Set() got unexpected diff (-want +got):\n%s", diff)
   127  			}
   128  		})
   129  	}
   130  }
   131  
   132  func TestCounterAdd(t *testing.T) {
   133  	when := time.Now().Add(-10 * time.Minute)
   134  	cases := []struct {
   135  		name   string
   136  		fields []string
   137  		adds   []map[int64][]string
   138  		want   map[string]map[string]interface{}
   139  	}{
   140  		{
   141  			name: "zero",
   142  			want: map[string]map[string]interface{}{},
   143  		},
   144  		{
   145  			name:   "basic",
   146  			fields: []string{"component"},
   147  			adds: []map[int64][]string{
   148  				{
   149  					12: {"updater"},
   150  				},
   151  			},
   152  			want: map[string]map[string]interface{}{
   153  				"component": {"updater": gauge{12, 12, 10 * time.Minute}},
   154  			},
   155  		},
   156  		{
   157  			name:   "fields",
   158  			fields: []string{"component", "source"},
   159  			adds: []map[int64][]string{
   160  				{64: {"updater", "prow"}},
   161  			},
   162  			want: map[string]map[string]interface{}{
   163  				"component": {
   164  					"updater": gauge{64, 64, 10 * time.Minute},
   165  				},
   166  				"source": {
   167  					"prow": gauge{64, 64, 10 * time.Minute},
   168  				},
   169  			},
   170  		},
   171  		{
   172  			name:   "values",
   173  			fields: []string{"component"},
   174  			adds: []map[int64][]string{
   175  				{64: {"updater"}},
   176  				{32: {"updater"}},
   177  			},
   178  			want: map[string]map[string]interface{}{
   179  				"component": {
   180  					"updater": gauge{64 + 32, 64 + 32, 10 * time.Minute},
   181  				},
   182  			},
   183  		},
   184  		{
   185  			name:   "fields and values",
   186  			fields: []string{"component", "source"},
   187  			adds: []map[int64][]string{
   188  				{64: {"updater", "prow"}},
   189  				{32: {"updater", "prow"}},
   190  			},
   191  			want: map[string]map[string]interface{}{
   192  				"component": {
   193  					"updater": gauge{64 + 32, 64 + 32, 10 * time.Minute},
   194  				},
   195  				"source": {
   196  					"prow": gauge{64 + 32, 64 + 32, 10 * time.Minute},
   197  				},
   198  			},
   199  		},
   200  		{
   201  			name:   "complex",
   202  			fields: []string{"component", "source"},
   203  			adds: []map[int64][]string{
   204  				{64: {"updater", "prow"}},
   205  				{66: {"updater", "google"}},
   206  				{32: {"summarizer", "google"}},
   207  			},
   208  			want: map[string]map[string]interface{}{
   209  				"component": {
   210  					"updater":    gauge{64 + 66, 64 + 66, 10 * time.Minute},
   211  					"summarizer": gauge{32, 32, 10 * time.Minute},
   212  				},
   213  				"source": {
   214  					"prow":   gauge{64, 64, 10 * time.Minute},
   215  					"google": gauge{66 + 32, 66 + 32, 10 * time.Minute},
   216  				},
   217  			},
   218  		},
   219  	}
   220  
   221  	for _, tc := range cases {
   222  		t.Run(tc.name, func(t *testing.T) {
   223  			var r Reporter
   224  			m := r.Counter("fake metric", "fake desc", logrus.WithField("name", tc.name), tc.fields...)
   225  			m.(*logCounter).last = when
   226  			for _, add := range tc.adds {
   227  				for n, values := range add {
   228  					m.Add(n, values...)
   229  				}
   230  			}
   231  
   232  			got := m.(Valuer).Values()
   233  			for _, got := range got {
   234  				for key, value := range got {
   235  					g := value.(gauge)
   236  					g.dur = g.dur.Round(time.Minute)
   237  					got[key] = g
   238  				}
   239  			}
   240  			if diff := cmp.Diff(tc.want, got, cmp.AllowUnexported(gauge{})); diff != "" {
   241  				t.Errorf("Add() got unexpected diff (-want +got):\n%s", diff)
   242  			}
   243  		})
   244  	}
   245  }
   246  
   247  func TestMean(t *testing.T) {
   248  	cases := []struct {
   249  		name string
   250  		m    mean
   251  		want string
   252  	}{
   253  		{
   254  			name: "basic",
   255  			want: "0 values",
   256  		},
   257  		{
   258  			name: "single",
   259  			m:    mean{values: []int64{7}},
   260  			want: "7",
   261  		},
   262  		{
   263  			name: "average",
   264  			m:    mean{values: []int64{7, 8, 9}},
   265  			want: "8 average (3 values)",
   266  		},
   267  	}
   268  
   269  	for _, tc := range cases {
   270  		t.Run(tc.name, func(t *testing.T) {
   271  			if got := tc.m.String(); got != tc.want {
   272  				t.Errorf("mean.String() got %q want %q", got, tc.want)
   273  			}
   274  		})
   275  	}
   276  }
   277  
   278  func TestQPS(t *testing.T) {
   279  	cases := []struct {
   280  		name string
   281  		g    gauge
   282  		want string
   283  	}{
   284  		{
   285  			name: "instant",
   286  			g: gauge{
   287  				delta: 100,
   288  			},
   289  			want: "0 per second",
   290  		},
   291  		{
   292  			name: "constant",
   293  			g: gauge{
   294  				dur: 5 * time.Second,
   295  			},
   296  			want: "0 per second",
   297  		},
   298  		{
   299  			name: "slow",
   300  			g: gauge{
   301  				delta: 1,
   302  				dur:   5*time.Second + 200*time.Millisecond,
   303  			},
   304  			want: "once per 5.2s",
   305  		},
   306  		{
   307  			name: "fast",
   308  			g: gauge{
   309  				delta: 100,
   310  				dur:   5 * time.Second,
   311  			},
   312  			want: "20.00 per second",
   313  		},
   314  	}
   315  
   316  	for _, tc := range cases {
   317  		t.Run(tc.name, func(t *testing.T) {
   318  			if got := tc.g.qps(); got != tc.want {
   319  				t.Errorf("gauge.qps() got %q want %q", got, tc.want)
   320  			}
   321  		})
   322  	}
   323  }