github.com/m3db/m3@v1.5.0/src/x/instrument/string_list_emitter_test.go (about) 1 // Copyright (c) 2019 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package instrument 22 23 import ( 24 "fmt" 25 "reflect" 26 "testing" 27 28 "github.com/stretchr/testify/require" 29 "github.com/uber-go/tally" 30 promreporter "github.com/uber-go/tally/prometheus" 31 ) 32 33 var bootstrappers = [][]string{ 34 { 35 "filesystem", 36 "peers", 37 "commitlog", 38 "uninitialized_topology", 39 }, 40 { 41 "uninitialized_topology", 42 "filesystem", 43 "peers", 44 "commitlog", 45 }, 46 { 47 "a", 48 "b", 49 "c", 50 "d", 51 }, 52 { 53 "foo", 54 "bar", 55 "hello", 56 "world", 57 "more", 58 "labels", 59 }, 60 { 61 "x", 62 "y", 63 }, 64 { 65 "foo", 66 }, 67 {"", "", "", ""}, 68 {}, 69 } 70 71 func TestBootstrapGaugeEmitterNoopScope(t *testing.T) { 72 scope := tally.NewTestScope("testScope", nil) 73 t.Run("TestNewBootstrapGaugeEmitter", func(t *testing.T) { 74 for _, bs := range bootstrappers { 75 76 bge := NewStringListEmitter(scope, "bootstrappers") 77 require.NotNil(t, bge) 78 require.NotNil(t, bge.gauges) 79 require.Equal(t, 1, len(bge.gauges)) 80 81 g := bge.newGauges(scope, bs) 82 require.NotNil(t, g) 83 require.Equal(t, len(bs), len(g)) 84 85 require.False(t, bge.running) 86 87 err := bge.UpdateStringList(bs) 88 require.Error(t, err) 89 require.NotNil(t, bge.gauges) 90 require.Equal(t, 1, len(bge.gauges)) 91 92 err = bge.Close() 93 require.Error(t, err) 94 95 err = bge.Start(bs) 96 require.NoError(t, err) 97 require.NotNil(t, bge.gauges) 98 require.True(t, bge.running) 99 require.Equal(t, len(bs), len(bge.gauges)) 100 if !reflect.DeepEqual(g, bge.gauges) { 101 t.Errorf("expected: %#v, got: %#v", g, bge.gauges) 102 } 103 104 err = bge.Close() 105 require.NoError(t, err) 106 require.False(t, bge.running) 107 } 108 }) 109 110 t.Run("TestEmitting", func(t *testing.T) { 111 scope := tally.NewTestScope("testScope", nil) 112 bs0 := bootstrappers[0] 113 bge := NewStringListEmitter(scope, "bootstrappers") 114 require.NotNil(t, bge) 115 require.NotNil(t, bge.gauges) 116 require.Equal(t, len(bge.gauges), 1) 117 118 // Start 119 err := bge.Start(bs0) 120 require.NoError(t, err) 121 require.True(t, bge.running) 122 require.NotNil(t, bge.gauges) 123 require.Equal(t, len(bge.gauges), len(bs0)) 124 125 gauges := scope.Snapshot().Gauges() 126 require.Equal(t, len(bs0), len(gauges), "length of gauges after start") 127 128 for _, id := range []string{ 129 fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]), 130 fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]), 131 fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]), 132 fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]), 133 } { 134 g, ok := gauges[id] 135 require.True(t, ok) 136 require.Equal(t, float64(1), g.Value(), "gauge value after start") 137 } 138 139 // // Update to new 140 bs1 := bootstrappers[1] 141 err = bge.UpdateStringList(bs1) 142 require.NoError(t, err) 143 require.True(t, bge.running, "state of bootstrapGaugeEmitter after update") 144 require.NotNil(t, bge.gauges) 145 require.Equal(t, len(bge.gauges), len(bs1)) 146 147 gauges = scope.Snapshot().Gauges() 148 require.Equal(t, 8, len(gauges), "length of gauges after updating") 149 for i, id := range []string{ 150 fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]), 151 fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]), 152 fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]), 153 fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]), 154 fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs1[0]), 155 fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs1[1]), 156 fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs1[2]), 157 fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs1[3]), 158 } { 159 g, ok := gauges[id] 160 require.True(t, ok) 161 if i < 4 { 162 require.Equal(t, float64(0), g.Value(), "first gauge value of after update") 163 } else { 164 require.Equal(t, float64(1), g.Value(), "second gauge value of after update") 165 } 166 } 167 168 // Update back to old 169 err = bge.UpdateStringList(bs0) 170 require.NoError(t, err) 171 require.True(t, bge.running, "state of bootstrapGaugeEmitter after update") 172 require.NotNil(t, bge.gauges) 173 require.Equal(t, len(bge.gauges), len(bs0)) 174 175 gauges = scope.Snapshot().Gauges() 176 require.Equal(t, 8, len(gauges), "length of gauges after updating") 177 for i, id := range []string{ 178 fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]), 179 fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]), 180 fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]), 181 fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]), 182 fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs1[0]), 183 fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs1[1]), 184 fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs1[2]), 185 fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs1[3]), 186 } { 187 g, ok := gauges[id] 188 require.True(t, ok) 189 if i < 4 { 190 require.Equal(t, float64(1), g.Value(), "first gauge value of after update") 191 } else { 192 require.Equal(t, float64(0), g.Value(), "second gauge value of after update") 193 } 194 } 195 196 // Update back to old again -- test emitting same metric twice 197 err = bge.UpdateStringList(bs0) 198 require.NoError(t, err) 199 require.True(t, bge.running, "state of bootstrapGaugeEmitter after update") 200 require.NotNil(t, bge.gauges) 201 require.Equal(t, len(bge.gauges), len(bs0)) 202 203 gauges = scope.Snapshot().Gauges() 204 require.Equal(t, 8, len(gauges), "length of gauges after updating") 205 for i, id := range []string{ 206 fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs0[0]), 207 fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs0[1]), 208 fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs0[2]), 209 fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs0[3]), 210 fmt.Sprintf("testScope.bootstrappers_0+type=%s", bs1[0]), 211 fmt.Sprintf("testScope.bootstrappers_1+type=%s", bs1[1]), 212 fmt.Sprintf("testScope.bootstrappers_2+type=%s", bs1[2]), 213 fmt.Sprintf("testScope.bootstrappers_3+type=%s", bs1[3]), 214 } { 215 g, ok := gauges[id] 216 require.True(t, ok) 217 if i < 4 { 218 require.Equal(t, float64(1), g.Value(), "first gauge value of after update") 219 } else { 220 require.Equal(t, float64(0), g.Value(), "second gauge value of after update") 221 } 222 } 223 224 // Close 225 err = bge.Close() 226 require.NoError(t, err) 227 require.False(t, bge.running) 228 }) 229 230 t.Run("MultipleLabelCombinations", func(t *testing.T) { 231 bge := NewStringListEmitter(scope, "bootstrappers") 232 require.NotNil(t, bge) 233 require.NotNil(t, bge.gauges) 234 235 err := bge.Start(bootstrappers[0]) 236 require.NoError(t, err) 237 require.True(t, bge.running) 238 require.NotNil(t, bge.gauges) 239 240 // Update same Gauge with standard bootstrappers 241 for _, bs := range bootstrappers { 242 err = bge.UpdateStringList(bs) 243 require.NoError(t, err) 244 require.True(t, bge.running) 245 require.NotNil(t, bge.gauges) 246 } 247 248 err = bge.Close() 249 require.NoError(t, err) 250 require.False(t, bge.running) 251 }) 252 } 253 254 // This test might timeout instead of just fail 255 func TestStringListEmitterPrometheusScope(t *testing.T) { 256 r := promreporter.NewReporter(promreporter.Options{}) 257 scope, closer := tally.NewRootScope(tally.ScopeOptions{ 258 Prefix: "", 259 Tags: map[string]string{}, 260 CachedReporter: r, 261 }, 0) 262 defer closer.Close() 263 264 bge := NewStringListEmitter(scope, "bootstrappers") 265 require.NotNil(t, bge) 266 require.NotNil(t, bge.gauges) 267 268 err := bge.Start(bootstrappers[0]) 269 require.NoError(t, err) 270 require.True(t, bge.running) 271 require.NotNil(t, bge.gauges) 272 273 for _, bs := range bootstrappers { 274 err = bge.UpdateStringList(bs) 275 require.NoError(t, err) 276 require.True(t, bge.running) 277 require.NotNil(t, bge.gauges) 278 } 279 280 err = bge.Close() 281 require.NoError(t, err) 282 require.False(t, bge.running) 283 }