interna/middleware: synchronize instead of sleeping in TestSetAndLoadExperiments

Fixes #62530.

Change-Id: I06516921c170a606e9fe663b6cd8a248cd891a73
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/526173
TryBot-Result: Gopher Robot <gobot@golang.org>
Commit-Queue: Bryan Mills <bcmills@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
kokoro-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Auto-Submit: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
diff --git a/internal/middleware/experiment_test.go b/internal/middleware/experiment_test.go
index 81687ef..c88dc73 100644
--- a/internal/middleware/experiment_test.go
+++ b/internal/middleware/experiment_test.go
@@ -21,16 +21,26 @@
 )
 
 func TestSetAndLoadExperiments(t *testing.T) {
-	ctx := context.Background()
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
 	const testFeature = "test-feature"
+
 	var mu sync.Mutex
 	testExps := []*internal.Experiment{{Name: testFeature, Rollout: 100}}
-	testGetter := func(context.Context) ([]*internal.Experiment, error) {
+	getterStarted := make(chan bool, 1)
+	testGetter := func(ctx context.Context) ([]*internal.Experiment, error) {
+		select {
+		case <-ctx.Done():
+			return nil, ctx.Err()
+		case getterStarted <- true:
+		}
+
 		mu.Lock()
 		defer mu.Unlock()
 		return testExps, nil
 	}
-	experimenter, err := NewExperimenter(ctx, 10*time.Millisecond, testGetter, nil)
+	experimenter, err := NewExperimenter(ctx, 1*time.Millisecond, testGetter, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -69,7 +79,20 @@
 	mu.Lock()
 	testExps = []*internal.Experiment{{Name: testFeature, Rollout: 0}}
 	mu.Unlock()
-	time.Sleep(100 * time.Millisecond)
+
+	// Wait for the getter to run for the third time.
+	// The first run happened before NewExperimenter returned,
+	// and filled the channel buffer.
+	// The second run happens at some point after we clear the buffer here.
+	<-getterStarted
+	// When we receive again, we know the second run has started.
+	<-getterStarted
+	// However, we don't know for certain that the poller has posted the result
+	// of that run, *until* it has started the third run.
+	<-getterStarted
+	// Now we know that the second run — which happened after we stored to testExps —
+	// has completed, and its result should be visible.
+
 	makeRequest(t)
 	if featureIsOn {
 		t.Fatalf("experiment %q should not be active", testFeature)