Skip to content

test(integration): testcontainers-based backend conformance suite (supersedes #294) - #348

Merged
funkyshu merged 4 commits into
mainfrom
feature/testcontainers-integration
Jul 25, 2026
Merged

test(integration): testcontainers-based backend conformance suite (supersedes #294)#348
funkyshu merged 4 commits into
mainfrom
feature/testcontainers-integration

Conversation

@funkyshu

Copy link
Copy Markdown
Member

Summary

Adds a new test-only testcontainers/ module that provisions real backend servers as disposable Docker containers and runs the shared backend/testsuite conformance and IO suites against them — no credentials or manual setup required. A dedicated Integration (testcontainers) GitHub Actions workflow runs it on every PR and on main.

Backends exercised:

Scheme Image Notes
s3 minio/minio registered twice: SSE off and on
azure azurite
gs fake-gcs-server
sftp atmoz/sftp
ftp fauria/vsftpd REVERSE_LOOKUP_ENABLE=NO to avoid a reverse-DNS login stall
mem, os (none) run without a container

Also fixes the conformance suite's special-character move assertion to compare File.Path() (raw on every backend) instead of File.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:

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 run passes (0 issues) in both modules.
  • releasegen validate passes.
  • Full container suite run locally against Docker (conformance + IO for all backends).

Made with Cursor

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>
@c2fo-cibot c2fo-cibot Bot added the size/XXL Denotes a PR that changes 1000+ lines label Jul 23, 2026
funkyshu and others added 2 commits July 23, 2026 14:42
…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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/testsuite move assertion to compare Path() rather than URI() 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.

Comment thread testcontainers/integration_test.go
Comment thread .github/workflows/integration.yml Outdated
Comment thread backend/testsuite/conformance.go Outdated
- 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>
@funkyshu
funkyshu merged commit 16b9722 into main Jul 25, 2026
42 checks passed
@funkyshu
funkyshu deleted the feature/testcontainers-integration branch July 25, 2026 06:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XXL Denotes a PR that changes 1000+ lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants