github.com/xmidt-org/webpa-common@v1.11.9/device/rehasher/rehasher_test.go (about) 1 package rehasher 2 3 import ( 4 "errors" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/mock" 10 "github.com/stretchr/testify/require" 11 "github.com/xmidt-org/webpa-common/device" 12 "github.com/xmidt-org/webpa-common/logging" 13 "github.com/xmidt-org/webpa-common/service" 14 "github.com/xmidt-org/webpa-common/service/monitor" 15 "github.com/xmidt-org/webpa-common/xmetrics/xmetricstest" 16 ) 17 18 func testNewNilConnector(t *testing.T) { 19 assert := assert.New(t) 20 assert.Panics(func() { 21 New(nil, nil, WithAccessorFactory(nil), WithIsRegistered(func(string) bool { return true })) 22 }) 23 } 24 25 func testNewEmptyServices(t *testing.T) { 26 assert := assert.New(t) 27 28 assert.Panics(func() { 29 New(new(device.MockConnector), nil, WithAccessorFactory(nil), WithIsRegistered(func(string) bool { return true })) 30 }) 31 } 32 33 func testNewMissingIsRegistered(t *testing.T) { 34 var ( 35 assert = assert.New(t) 36 c = new(device.MockConnector) 37 ) 38 39 assert.Panics(func() { 40 New(c, nil, WithAccessorFactory(nil)) 41 }) 42 43 c.AssertExpectations(t) 44 } 45 46 func testNewNilLogger(t *testing.T) { 47 var ( 48 assert = assert.New(t) 49 50 isRegistered = func(string) bool { 51 assert.Fail("isRegistered should not have been called") 52 return false 53 } 54 55 connector = new(device.MockConnector) 56 r = New( 57 connector, 58 []string{"talaria"}, 59 WithLogger(nil), 60 WithIsRegistered(isRegistered), 61 ) 62 ) 63 64 assert.NotNil(r) 65 connector.AssertExpectations(t) 66 } 67 68 func testNewNilMetricsProvider(t *testing.T) { 69 var ( 70 assert = assert.New(t) 71 72 isRegistered = func(string) bool { 73 assert.Fail("isRegistered should not have been called") 74 return false 75 } 76 77 connector = new(device.MockConnector) 78 r = New( 79 connector, 80 []string{"talaria"}, 81 WithLogger(logging.NewTestLogger(nil, t)), 82 WithIsRegistered(isRegistered), 83 WithMetricsProvider(nil), 84 ) 85 ) 86 87 assert.NotNil(r) 88 connector.AssertExpectations(t) 89 } 90 91 func TestNew(t *testing.T) { 92 t.Run("NilConnector", testNewNilConnector) 93 t.Run("EmptyServices", testNewEmptyServices) 94 t.Run("MissingIsRegistered", testNewMissingIsRegistered) 95 t.Run("NilLogger", testNewNilLogger) 96 t.Run("NilMetricsProvider", testNewNilMetricsProvider) 97 } 98 99 func testRehasherServiceDiscoveryError(t *testing.T) { 100 var ( 101 assert = assert.New(t) 102 require = require.New(t) 103 provider = xmetricstest.NewProvider(nil, Metrics) 104 105 isRegistered = func(string) bool { 106 assert.Fail("isRegistered should not have been called") 107 return false 108 } 109 110 serviceDiscoveryError = errors.New("service discovery error") 111 connector = new(device.MockConnector) 112 r = New( 113 connector, 114 []string{"talaria", "caduceus"}, 115 WithLogger(logging.NewTestLogger(nil, t)), 116 WithIsRegistered(isRegistered), 117 WithMetricsProvider(provider), 118 ) 119 ) 120 121 require.NotNil(r) 122 connector.On("DisconnectAll", device.CloseReason{Err: serviceDiscoveryError, Text: ServiceDiscoveryError}).Return(12) 123 provider.Expect(RehashKeepDevice, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 124 provider.Expect(RehashDisconnectDevice, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 125 provider.Expect(RehashDisconnectAllCounter, service.ServiceLabel, "talaria", ReasonLabel, DisconnectAllServiceDiscoveryError)( 126 xmetricstest.Counter, 127 xmetricstest.Value(1.0), 128 ) 129 provider.Expect(RehashTimestamp, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 130 provider.Expect(RehashDurationMilliseconds, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 131 132 r.MonitorEvent(monitor.Event{EventCount: 10, Key: "test", Service: "talaria", Err: serviceDiscoveryError}) 133 134 connector.AssertExpectations(t) 135 provider.AssertExpectations(t) 136 } 137 138 func testRehasherServiceDiscoveryStopped(t *testing.T) { 139 var ( 140 assert = assert.New(t) 141 require = require.New(t) 142 provider = xmetricstest.NewProvider(nil, Metrics) 143 144 isRegistered = func(string) bool { 145 assert.Fail("isRegistered should not have been called") 146 return false 147 } 148 149 connector = new(device.MockConnector) 150 r = New( 151 connector, 152 []string{"caduceus"}, 153 WithLogger(logging.NewTestLogger(nil, t)), 154 WithIsRegistered(isRegistered), 155 WithMetricsProvider(provider), 156 ) 157 ) 158 159 require.NotNil(r) 160 connector.On("DisconnectAll", device.CloseReason{Text: ServiceDiscoveryStopped}).Return(0) 161 provider.Expect(RehashKeepDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 162 provider.Expect(RehashDisconnectDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 163 provider.Expect(RehashDisconnectAllCounter, service.ServiceLabel, "caduceus", ReasonLabel, DisconnectAllServiceDiscoveryStopped)( 164 xmetricstest.Counter, 165 xmetricstest.Value(1.0), 166 ) 167 provider.Expect(RehashTimestamp, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 168 provider.Expect(RehashDurationMilliseconds, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 169 170 r.MonitorEvent(monitor.Event{Key: "test", Service: "caduceus", EventCount: 10, Stopped: true}) 171 172 connector.AssertExpectations(t) 173 provider.AssertExpectations(t) 174 } 175 176 func testRehasherInitialEvent(t *testing.T) { 177 var ( 178 assert = assert.New(t) 179 require = require.New(t) 180 provider = xmetricstest.NewProvider(nil, Metrics) 181 182 isRegistered = func(string) bool { 183 assert.Fail("isRegistered should not have been called") 184 return false 185 } 186 187 connector = new(device.MockConnector) 188 r = New( 189 connector, 190 []string{"talaria"}, 191 WithLogger(logging.NewTestLogger(nil, t)), 192 WithIsRegistered(isRegistered), 193 WithMetricsProvider(provider), 194 ) 195 ) 196 197 require.NotNil(r) 198 provider.Expect(RehashKeepDevice, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 199 provider.Expect(RehashDisconnectDevice, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 200 provider.Expect(RehashDisconnectAllCounter, service.ServiceLabel, "talaria")(xmetricstest.Counter, xmetricstest.Value(0.0)) 201 provider.Expect(RehashTimestamp, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 202 provider.Expect(RehashDurationMilliseconds, service.ServiceLabel, "talaria")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 203 204 r.MonitorEvent(monitor.Event{Key: "test", Service: "talaria", EventCount: 1}) 205 206 connector.AssertExpectations(t) 207 provider.AssertExpectations(t) 208 } 209 210 func testRehasherSkippedService(t *testing.T) { 211 var ( 212 assert = assert.New(t) 213 require = require.New(t) 214 provider = xmetricstest.NewProvider(nil, Metrics) 215 216 isRegistered = func(string) bool { 217 assert.Fail("isRegistered should not have been called") 218 return false 219 } 220 221 connector = new(device.MockConnector) 222 r = New( 223 connector, 224 []string{"caduceus"}, 225 WithLogger(logging.NewTestLogger(nil, t)), 226 WithIsRegistered(isRegistered), 227 WithMetricsProvider(provider), 228 ) 229 ) 230 231 require.NotNil(r) 232 connector.AssertNotCalled(t, "DisconnectAll", mock.Anything) 233 provider.Expect(RehashKeepDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 234 provider.Expect(RehashDisconnectDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 235 provider.Expect(RehashDisconnectAllCounter, service.ServiceLabel, "caduceus", ReasonLabel, DisconnectAllServiceDiscoveryNoInstances)( 236 xmetricstest.Counter, 237 xmetricstest.Value(0.0), 238 ) 239 provider.Expect(RehashTimestamp, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 240 provider.Expect(RehashDurationMilliseconds, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 241 242 r.MonitorEvent(monitor.Event{Key: "test", Service: "tr1d1um", EventCount: 10}) 243 244 connector.AssertExpectations(t) 245 provider.AssertExpectations(t) 246 } 247 248 func testRehasherNoInstances(t *testing.T) { 249 var ( 250 assert = assert.New(t) 251 require = require.New(t) 252 provider = xmetricstest.NewProvider(nil, Metrics) 253 254 isRegistered = func(string) bool { 255 assert.Fail("isRegistered should not have been called") 256 return false 257 } 258 259 connector = new(device.MockConnector) 260 r = New( 261 connector, 262 []string{"caduceus"}, 263 WithLogger(logging.NewTestLogger(nil, t)), 264 WithIsRegistered(isRegistered), 265 WithMetricsProvider(provider), 266 ) 267 ) 268 269 require.NotNil(r) 270 connector.On("DisconnectAll", device.CloseReason{Text: ServiceDiscoveryNoInstances}).Return(0) 271 provider.Expect(RehashKeepDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 272 provider.Expect(RehashDisconnectDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 273 provider.Expect(RehashDisconnectAllCounter, service.ServiceLabel, "caduceus", ReasonLabel, DisconnectAllServiceDiscoveryNoInstances)( 274 xmetricstest.Counter, 275 xmetricstest.Value(1.0), 276 ) 277 provider.Expect(RehashTimestamp, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 278 provider.Expect(RehashDurationMilliseconds, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(0.0)) 279 280 r.MonitorEvent(monitor.Event{Key: "test", Service: "caduceus", EventCount: 10}) 281 282 connector.AssertExpectations(t) 283 provider.AssertExpectations(t) 284 } 285 286 func testRehasherRehash(t *testing.T) { 287 var ( 288 assert = assert.New(t) 289 require = require.New(t) 290 provider = xmetricstest.NewProvider(nil, Metrics) 291 292 keepID = device.ID("keep") 293 keepNode = "keep.xfinity.net" 294 295 rehashedID = device.ID("rehashed") 296 rehashNode = "rehash.xfinity.net" 297 298 accessorErrorID = device.ID("accessorError") 299 accessorError = errors.New("expected accessor error") 300 301 expectedNodes = []string{keepNode, rehashNode} 302 accessorFactory = service.AccessorFactory(func(actualNodes []string) service.Accessor { 303 assert.Equal(expectedNodes, actualNodes) 304 return service.AccessorFunc(func(key []byte) (string, error) { 305 switch string(key) { 306 case string(keepID): 307 return keepNode, nil 308 309 case string(rehashedID): 310 return rehashNode, nil 311 312 case string(accessorErrorID): 313 return "", accessorError 314 315 default: 316 assert.Fail("Invalid accessor key") 317 return "", errors.New("test failure: invalid accessor key") 318 } 319 }) 320 }) 321 322 isRegistered = func(v string) bool { 323 return keepNode == v 324 } 325 326 expectedDuration = 10 * time.Minute 327 start = time.Now() 328 end = start.Add(expectedDuration) 329 nowFirst = true 330 now = func() time.Time { 331 if nowFirst { 332 nowFirst = false 333 return start 334 } 335 336 return end 337 } 338 339 connector = new(device.MockConnector) 340 r = New( 341 connector, 342 []string{"talaria", "caduceus"}, 343 WithLogger(logging.NewTestLogger(nil, t)), 344 WithIsRegistered(isRegistered), 345 WithAccessorFactory(accessorFactory), 346 WithMetricsProvider(provider), 347 ) 348 ) 349 350 require.NotNil(r) 351 r.(*rehasher).now = now 352 connector.On("DisconnectIf", mock.MatchedBy( 353 func(func(device.ID) (device.CloseReason, bool)) bool { return true }, 354 )). 355 Run(func(arguments mock.Arguments) { 356 f := arguments.Get(0).(func(device.ID) (device.CloseReason, bool)) 357 358 reason, closed := f(keepID) 359 assert.Equal(device.CloseReason{}, reason) 360 assert.False(closed) 361 362 reason, closed = f(rehashedID) 363 assert.Equal(device.CloseReason{Text: RehashOtherInstance}, reason) 364 assert.True(closed) 365 366 reason, closed = f(accessorErrorID) 367 assert.Equal(device.CloseReason{Err: accessorError, Text: RehashError}, reason) 368 assert.True(closed) 369 }). 370 Return(2) 371 372 provider.Expect(RehashKeepDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(1.0)) 373 provider.Expect(RehashDisconnectDevice, service.ServiceLabel, "caduceus")(xmetricstest.Gauge, xmetricstest.Value(2.0)) 374 provider.Expect(RehashDisconnectAllCounter, service.ServiceLabel, "caduceus")(xmetricstest.Counter, xmetricstest.Value(0.0)) 375 provider.Expect(RehashTimestamp, service.ServiceLabel, "caduceus")( 376 xmetricstest.Gauge, 377 xmetricstest.Value(float64(start.UTC().Unix())), 378 ) 379 provider.Expect(RehashDurationMilliseconds, service.ServiceLabel, "caduceus")( 380 xmetricstest.Gauge, 381 xmetricstest.Value(float64(expectedDuration/time.Millisecond)), 382 ) 383 384 r.MonitorEvent(monitor.Event{Key: "test", Service: "caduceus", EventCount: 10, Instances: expectedNodes}) 385 386 connector.AssertExpectations(t) 387 provider.AssertExpectations(t) 388 } 389 390 func TestRehasher(t *testing.T) { 391 t.Run("ServiceDiscoveryError", testRehasherServiceDiscoveryError) 392 t.Run("ServiceDiscoveryStopped", testRehasherServiceDiscoveryStopped) 393 t.Run("InitialEvent", testRehasherInitialEvent) 394 t.Run("NoInstances", testRehasherNoInstances) 395 t.Run("Rehash", testRehasherRehash) 396 t.Run("SkippedServicee", testRehasherSkippedService) 397 }