func TestMultipleRegistrations(t *testing.T) { testcases := []struct { name string // component checker health.Checker // health checker }{ {"component-alive", healthy}, {"component-up", healthy}, {"component-failed", failed}, {"component-dead", failed}, {"component-ok", healthy}, } for _, tc := range testcases { health.Register(tc.name, tc.checker) } assert.Len(t, health.Components(), len(testcases)) // all registered all := health.RunChecks() for _, tc := range testcases { assert.Contains(t, health.Components(), tc.name) _, found := all[tc.name] assert.True(t, found) assert.EqualValues(t, all[tc.name], tc.checker.Check(), tc.name) } teardown() }
func TestDeregisterHealthCheck(t *testing.T) { health.Register(COMPONENT, healthy) health.Unregister(COMPONENT) assert.Len(t, health.Components(), 0) assert.NotContains(t, health.Components(), COMPONENT) all := health.RunChecks() assert.Len(t, all, 0) teardown() }
func TestRegisterFunc(t *testing.T) { health.RegisterFunc(COMPONENT, alwaysFailing) assert.Len(t, health.Components(), 1) assert.Contains(t, health.Components(), COMPONENT) all := health.RunChecks() status, found := all[COMPONENT] assert.True(t, found) assert.EqualValues(t, status, alwaysFailing()) teardown() }
func TestRegisterDuplicateHealthCheck(t *testing.T) { health.Register(COMPONENT, healthy) health.RegisterFunc(COMPONENT, alwaysFailing) // replace with failing health check assert.Len(t, health.Components(), 1) assert.Contains(t, health.Components(), COMPONENT) all := health.RunChecks() status, found := all[COMPONENT] assert.True(t, found) assert.EqualValues(t, status, alwaysFailing()) teardown() }
func TestHealthCheckExecuteUnhealthy(t *testing.T) { health.Register(COMPONENT, &stubHealthCheck{healthy: false}) checks := health.RunChecks() for component, hc := range checks { assert.Equal(t, component, COMPONENT) assert.False(t, hc.Healthy) assert.Equal(t, FAILING, hc.Properties["message"]) } teardown() }
func TestHealthCheckExecuteHealthy(t *testing.T) { health.Register(COMPONENT, &stubHealthCheck{healthy: true}) checks := health.RunChecks() for component, hc := range checks { assert.Equal(t, component, COMPONENT) assert.True(t, hc.Healthy) assert.Empty(t, hc.Properties["cause"]) } teardown() }
//----------------------------------------------------------------------------- // recover from health check panic and mark component as failing func TestRecoverFromHealthCheckPanic(t *testing.T) { cause := "oops I did it again" health.RegisterFunc("Will panic", func() health.Status { panic(cause) }) checks := health.RunChecks() assert.Len(t, checks, 1) for _, hc := range checks { assert.False(t, hc.Healthy) assert.Equal(t, health.CheckPanicked, hc.Properties["message"]) assert.Equal(t, cause, hc.Properties["cause"]) } teardown() }
func TestParallelExecution(t *testing.T) { start := time.Now() expected_end := start.Add(time.Second) for i := 0; i < 5; i++ { health.RegisterFunc(fmt.Sprint("Sleeper-", i), func() health.Status { time.Sleep(1 * time.Second) return health.Healthy }) } _ = health.RunChecks() // we don't really expect it to diverge by more than ~100ms, to avoid false negatives, allow one // second drift - still considerably less than the 5s if running checks sequenctially assert.WithinDuration(t, expected_end, time.Now(), time.Second, "not running concurrently") teardown() }