test(inttest): de-flake the no-repeat pin guard
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m16s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m51s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m16s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m51s
The bag seed comes from crypto/rand, so an opening rack occasionally has no playable word — a legitimate engine answer that says nothing about the pin the test is guarding. Reproduced at roughly one run in three hundred locally, and it turned CI red once. Retry with fresh games instead: an unlucky draw no longer decides the result, while a genuinely broken path still fails every attempt.
This commit is contained in:
@@ -4,6 +4,7 @@ package inttest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -64,23 +65,38 @@ func TestNoRepeatWordsPinnedFromTheVariant(t *testing.T) {
|
|||||||
func TestNoRepeatWordsHonoursThePinNotTheVariant(t *testing.T) {
|
func TestNoRepeatWordsHonoursThePinNotTheVariant(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
svc := newGameService()
|
svc := newGameService()
|
||||||
g := createTwoSeatGame(t, svc, engine.VariantErudit)
|
|
||||||
|
|
||||||
if _, err := testDB.ExecContext(ctx,
|
// Each game draws from a bag seeded with crypto/rand, so an opening rack occasionally has no
|
||||||
`UPDATE backend.games SET no_repeat_words = false WHERE game_id = $1`, g.ID); err != nil {
|
// playable word at all. That is a legitimate engine answer which says nothing about the pin
|
||||||
t.Fatalf("clear the pin: %v", err)
|
// under test, and taking it for a failure made this test flake (~1 run in 300 on the committed
|
||||||
}
|
// dictionary, and more often on another one). Retry with fresh games instead: one unlucky draw
|
||||||
|
// no longer decides the result, while a genuinely broken path still fails every attempt.
|
||||||
|
const draws = 5
|
||||||
|
for attempt := 1; ; attempt++ {
|
||||||
|
g := createTwoSeatGame(t, svc, engine.VariantErudit)
|
||||||
|
if _, err := testDB.ExecContext(ctx,
|
||||||
|
`UPDATE backend.games SET no_repeat_words = false WHERE game_id = $1`, g.ID); err != nil {
|
||||||
|
t.Fatalf("clear the pin: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
reloaded, err := svc.GameByID(ctx, g.ID)
|
reloaded, err := svc.GameByID(ctx, g.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("get game: %v", err)
|
t.Fatalf("get game: %v", err)
|
||||||
}
|
}
|
||||||
if reloaded.NoRepeatWords {
|
if reloaded.NoRepeatWords {
|
||||||
t.Fatal("an Erudit game whose row has the rule off must report it off")
|
t.Fatal("an Erudit game whose row has the rule off must report it off")
|
||||||
}
|
}
|
||||||
// The rule reaches the engine from the row, so the reconstructed game plays unrestricted:
|
// The rule reaches the engine from the row, so the reconstructed game plays unrestricted:
|
||||||
// its generated moves are the solver's full list, none filtered away.
|
// its generated moves are the solver's full list, none filtered away.
|
||||||
if _, err := svc.Hint(ctx, reloaded.ID, reloaded.Seats[reloaded.ToMove].AccountID); err != nil {
|
_, err = svc.Hint(ctx, reloaded.ID, reloaded.Seats[reloaded.ToMove].AccountID)
|
||||||
t.Fatalf("hint on an unrestricted Erudit game: %v", err)
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !errors.Is(err, game.ErrNoHintAvailable) {
|
||||||
|
t.Fatalf("hint on an unrestricted Erudit game: %v", err)
|
||||||
|
}
|
||||||
|
if attempt == draws {
|
||||||
|
t.Fatalf("no opening rack in %d games had a playable move", draws)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user