(t *testing.T)
| 234 | } |
| 235 | |
| 236 | func TestAutoForgetDelegate(t *testing.T) { |
| 237 | const forgetPeriod = time.Minute |
| 238 | registeredAt := time.Now() |
| 239 | |
| 240 | tests := map[string]struct { |
| 241 | setup func(ringDesc *Desc) |
| 242 | expectedInstances []string |
| 243 | }{ |
| 244 | "no unhealthy instance in the ring": { |
| 245 | setup: func(ringDesc *Desc) { |
| 246 | ringDesc.AddIngester("instance-1", "1.1.1.1", "", nil, ACTIVE, registeredAt) |
| 247 | }, |
| 248 | expectedInstances: []string{testInstanceID, "instance-1"}, |
| 249 | }, |
| 250 | "unhealthy instance in the ring that has NOTreached the forget period yet": { |
| 251 | setup: func(ringDesc *Desc) { |
| 252 | i := ringDesc.AddIngester("instance-1", "1.1.1.1", "", nil, ACTIVE, registeredAt) |
| 253 | i.Timestamp = time.Now().Add(-forgetPeriod).Add(5 * time.Second).Unix() |
| 254 | ringDesc.Ingesters["instance-1"] = i |
| 255 | }, |
| 256 | expectedInstances: []string{testInstanceID, "instance-1"}, |
| 257 | }, |
| 258 | "unhealthy instance in the ring that has reached the forget period": { |
| 259 | setup: func(ringDesc *Desc) { |
| 260 | i := ringDesc.AddIngester("instance-1", "1.1.1.1", "", nil, ACTIVE, registeredAt) |
| 261 | i.Timestamp = time.Now().Add(-forgetPeriod).Add(-5 * time.Second).Unix() |
| 262 | ringDesc.Ingesters["instance-1"] = i |
| 263 | }, |
| 264 | expectedInstances: []string{testInstanceID}, |
| 265 | }, |
| 266 | } |
| 267 | |
| 268 | for testName, testData := range tests { |
| 269 | t.Run(testName, func(t *testing.T) { |
| 270 | ctx := context.Background() |
| 271 | cfg := prepareBasicLifecyclerConfig() |
| 272 | cfg.HeartbeatPeriod = 100 * time.Millisecond |
| 273 | |
| 274 | testDelegate := &mockDelegate{} |
| 275 | |
| 276 | autoForgetDelegate := NewAutoForgetDelegate(forgetPeriod, testDelegate, log.NewNopLogger()) |
| 277 | lifecycler, store, err := prepareBasicLifecyclerWithDelegate(t, cfg, autoForgetDelegate) |
| 278 | require.NoError(t, err) |
| 279 | |
| 280 | // Setup the initial state of the ring. |
| 281 | require.NoError(t, store.CAS(ctx, testRingKey, func(in any) (out any, retry bool, err error) { |
| 282 | ringDesc := NewDesc() |
| 283 | testData.setup(ringDesc) |
| 284 | return ringDesc, true, nil |
| 285 | })) |
| 286 | |
| 287 | // Start the lifecycler. |
| 288 | require.NoError(t, services.StartAndAwaitRunning(ctx, lifecycler)) |
| 289 | defer services.StopAndAwaitTerminated(ctx, lifecycler) //nolint:errcheck |
| 290 | |
| 291 | // Wait until an heartbeat has been sent. |
| 292 | test.Poll(t, time.Second, true, func() any { |
| 293 | return testutil.ToFloat64(lifecycler.metrics.heartbeats) > 0 |
nothing calls this directly
no test coverage detected