func TestFromHealthCheckSource(t *testing.T) {
	// health check sends on this channel on its third run (after it has returned healthy and then error)
	doneChan := make(chan struct{})
	defer close(doneChan)

	// health check waits on this channel on its third run (after it has sent on doneChan)
	pauseChan := make(chan struct{})
	defer close(pauseChan)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	gracePeriod := 100 * time.Millisecond
	retryInterval := 10 * time.Millisecond
	counter := 0

	source := FromHealthCheckSource(ctx, gracePeriod, retryInterval, Source{
		Checks: map[health.CheckType]CheckFunc{
			checkType: func(ctx context.Context) (rVal *health.HealthCheckResult) {
				defer func() {
					counter++
				}()

				switch counter {
				// return healthy state on first run
				case 0:
					return &health.HealthCheckResult{
						Type:    checkType,
						State:   health.HealthStateHealthy,
						Message: stringPtr("Healthy state"),
						Params: map[string]interface{}{
							"counter": counter,
						},
					}
				// return error state on second run
				case 1:
					return &health.HealthCheckResult{
						Type:    checkType,
						State:   health.HealthStateError,
						Message: stringPtr("Error state"),
						Params: map[string]interface{}{
							"counter": counter,
						},
					}
				// on third run, send on doneChan and read from pauseChan
				case 2:
					// signal that health can be checked
					doneChan <- struct{}{}
					// pause until health check has occurred
					<-pauseChan
					// return unhealthy
					return &health.HealthCheckResult{
						Type:    checkType,
						State:   health.HealthStateError,
						Message: stringPtr("Error state"),
						Params: map[string]interface{}{
							"counter": counter,
						},
					}
				case 3:
					// signal that health can be checked
					doneChan <- struct{}{}
					// pause (do not return until test has completed)
					<-pauseChan
				}
				return nil
			},
		},
	})

	// wait until health check has returned healthy and then unhealthy
	<-doneChan
	status := source.HealthStatus(ctx)

	// health check should be healthy: even though health source returned error state most recently, it returned
	// healthy state within the grace period
	assert.Equal(t, map[health.CheckType]health.HealthCheckResult{
		checkType: {
			Type:    checkType,
			State:   health.HealthStateHealthy,
			Message: stringPtr("Healthy state"),
			Params: map[string]interface{}{
				"counter": 0,
			},
		},
	}, status.Checks)

	// health has been checked: wait for grace period to pass and then unpause the health routine
	time.Sleep(gracePeriod)
	pauseChan <- struct{}{}
	<-doneChan

	// health check should be unhealthy: the most recent check ran within the grace period, but the last success was before grace period
	status = source.HealthStatus(ctx)
	assert.Equal(t, map[health.CheckType]health.HealthCheckResult{
		checkType: {
			Type:    checkType,
			State:   health.HealthStateError,
			Message: stringPtr("No successful checks during 100ms grace period: Error state"),
			Params: map[string]interface{}{
				"counter": 2,
			},
		},
	}, status.Checks)

	// wait for grace period
	time.Sleep(gracePeriod)

	// health check should be unhealthy: no check ran within grace period, and last known status was unhealthy
	status = source.HealthStatus(ctx)
	assert.Equal(t, map[health.CheckType]health.HealthCheckResult{
		checkType: {
			Type:    checkType,
			State:   health.HealthStateError,
			Message: stringPtr("No completed checks during 100ms grace period: Error state"),
			Params: map[string]interface{}{
				"counter": 2,
			},
		},
	}, status.Checks)
}
// Test does the following:
//   * Starts health check source with 10ms retry interval and 100ms grace period
//   * First health check returns healthy (t=10ms, counter=0)
//   * Second health check returns unhealthy (t=20ms, counter=1)
//   * When third health check is run, pause the health check routine and signal that health should be checked (t=30ms)
//   * TEST: health status should be healthy, counter=0 (checking at roughly t=30ms, so there was a healthy check within grace period)
//   * Wait until grace period has elapsed since healthy check was returned (roughly t=130ms)
//   * Third check returns unhealthy (t=130ms, counter=2)
//   * TEST: health status should be unhealthy due to no success within grace period (checking at roughly t=130ms, so there was a check that occurred within the grace period, but no successful check within the grace period)
//   * Wait until grace period has elapsed (t=230ms)
//   * TEST: health status should be unhealthy due to no check within grace period (checking at roughly t=230ms, so there is no check that occurred within the grace period)
Test does the following:
Starts health check source with 10ms retry interval and 100ms grace period
First health check returns healthy (t=10ms, counter=0)
Second health check returns unhealthy (t=20ms, counter=1)
When third health check is run, pause the health check routine and signal that health should be checked (t=30ms)
TEST: health status should be healthy, counter=0 (checking at roughly t=30ms, so there was a healthy check within grace period)
Wait until grace period has elapsed since healthy check was returned (roughly t=130ms)
Third check returns unhealthy (t=130ms, counter=2)
TEST: health status should be unhealthy due to no success within grace period (checking at roughly t=130ms, so there was a check that occurred within the grace period, but no successful check within the grace period)
Wait until grace period has elapsed (t=230ms)
TEST: health status should be unhealthy due to no check within grace period (checking at roughly t=230ms, so there is no check that occurred within the grace period)
// Test does the following : // * Starts health check source with 10ms retry interval and 100ms grace period // * First health check returns healthy ( t = 10ms counter = 0 ) // * Second health check returns unhealthy ( t = 20ms counter = 1 ) // * When third health check is run pause the health check routine and signal that health should be checked ( t = 30ms ) // * TEST : health status should be healthy counter = 0 ( checking at roughly t = 30ms so there was a healthy check within grace period ) // * Wait until grace period has elapsed since healthy check was returned ( roughly t = 130ms ) // * Third check returns unhealthy ( t = 130ms counter = 2 ) // * TEST : health status should be unhealthy due to no success within grace period ( checking at roughly t = 130ms so there was a check that occurred within the grace period but no successful check within the grace period ) // * Wait until grace period has elapsed ( t = 230ms ) // * TEST : health status should be unhealthy due to no check within grace period ( checking at roughly t = 230ms so there is no check that occurred within the grace period )
func TestFromHealthCheckSource(t *testing.T) {
	doneChan := make(chan struct{})
	defer close(doneChan)
	pauseChan := make(chan struct{})
	defer close(pauseChan)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	gracePeriod := 100 * time.Millisecond
	retryInterval := 10 * time.Millisecond
	counter := 0
	source := FromHealthCheckSource(ctx, gracePeriod, retryInterval, Source{
		Checks: map[health.CheckType]CheckFunc{
			checkType: func(ctx context.Context) (rVal *health.HealthCheckResult) {
				defer func() {
					counter++
				}()
				switch counter {
				case 0:
					return &health.HealthCheckResult{
						Type:    checkType,
						State:   health.HealthStateHealthy,
						Message: stringPtr("Healthy state"),
						Params: map[string]interface{}{
							"counter": counter,
						},
					}
				case 1:
					return &health.HealthCheckResult{
						Type:    checkType,
						State:   health.HealthStateError,
						Message: stringPtr("Error state"),
						Params: map[string]interface{}{
							"counter": counter,
						},
					}
				case 2:
					doneChan <- struct{}{}
					<-pauseChan
					return &health.HealthCheckResult{
						Type:    checkType,
						State:   health.HealthStateError,
						Message: stringPtr("Error state"),
						Params: map[string]interface{}{
							"counter": counter,
						},
					}
				case 3:
					doneChan <- struct{}{}
					<-pauseChan
				}
				return nil
			},
		},
	})
	<-doneChan
	status := source.HealthStatus(ctx)
	assert.Equal(t, map[health.CheckType]health.HealthCheckResult{
		checkType: {
			Type:    checkType,
			State:   health.HealthStateHealthy,
			Message: stringPtr("Healthy state"),
			Params: map[string]interface{}{
				"counter": 0,
			},
		},
	}, status.Checks)
	time.Sleep(gracePeriod)
	pauseChan <- struct{}{}
	<-doneChan
	status = source.HealthStatus(ctx)
	assert.Equal(t, map[health.CheckType]health.HealthCheckResult{
		checkType: {
			Type:    checkType,
			State:   health.HealthStateError,
			Message: stringPtr("No successful checks during 100ms grace period: Error state"),
			Params: map[string]interface{}{
				"counter": 2,
			},
		},
	}, status.Checks)
	time.Sleep(gracePeriod)
	status = source.HealthStatus(ctx)
	assert.Equal(t, map[health.CheckType]health.HealthCheckResult{
		checkType: {
			Type:    checkType,
			State:   health.HealthStateError,
			Message: stringPtr("No completed checks during 100ms grace period: Error state"),
			Params: map[string]interface{}{
				"counter": 2,
			},
		},
	}, status.Checks)
}
func TestFromHealthCheckSource ( t * testing . T ) { doneChan := make ( chan struct { } ) defer close ( doneChan ) pauseChan := make ( chan struct { } ) defer close ( pauseChan ) ctx , cancel := context . WithCancel ( context . Background ( ) ) defer cancel ( ) gracePeriod := 100 * time . Millisecond retryInterval := 10 * time . Millisecond counter := 0 source := FromHealthCheckSource ( ctx , gracePeriod , retryInterval , Source { Checks : map [ health . CheckType ] CheckFunc { checkType : func ( ctx context . Context ) ( rVal * health . HealthCheckResult ) { defer func ( ) { counter ++ } ( ) switch counter { case 0 : return & health . HealthCheckResult { Type : checkType , State : health . HealthStateHealthy , Message : stringPtr ( " " ) , Params : map [ string ] interface { } { " " : counter , } , } case 1 : return & health . HealthCheckResult { Type : checkType , State : health . HealthStateError , Message : stringPtr ( " " ) , Params : map [ string ] interface { } { " " : counter , } , } case 2 : doneChan <- struct { } { } <- pauseChan return & health . HealthCheckResult { Type : checkType , State : health . HealthStateError , Message : stringPtr ( " " ) , Params : map [ string ] interface { } { " " : counter , } , } case 3 : doneChan <- struct { } { } <- pauseChan } return nil } , } , } ) <- doneChan status := source . HealthStatus ( ctx ) assert . Equal ( t , map [ health . CheckType ] health . HealthCheckResult { checkType : { Type : checkType , State : health . HealthStateHealthy , Message : stringPtr ( " " ) , Params : map [ string ] interface { } { " " : 0 , } , } , } , status . Checks ) time . Sleep ( gracePeriod ) pauseChan <- struct { } { } <- doneChan status = source . HealthStatus ( ctx ) assert . Equal ( t , map [ health . CheckType ] health . HealthCheckResult { checkType : { Type : checkType , State : health . HealthStateError , Message : stringPtr ( " " ) , Params : map [ string ] interface { } { " " : 2 , } , } , } , status . Checks ) time . Sleep ( gracePeriod ) status = source . HealthStatus ( ctx ) assert . Equal ( t , map [ health . CheckType ] health . HealthCheckResult { checkType : { Type : checkType , State : health . HealthStateError , Message : stringPtr ( " " ) , Params : map [ string ] interface { } { " " : 2 , } , } , } , status . Checks ) }
Test does the following:
Starts health check source with 10ms retry interval and 100ms grace period
First health check returns healthy (t=10ms, counter=0)
Second health check returns unhealthy (t=20ms, counter=1)
When third health check is run, pause the health check routine and signal that health should be checked (t=30ms)
TEST: health status should be healthy, counter=0 (checking at roughly t=30ms, so there was a healthy check within grace period)
Wait until grace period has elapsed since healthy check was returned (roughly t=130ms)
Third check returns unhealthy (t=130ms, counter=2)
TEST: health status should be unhealthy due to no success within grace period (checking at roughly t=130ms, so there was a check that occurred within the grace period, but no successful check within the grace period)
Wait until grace period has elapsed (t=230ms)
TEST: health status should be unhealthy due to no check within grace period (checking at roughly t=230ms, so there is no check that occurred within the grace period)
Test does the following : Starts health check source with 10ms retry interval and 100ms grace period First health check returns healthy ( t = 10ms counter = 0 ) Second health check returns unhealthy ( t = 20ms counter = 1 ) When third health check is run pause the health check routine and signal that health should be checked ( t = 30ms ) TEST : health status should be healthy counter = 0 ( checking at roughly t = 30ms so there was a healthy check within grace period ) Wait until grace period has elapsed since healthy check was returned ( roughly t = 130ms ) Third check returns unhealthy ( t = 130ms counter = 2 ) TEST : health status should be unhealthy due to no success within grace period ( checking at roughly t = 130ms so there was a check that occurred within the grace period but no successful check within the grace period ) Wait until grace period has elapsed ( t = 230ms ) TEST : health status should be unhealthy due to no check within grace period ( checking at roughly t = 230ms so there is no check that occurred within the grace period )
// health check sends on this channel on its third run (after it has returned healthy and then error) // health check waits on this channel on its third run (after it has sent on doneChan) // return healthy state on first run // return error state on second run // on third run, send on doneChan and read from pauseChan // signal that health can be checked // pause until health check has occurred // return unhealthy // signal that health can be checked // pause (do not return until test has completed) // wait until health check has returned healthy and then unhealthy // health check should be healthy: even though health source returned error state most recently, it returned // healthy state within the grace period // health has been checked: wait for grace period to pass and then unpause the health routine // health check should be unhealthy: the most recent check ran within the grace period, but the last success was before grace period // wait for grace period // health check should be unhealthy: no check ran within grace period, and last known status was unhealthy