//go:build race
// +build race

package reloader

import (
	"context"
	"net/http"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestAtomicHandlerRaces(t *testing.T) {
	type testHandler struct{ http.Handler }

	hrFn := func() http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
	}

	const count = 8
	hrFuncMap := make(map[http.Handler]struct{}, count)
	for i := 0; i < count; i++ {
		hrFuncMap[&testHandler{hrFn()}] = struct{}{}
	}

	hr := NewAtomicHandler(nil)
	assert.NotNil(t, hr)

	var wg sync.WaitGroup
	defer wg.Wait()

	ctx, cancel := context.WithTimeout(context.Background(), time.Second/4)
	defer cancel()

	// We create 8 goroutines reading & writing to the handler concurrently. If
	// a race condition occurs the test will fail and halt.
	for i := 0; i < count; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			for hrFunc := range hrFuncMap {
				select {
				case <-ctx.Done():
				default:
				}

				hr.Store(hrFunc)

				got := hr.load()
				_, ok := hrFuncMap[got]
				if !ok {
					// This will trigger a race failure / exit test
					t.Fatal("unknown handler returned from load()")
					return
				}
			}
		}()
	}
	wg.Wait()
}
