test(integration): testcontainers-based backend conformance suite (supersedes #294) - #348
Merged
Merged
Conversation
Adds a new test-only `testcontainers/` module that provisions real backend servers (minio, azurite, fake-gcs-server, atmoz/sftp, fauria/vsftpd) as disposable Docker containers and runs the shared backend/testsuite conformance and IO suites against them, plus a dedicated "Integration (testcontainers)" CI workflow. No credentials or manual setup required. Also fixes the conformance suite's special-character move assertion to compare File.Path() instead of File.URI() so sftp/ftp pass the same suite. Derived from the community contribution in #294 by Nathan Baulch, reworked and split into #346 (Azure/FTP bug fixes), #347 (conformance ConformanceOptions + EOF handling), and this module. Co-authored-by: Nathan Baulch <249604+NathanBaulch@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…olicy The module's go.mod declared `go 1.26`, which broke the CI matrix job running on Go 1.25 (VFS supports the latest Go minus one minor version). `go mod tidy` had resolved github.com/jlaffaye/ftp to the tagged v0.2.1 (which requires go 1.26) instead of the go-1.17 pseudo-version the core module pins. Pin jlaffaye/ftp to that same pseudo-version so the whole module builds on Go 1.25, and set the go directive to 1.25.11 to match the core and contrib modules. Co-authored-by: Cursor <cursoragent@cursor.com>
On GitHub-hosted runners ctr.Host() returns "localhost", which resolves to the
IPv6 loopback (::1) first. jlaffaye/ftp reuses the control-connection host for
the passive data connection (discarding the private PASV IP the server
advertises), so it dialed [::1]:21100. The passive ports are published on IPv4
only (0.0.0.0) via HostConfigModifier, so those data connections were refused
("dial tcp [::1]:21100: connect: connection refused").
Pin the control host to 127.0.0.1 (already used for PASV_ADDRESS) so the reused
data-connection host stays on IPv4 and matches the published passive ports.
Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new testcontainers/ test-only Go module that provisions real backend servers as disposable Docker containers and runs the shared backend/testsuite conformance + IO suites against them (no credentials/manual setup), and wires it into a dedicated GitHub Actions workflow. It also adjusts the conformance suite to use File.Path() (raw) instead of File.URI() (sometimes percent-encoded) for the special-character move assertion, improving cross-backend portability.
Changes:
- Introduces
testcontainers/integration test module (container provisioning + suite runner) and documentation. - Adds
Integration (testcontainers)workflow to run the new container-backed suite on PRs,main, and nightly. - Updates
backend/testsuitemove assertion to comparePath()rather thanURI()for special-character filenames.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
testcontainers/README.md |
Documents running the container-backed suite locally/CI and how to add new backends. |
testcontainers/integration_test.go |
Defines the testify suite that provisions targets once and runs conformance + IO suites. |
testcontainers/containers_test.go |
Implements per-backend container provisioning and backend registration (minio/azurite/fake-gcs-server/sftp/ftp + mem/os). |
testcontainers/doc.go |
Adds package-level godoc for the test-only module and attribution. |
testcontainers/go.mod |
Adds a dedicated module to isolate testcontainers dependencies from core VFS. |
testcontainers/go.sum |
Captures dependency sums for the new module. |
contrib/backend/README.md |
Notes the container-based pattern for contrib backends while keeping dependencies isolated per module. |
CHANGELOG.md |
Records the new module/workflow and the conformance-suite fix under Unreleased. |
backend/testsuite/io_conformance.go |
Updates explanatory comment about FTP IO limitations validation. |
backend/testsuite/conformance.go |
Switches special-character move assertions from URI() suffix checks to Path() suffix checks. |
.github/workflows/integration.yml |
Adds Linux-only workflow to run the testcontainers/ module suite. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- integration.yml: gate the Docker Hub login step on both DOCKERHUB_USERNAME
*and* DOCKERHUB_TOKEN being non-empty, so a half-configured secret set does
not run the login step and fail the workflow.
- backend/testsuite: reword the two special-character move-assertion messages
so they accurately describe what was checked. The move-back-to-source
assertion had inherited a copy-pasted "destination file ... source string"
message that mislabeled `newSrcSpaces` and the expected suffix; both messages
now describe the operation ("moved-to-destination" vs "moved-back-to-source")
and the expected suffix explicitly.
The third review comment (loop-variable capture in the errgroup.SetupSuite
goroutines) is a false positive under Go 1.22+ per-iteration loop scoping;
the testcontainers module pins `go 1.25.11`, so `i` and `reg` are correctly
captured per iteration and no code change is needed.
Co-authored-by: Cursor <cursoragent@cursor.com>
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new test-only
testcontainers/module that provisions real backend servers as disposable Docker containers and runs the sharedbackend/testsuiteconformance and IO suites against them — no credentials or manual setup required. A dedicated Integration (testcontainers) GitHub Actions workflow runs it on every PR and onmain.Backends exercised:
s3minio/minioazureazuritegsfake-gcs-serversftpatmoz/sftpftpfauria/vsftpdREVERSE_LOOKUP_ENABLE=NOto avoid a reverse-DNS login stallmem,osAlso fixes the conformance suite's special-character move assertion to compare
File.Path()(raw on every backend) instead ofFile.URI()(percent-encoded on sftp/ftp), so those backends pass the same suite without changing any backend's URI behavior.Attribution
This is derived from the community contribution in #294 ("Integration testing with Testcontainers") by @NathanBaulch. That proposal was reviewed, reworked, and split into three focused changes:
ConformanceOptions, IO EOF handling)Attribution is preserved in the commit (
Co-authored-by),testcontainers/doc.go,testcontainers/README.md, and the CHANGELOG entry. Supersedes #294, which will be closed with thanks.Testing
go test ./...(both modules) passes.golangci-lint runpasses (0 issues) in both modules.releasegen validatepasses.Made with Cursor