core/internal/health/healthfile/observer_test.go

145 lines
2.8 KiB
Go

package healthfile_test
import (
"context"
"errors"
"path"
"sync"
"testing"
"time"
"gitea.dwysokinski.me/twhelp/corev3/internal/health"
"gitea.dwysokinski.me/twhelp/corev3/internal/health/healthfile"
"gitea.dwysokinski.me/twhelp/corev3/internal/health/healthtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLiveObserver(t *testing.T) {
t.Parallel()
testObserver(t, func(t *testing.T) *healthfile.Observer {
t.Helper()
h := health.New(
health.WithLiveCheck(healthtest.Checker{Nam: "test"}),
health.WithLiveCheck(healthtest.Checker{Nam: "test2"}),
)
dir := t.TempDir()
livePath := path.Join(dir, "live")
o := healthfile.LiveObserver(h, livePath)
t.Cleanup(func() {
_ = o.Close()
})
return o
})
}
func TestReadyObserver(t *testing.T) {
t.Parallel()
testObserver(t, func(t *testing.T) *healthfile.Observer {
t.Helper()
h := health.New(
health.WithReadyCheck(healthtest.Checker{Nam: "test"}),
health.WithReadyCheck(healthtest.Checker{Nam: "test2"}),
)
dir := t.TempDir()
readyPath := path.Join(dir, "ready")
o := healthfile.ReadyObserver(h, readyPath)
t.Cleanup(func() {
_ = o.Close()
})
return o
})
}
func testObserver(t *testing.T, newObserver func(t *testing.T) *healthfile.Observer) {
t.Helper()
t.Run("standard run/close path", func(t *testing.T) {
t.Parallel()
o := newObserver(t)
observerStopped := make(chan struct{})
go func() {
defer close(observerStopped)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
_ = o.Run(ctx)
}()
assert.EventuallyWithT(t, func(collect *assert.CollectT) {
assert.FileExists(collect, o.Path())
}, time.Second, 10*time.Millisecond)
require.NoError(t, o.Close())
select {
case <-observerStopped:
// OK
default:
assert.Fail(t, "Run goroutine not stopped")
}
})
t.Run("observer respects ctx.Done", func(t *testing.T) {
t.Parallel()
o := newObserver(t)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
require.ErrorIs(t, o.Run(ctx), context.DeadlineExceeded)
})
t.Run("run can only be called once", func(t *testing.T) {
t.Parallel()
expectedErrs := 2
o := newObserver(t)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
var wg sync.WaitGroup
errCh := make(chan error)
for i := 1; i <= 1+expectedErrs; i++ {
wg.Add(1)
go func() {
defer wg.Done()
errCh <- o.Run(ctx)
}()
}
go func() {
wg.Wait()
close(errCh)
}()
var cnt int
for err := range errCh {
if errors.Is(err, healthfile.ErrAlreadyRunning) {
cnt++
}
if cnt == expectedErrs {
require.NoError(t, o.Close())
}
}
assert.Equal(t, expectedErrs, cnt)
})
}