test(data): add Testcontainers integration tests for LeaderboardRepository#45
test(data): add Testcontainers integration tests for LeaderboardRepository#45yanmoyy wants to merge 9 commits intoBroderick-Westrope:mainfrom
Conversation
|
@yanmoyy this PR is increasing the Go version in |
|
Thanks, I will fix the version. |
|
@Broderick-Westrope While making this change, I noticed that I'd like your guidance on handling this, I'm considering two options:
I lean toward Option 1 for consistent integration testing, but I’m open to your preference based on the project’s goals. |
|
@yanmoyy thanks for raising this. It seems here that we should be able to run test containers in the workflow without further configuration. This page is for DotNet but I think the workflow requirements would be the same. Could you please push the other fixes and we will see if there is any issues with the workflow test containers. |
|
@Broderick-Westrope It seems like every tests on each OS failed because of no Docker. I checked the documentation, which says:
I will keep trying to figure this out. If you have any comments, please let me know. |
a0fa045 to
c836cc9
Compare
WalkthroughBumps Go toolchain to 1.24.x across CI and tooling, updates golangci-lint action/configs, adjusts dependencies in go.mod, introduces context-aware DB calls, adds a testcontainers-backed SQLite test suite and utility, refactors minor Tetris logic, and standardizes tests to assert.Equal. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Developer
participant TS as LeaderboardTestSuite
participant TU as CreateSQLiteContainer
participant TC as testcontainers
participant DB as SQLite (container)
participant Repo as Leaderboard Repository
Dev->>TS: go test
rect rgb(240,248,255)
note right of TS: Suite setup
TS->>TU: CreateSQLiteContainer(ctx)
TU->>TC: Start container (nouchka/sqlite3)
TC-->>TU: Container ready (log: "SQLite version")
TU-->>TS: {Container, DSN}
end
rect rgb(245,255,240)
note right of TS: Test: Save
TS->>Repo: Save(score) using DSN
Repo->>DB: ExecContext(INSERT)
DB-->>Repo: result (id)
Repo-->>TS: id
end
rect rgb(255,248,240)
note right of TS: Test: List
TS->>Repo: All(mode)
Repo->>DB: QueryContext(SELECT … ORDER BY score DESC, time ASC)
DB-->>Repo: rows
Repo-->>TS: []Score
end
TS->>TC: Terminate container (teardown)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/tetris/matrix_test.go (1)
37-39: Swapassert.EqualErrorargs.Current call compares
tc.wantErrtoerr.Error(); pass the actual error first.-assert.EqualError(t, tc.wantErr, err.Error()) +assert.EqualError(t, err, tc.wantErr.Error())
🧹 Nitpick comments (13)
pkg/tetris/modes/single/single.go (1)
295-296: Idiomatic loop; consider a brief comment to clarify the empty bodySwitch to condition-based loop is a clean, idiomatic improvement. To appease linters and future readers, add a short comment inside the empty body.
- for g.ghostTet.MoveDown(g.matrix) { - } + for g.ghostTet.MoveDown(g.matrix) { + // keep dropping ghost until blocked + }.github/workflows/release.yaml (2)
23-23: Go 1.24.x bump in release pipeline looks goodConsider enabling module cache to speed releases: add with.cache: true and cache-dependency-path: '**/go.sum' to actions/setup-go.
- - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: 1.24.x + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.24.x + cache: true + cache-dependency-path: '**/go.sum'
29-31: Verify secret name for GoReleaserEnsure secrets.GH_PAT exists; otherwise prefer the built-in GITHUB_TOKEN which already has contents: write in this job.
- env: - GITHUB_TOKEN: ${{secrets.GH_PAT}} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}internal/data/data.go (1)
4-4: Avoid context.TODO in production pathsPrefer Background (or a timeout) over TODO for table creation.
- _, err := db.ExecContext( - context.TODO(), + _, err := db.ExecContext( + context.Background(), `CREATE TABLE IF NOT EXISTS leaderboard (id INTEGER PRIMARY KEY, game_mode TEXT, name TEXT, time INTEGER, score INTEGER, lines INTEGER, level INTEGER)`, )Optionally thread a ctx into EnsureTablesExist and NewDB to allow caller‑controlled timeouts.
Also applies to: 27-31
pkg/tetris/matrix_test.go (1)
223-224: Fix misleading subtest names.Case names say “true/false; left/right” but expected values are opposite for the right-boundary cases, which is confusing in CI output.
Apply:
- "true; right": { + "false; right (col 9 in-bounds)": { 9, false, }, - "false; right": { + "true; right (col 10 out-of-bounds)": { 10, true, },Also applies to: 200-216
.golangci.yaml (1)
1-1: Config looks consistent with v2; watch for redundant complexity linters.Enabling both
cyclopandgocyclocan yield duplicate findings; consider keeping one.Also applies to: 3-3, 68-154, 181-192
internal/data/leaderboard.go (2)
54-57: Same for INSERT: switch to?placeholders.Keeps driver-agnostic and avoids subtle binding issues.
-res, err := r.db.ExecContext(context.TODO(), - "INSERT INTO leaderboard (game_mode, name, time, score, lines, level) VALUES ($1, $2, $3, $4, $5, $6)", - score.GameMode, score.Name, score.Time, score.Score, score.Lines, score.Level, -) +res, err := r.db.ExecContext(context.Background(), + "INSERT INTO leaderboard (game_mode, name, time, score, lines, level) VALUES (?, ?, ?, ?, ?, ?)", + score.GameMode, score.Name, score.Time, score.Score, score.Lines, score.Level, +)Also applies to: 61-66
28-31: Propagate context from callers (follow-up).Prefer method signatures
All(ctx context.Context, gameMode string)andSave(ctx context.Context, score *Score)instead ofcontext.TODO().I can draft the repo-wide refactor if you want it in this PR or a follow-up.
Also applies to: 54-57
.github/workflows/lint.yaml (1)
12-12: CI note re Testcontainers across OSes.Docker isn’t available on GitHub macOS/Windows runners. Run integration tests only on
ubuntu-latestor guard withif: runner.os == 'Linux'.internal/data/testutils/container.go (1)
22-25: Flakiness risk: startup timeout too low.Even if you keep this, 5s is tight on CI pulls; bump to ≥60s.
internal/data/leaderboard_test.go (2)
36-45: TearDown should notlog.Fatalf; also don’t depend on container.Prefer
suite.Require().NoErrorand remove container termination if you drop it.-err := suite.repo.db.Close() -if err != nil { - log.Fatalf("error closing db: %s", err) -} -err = suite.container.Terminate(suite.ctx) -if err != nil { - log.Fatalf("error terminating SQLite container: %s", err) -} +suite.Require().NoError(suite.repo.db.Close())
98-115: Add assertions for Rank and game-mode filtering; test tie-breakers.You already verify order; also assert
Rankfields and add a case where scores tie and times decide.I can extend the suite with these cases if you want.
.golangci.bck.yaml (1)
1-8: Consider removing backup config from repo root.Keeping both
.golangci.yamland.golangci.bck.yamlmay confuse contributors; store backups outside the repo or as a Gist.Also applies to: 182-255
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (17)
.github/workflows/lint.yaml(1 hunks).github/workflows/release.yaml(1 hunks).github/workflows/test.yaml(1 hunks).golangci.bck.yaml(1 hunks).golangci.yaml(1 hunks)Taskfile.yaml(1 hunks)go.mod(2 hunks)internal/data/data.go(2 hunks)internal/data/leaderboard.go(3 hunks)internal/data/leaderboard_test.go(1 hunks)internal/data/testutils/container.go(1 hunks)internal/tui/views/single_test.go(1 hunks)pkg/tetris/matrix.go(2 hunks)pkg/tetris/matrix_test.go(4 hunks)pkg/tetris/modes/single/single.go(1 hunks)pkg/tetris/next_queue_test.go(1 hunks)pkg/tetris/tetrimino_test.go(9 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
internal/data/leaderboard_test.go (3)
internal/data/testutils/container.go (2)
SQLiteContainer(13-16)CreateSQLiteContainer(19-38)internal/data/leaderboard.go (3)
LeaderboardRepository(20-22)NewLeaderboardRepository(24-26)Score(9-18)internal/data/data.go (1)
NewDB(11-23)
internal/data/testutils/container.go (1)
internal/tui/testutils/testutils.go (1)
SetupInMemoryDB(34-41)
internal/tui/views/single_test.go (1)
internal/data/leaderboard.go (1)
Score(9-18)
🔇 Additional comments (13)
pkg/tetris/modes/single/single.go (1)
3-8: CI/toolchain aligned — Go 1.24 and Docker present for Testcontainers
go.mod declares go 1.24.0; .github workflows use actions/setup-go with go-version 1.24.x; the test workflow verifies Docker and sets up Docker on macOS; testcontainers-go v0.39.0 is required and math/rand/v2 is used in code and tests.pkg/tetris/matrix.go (1)
6-6: Simpler line-complete check using slices.ContainsFuncChange is correct and preserves semantics (ghost cells still count as empty). Nice cleanup.
Also applies to: 60-61
pkg/tetris/next_queue_test.go (1)
75-76: Tightening assertions to EqualGood switch from EqualValues to Equal for stricter type checks.
Also applies to: 82-83
pkg/tetris/tetrimino_test.go (1)
75-75: Consistent move to assert.Equal across testsLGTM. Improves type strictness without changing behavior.
Also applies to: 164-164, 252-252, 396-396, 1117-1117, 1917-1918, 3404-3405, 3545-3545, 3651-3653, 3664-3666
internal/tui/views/single_test.go (1)
238-247: Stricter struct equality in leaderboard handoffEqual over EqualValues is appropriate here. 👍
Taskfile.yaml (1)
4-4: GOLANG_CROSS_VERSION updated to v1.24LGTM; automated sandbox search couldn't confirm absence of 1.23 references (ripgrep reported "No files were searched"). Confirm there are no remaining "1.23", "go1.23", or "v1.23" occurrences across the repo by running locally: git grep -nE '(\b1.23\b|go1.23|v1.23)' || rg -nP '(\b1.23\b|go1.23|v1.23)'.
pkg/tetris/matrix_test.go (3)
194-195: LGTM on equality change.Switch to
assert.Equalis correct for matrix structural equality.
380-381: LGTM on equality change.
assert.Equalhere verifies full matrix state post-mutation.
456-457: LGTM on equality change.Keeps removal semantics strict.
.github/workflows/lint.yaml (1)
17-17: LGTM; matches prior guidance on versions.Go 1.24.x and golangci-lint action v8/v2.1.0 look right.
Also applies to: 23-26
.golangci.yaml (1)
184-192: Don't use a top-levelformatters.goimports— useformatters.enable+formatters.settings(golangci-lint v2).golangci-lint v2 (including v2.1.0) rejects a top-level
formatters.goimports; enable formatters viaformatters.enableand put formatter options underformatters.settings.Likely an incorrect or invalid review comment.
go.mod (1)
16-18: Verify ecosystem upgrade impact (testcontainers + testify)
- Good adds.
- go.mod declares go 1.24.0 and workflows (.github/workflows/lint.yaml, release.yaml, test.yaml) target Go 1.24.x; no Dockerfiles reference older golang.
- No module-caching steps detected in workflows — add/update actions/cache or use setup-go's cache input to cache Go modules and speed CI.
internal/data/leaderboard.go (1)
41-44: leaderboard.time: schema is INTEGER — ensure scan/insert units matchinternal/data/data.go creates leaderboard.time as INTEGER; scanning into time.Duration is safe only if inserts store an integer nanosecond count. Actionable options:
- If inserts write d.Nanoseconds() (int64) — keep scanning but prefer scanning into an int64 and converting: var ns int64; rows.Scan(..., &ns, ...); s.Time = time.Duration(ns).
- If inserts store milliseconds or TEXT — change read/write accordingly (use milliseconds→time.Duration(ms)*time.Millisecond or scan to string then parse).
Locations: internal/data/data.go (CREATE TABLE), internal/data/leaderboard.go (rows.Scan).
|
I apologize for the numerous trial commits on this branch. I was trying to set up Docker on a macOS runner in GitHub Actions. The last commit uses the best solution I found: douglascamata/setup-docker-macos-action@v1.0.0. However, the macOS-latest runner does not seem to support Docker due to I'm unsure of the best approach, but I’ve considered two options:
I believe both options are valid. If you have feedback or prefer one approach, please let me know, and I’ll finalize the workflow after locally testing the GitHub Action with act. |
|
No need for an apology; a pull request is a place you can experiment with the changes you'd like to propose. I'd like to keep the tests running for each OS so that we can ensure there are no differences (as I've found once or twice during this project). With this in mind, I think the easiest way to do what we want to do would be with an environment variable that skips tests which rely on test containers. Two things to note for these new tests:
|
7f93106 to
408a31e
Compare
408a31e to
2df1734
Compare
|
Same problem happens like before (#48). I think we need to fix this issue before we merge this branch. |
6bc2865 to
4b8ee5e
Compare
- add reuse option to testcontainers
a257db3 to
a6d5a10
Compare
5453b4b to
d8bb26c
Compare
|
I've extended the I experimented with the windows-2025 runner, which uses WSL2, as After further investigation, it seems Windows runners on GitHub Actions may not fully support Linux containers, possibly due to default Windows container support (as noted on the Testcontainers website and StackOverflow question). As a result, I updated the workflow to set Additionally, I added timeouts to the tests in I’m unsure if this is the optimal solution, but I believe limiting Testcontainers to Linux environments (e.g., |
4150f84 to
d166681
Compare
d166681 to
b723ae9
Compare
Description:
This PR introduces Testcontainers integration tests for the
LeaderboardRepositoryusing an in-memory SQLite container, addressing #30. The tests cover:TestSaveScore: Verifies that a score is saved with a valid ID.TestAllScores: Tests retrieving and sorting multiple marathon scores by score DESC, time ASC.The implementation is inspired by the structure outlined in the Testcontainers for Go getting started guide.
Please let me know if this aligns with your testing vision or if there are specific edge cases you’d like to see added.
Summary by CodeRabbit