Skip to content

Conversation

@chatton
Copy link
Collaborator

@chatton chatton commented Oct 23, 2025

Overview

Volumes were still not being cleaned up after tests, I found that this was due to prune explicitly not working on volumes that were created with the docker client, even if there was no associated container (this is by design)

This PR should also address the issue of resources not being correctly deleted when created in subtests (due to issues with t.Name() ), this is achieved by adding in a label upon client creation, and then using that label when that client instance creates or removes resources.

Method signatures needed to be updated to take an interface rather than the concrete type.

Summary by CodeRabbit

  • Refactor
    • Replaced direct Docker usage with a unified Docker client abstraction across the framework.
    • Streamlined setup/cleanup flow to use per-run cleanup labels and improved resource pruning.
    • Test suites updated to use the new client and setup flow, improving cleanup reliability and log handling.
    • Renamed the environment variable controlling failure cleanup to a new project-specific name.

@coderabbitai
Copy link

coderabbitai bot commented Oct 23, 2025

Walkthrough

Replaces direct Moby Docker client usage with a new types.TastoraDockerClient interface and adds a concrete wrapper framework/docker/client.Client that stores a per-run cleanup label. Updates signatures, structs, tests, and cleanup/prune flows to accept and use the new client and its CleanupLabel().

Changes

Cohort / File(s) Summary
New interface & wrapper
framework/types/docker_client.go, framework/docker/client/client.go
Add types.TastoraDockerClient interface (embeds Docker CommonAPIClient + CleanupLabel()) and a concrete tastoraclient.Client wrapper with NewClient and CleanupLabel().
Global setup & cleanup
framework/docker/setup.go, framework/docker/docker_test.go, framework/docker/setup_test.go
Replace DockerSetup → Setup returning types.TastoraDockerClient; introduce SetupTestingT, Cleanup/CleanupWithLabel; prune logic now filters by cleanup label and enumerates/removes volumes.
Container lifecycle & runtime
framework/docker/container/image.go, framework/docker/container/job.go, framework/docker/container/lifecycle.go, framework/docker/container/node.go
Swap *client.Client fields/params to types.TastoraDockerClient; derive labels via client.CleanupLabel(); remove explicit testName parameter for volume removal.
Builders & configs
framework/docker/cosmos/*, framework/docker/evstack/*, framework/docker/dataavailability/*, framework/docker/evstack/evmsingle/*, framework/docker/evstack/reth/*
Replace Docker client fields and WithDockerClient signatures to accept types.TastoraDockerClient; update imports.
File helpers & volume utilities
framework/docker/file/*, framework/docker/volume/owner.go, framework/testutil/docker/toml.go, framework/docker/toml.go
Writer/Retriever/owner and toml helpers accept types.TastoraDockerClient; use CleanupLabel() for container labels and cleanup filtering.
Internal utilities
framework/docker/internal/* (busybox, network, startcontainer, docker_keyring.go, keyring.go)
Internal functions and constructors updated to accept types.TastoraDockerClient; call sites adjusted to use embedded CommonAPIClient methods and CleanupLabel().
Tests updated to wrap client
framework/docker/internal/docker_keyring_test.go, framework/docker/chain_node_test.go, framework/docker/file/*_test.go, framework/docker/ibc_test.go, framework/docker/ibc_transfer_test.go, framework/docker/container/..._test.go
Tests now call docker.Setup(t) and wrap raw moby client with tastoraclient.NewClient(...) where needed; removed some per-test cleanup registrations.
IB C / relayer
framework/docker/ibc/relayer/hermes.go
NewHermes and related functions now accept types.TastoraDockerClient.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Code
    participant Setup as Setup()
    participant Wrapper as tastoraclient.Client
    participant SDK as Docker SDK (moby client)

    Test->>Setup: Setup(t) -> (client, cleanupLabel)
    Setup->>SDK: create raw Docker client
    Setup->>Wrapper: NewClient(rawClient, cleanupLabel)
    Setup-->>Test: return Wrapper (TastoraDockerClient)

    Test->>Wrapper: Create/Start/Inspect containers
    Wrapper->>SDK: delegated CommonAPIClient calls

    Note right of Wrapper: Wrapper exposes CleanupLabel()
    Test->>Wrapper: request Cleanup()
    Wrapper-->>Test: CleanupLabel
    Test->>SDK: list & remove volumes/networks filtered by label
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • setup/prune logic changes in framework/docker/setup.go (enumeration & per-volume removal).
    • lifecycle and RemoveVolumes signature changes across container/*.
    • public API surface changes where structs/fields now expose types.TastoraDockerClient.

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • mojtaba-esk
  • tty47

Poem

🐰 I hopped in with a tiny wrapper bright,
A label for cleanup to keep things light.
Containers start, volumes neatly pruned,
Tests run tidy, no mess left strewn.
🥕 Hooray — neat client, snug and right!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.70% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'chore: add labeled client and update volume cleanup' accurately summarizes the main changes: introducing a labeled client wrapper and updating volume cleanup logic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cian/ensure-proper-volume-cleanup

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60e3f53 and 935a2e8.

📒 Files selected for processing (6)
  • framework/docker/docker_test.go (2 hunks)
  • framework/docker/file/file_retriever_test.go (2 hunks)
  • framework/docker/file/file_writer_test.go (2 hunks)
  • framework/docker/ibc_transfer_test.go (1 hunks)
  • framework/docker/setup.go (6 hunks)
  • framework/docker/setup_test.go (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • framework/docker/ibc_transfer_test.go
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: chatton
Repo: celestiaorg/tastora PR: 106
File: framework/docker/dataavailability/config.go:3-7
Timestamp: 2025-08-27T08:24:51.731Z
Learning: The tastora codebase consistently uses `github.com/moby/moby/client` for Docker client imports throughout all framework/docker packages. Do not suggest changing this to `github.com/docker/docker/client` as it would break type compatibility.
Learnt from: chatton
Repo: celestiaorg/tastora PR: 106
File: framework/docker/dataavailability/node.go:259-268
Timestamp: 2025-08-27T08:29:14.500Z
Learning: The user chatton prefers to keep existing logic unchanged during refactors, even when there are potential improvements, to maintain focus on the structural changes and avoid introducing bugs during code movement.
📚 Learning: 2025-08-27T08:24:51.731Z
Learnt from: chatton
Repo: celestiaorg/tastora PR: 106
File: framework/docker/dataavailability/config.go:3-7
Timestamp: 2025-08-27T08:24:51.731Z
Learning: The tastora codebase consistently uses `github.com/moby/moby/client` for Docker client imports throughout all framework/docker packages. Do not suggest changing this to `github.com/docker/docker/client` as it would break type compatibility.

Applied to files:

  • framework/docker/docker_test.go
  • framework/docker/file/file_writer_test.go
  • framework/docker/file/file_retriever_test.go
  • framework/docker/setup.go
📚 Learning: 2025-08-07T13:30:18.395Z
Learnt from: CR
Repo: celestiaorg/tastora PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-07T13:30:18.395Z
Learning: Applies to framework/testutil/**/*.go : Functions in `framework/testutil` should depend on small interfaces defined in the same package to avoid dependency cycles.

Applied to files:

  • framework/docker/docker_test.go
  • framework/docker/file/file_writer_test.go
  • framework/docker/setup_test.go
📚 Learning: 2025-08-27T08:33:47.114Z
Learnt from: chatton
Repo: celestiaorg/tastora PR: 106
File: framework/testutil/wait/wait.go:6-6
Timestamp: 2025-08-27T08:33:47.114Z
Learning: In framework/testutil/wait/wait.go, the maintainer (chatton) has decided to keep the direct dependency on the concrete dataavailability package (da "github.com/celestiaorg/tastora/framework/docker/dataavailability") rather than using interfaces, acknowledging it's not ideal but acceptable for now with the plan to introduce a small interface later if needed.

Applied to files:

  • framework/docker/docker_test.go
🧬 Code graph analysis (4)
framework/docker/docker_test.go (4)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/setup.go (1)
  • Setup (50-74)
framework/docker/upgrade_version_test.go (1)
  • TestUpgradeVersion (11-46)
framework/docker/dataavailability/network_builder.go (1)
  • t (15-38)
framework/docker/file/file_writer_test.go (1)
framework/docker/setup.go (1)
  • Setup (50-74)
framework/docker/file/file_retriever_test.go (1)
framework/docker/setup.go (1)
  • Setup (50-74)
framework/docker/setup.go (4)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/testutil/random/random.go (1)
  • LowerCaseLetterString (10-16)
framework/docker/client/client.go (1)
  • NewClient (22-27)
framework/docker/consts/consts.go (2)
  • CelestiaDockerPrefix (4-4)
  • CleanupLabel (6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: Analyze (go)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatton chatton marked this pull request as ready for review October 23, 2025 15:12
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
framework/docker/container/lifecycle.go (1)

45-58: Go compilation will fail: unused parameter testName must be discarded or removed

The parameter testName is unused in the function body (verified: declared at line 47, referenced nowhere else). Go forbids unused parameters. The proposed fix to discard it with blank identifier _ is correct and maintains signature stability while fixing the compilation error. Multiple call sites currently pass this parameter.

 func (c *Lifecycle) CreateContainer(
 	ctx context.Context,
-	testName string,
+	_ string,
 	networkID string,
 	image Image,

Alternatively, if removing it entirely is preferred, update call sites at:

  • framework/docker/dataavailability/node.go:283
  • framework/docker/ibc/relayer/hermes.go:88
  • framework/docker/evstack/reth/node.go:236
  • framework/docker/cosmos/node.go:464
  • framework/docker/evstack/evmsingle/node.go:189
  • framework/docker/evstack/node.go:159
  • framework/docker/container/node.go:140
🧹 Nitpick comments (12)
framework/docker/evstack/reth/builder.go (1)

93-105: Guard against a nil Docker client in Build

Add a fast-fail to avoid later NPEs when callers forget WithDockerClient.

Apply:

@@
 import (
   "context"
+  "errors"
   "github.com/celestiaorg/tastora/framework/types"
   "testing"
@@
 func (b *NodeBuilder) Build(ctx context.Context) (*Node, error) {
+  if b.dockerClient == nil {
+    return nil, errors.New("docker client is required; call WithDockerClient")
+  }
   cfg := Config{
framework/docker/container/node.go (1)

193-207: Differentiate “not found” from real errors in ensureVolume

Treating any inspect error as “volume missing” can mask daemon/permission/network issues. Use errdefs.IsNotFound to branch.

Apply:

@@
-import (
+import (
   "context"
   "fmt"
   "github.com/celestiaorg/tastora/framework/docker/internal"
@@
   "github.com/celestiaorg/tastora/framework/types"
   "github.com/docker/docker/api/types/mount"
   volumetypes "github.com/docker/docker/api/types/volume"
+  "github.com/docker/docker/errdefs"
   "github.com/docker/go-connections/nat"
   "go.uber.org/zap"
 )
@@
-  _, err := n.DockerClient.VolumeInspect(ctx, volName)
-  if err != nil {
-    // volume doesn't exist, create it
+  _, err := n.DockerClient.VolumeInspect(ctx, volName)
+  if err != nil {
+    if !errdefs.IsNotFound(err) {
+      return fmt.Errorf("inspecting volume %q: %w", volName, err)
+    }
+    // volume doesn't exist, create it
     v, createErr := n.DockerClient.VolumeCreate(ctx, volumetypes.CreateOptions{
       Name: volName,
       Labels: map[string]string{
         consts.CleanupLabel:   n.DockerClient.CleanupLabel(),
         consts.NodeOwnerLabel: nodeName,
       },
     })

Also applies to: 3-16

framework/docker/internal/docker_keyring_test.go (2)

39-40: Close the client in teardown

Release HTTP connections/resources after the suite.

Apply:

 func (s *DockerKeyringTestSuite) TearDownSuite() {
   if s.containerID != "" {
     ctx := context.Background()
     _ = s.dockerClient.ContainerStop(ctx, s.containerID, container.StopOptions{})
     _ = s.dockerClient.ContainerRemove(ctx, s.containerID, container.RemoveOptions{})
   }
+  if s.dockerClient != nil {
+    _ = s.dockerClient.Close()
+  }
 }

Also applies to: 87-93


70-72: Typo: “wet up” → “set up”

Fix the comment wording.

Apply:

-  // wet up keyring directory in container
+  // set up keyring directory in container
framework/docker/file/file_retriever.go (1)

42-59: Verify bind-mount visibility without starting the helper container

Some Docker setups only apply binds after start; CopyFromContainer may fail to see volume contents if the container never starts.

Please confirm CI/runtime behavior. If flaky, options:

  • Start the container before copy, then remove:
    • ContainerStart → CopyFromContainer → ContainerRemove.
  • Or switch to HostConfig.Mounts with mount.TypeVolume.

Also applies to: 50-53

framework/docker/client/client.go (1)

13-17: Consider tiny helpers to reduce label boilerplate

A helper for common label/filter usage would cut repetition and mistakes at call sites.

// In this package:
func (c *Client) LabelsMap(key string) map[string]string {
	return map[string]string{key: c.cleanupLabel}
}

Usage: Labels: dockerClient.LabelsMap(consts.CleanupLabel).

Also applies to: 29-32

framework/docker/container/lifecycle.go (3)

37-43: Param naming nit

Rename c to cli to avoid confusion with the method receiver c *Lifecycle elsewhere.


214-225: Stop should also ignore NotFound

For parity with other call sites and cleanup flows, treat “not found” like “already stopped.”

-err := c.client.ContainerStop(ctx, c.id, timeout)
-if err != nil && errdefs.IsNotModified(err) {
+err := c.client.ContainerStop(ctx, c.id, timeout)
+if err != nil && (errdefs.IsNotModified(err) || errdefs.IsNotFound(err)) {
 	// container is already stopped, this is not an error
 	return nil
}

172-175: Prefer structured logging over fmt.Printf

Use c.log to emit the panic details instead of printing to stdout.

-		fmt.Printf("\nContainer name: %s.\nerror: %s.\nlogs\n%s\n", c.containerName, err.Error(), logs.String())
+		c.log.Error("Container failed to start",
+			zap.String("container", c.containerName),
+			zap.Error(err),
+			zap.String("logs", logs.String()),
+		)
framework/docker/container/job.go (1)

215-221: Minor log key typo

zap.Strings("env,", opts.Env) likely meant "env". Harmless but noisy in logs.

-			zap.Strings("env,", opts.Env),
+			zap.Strings("env", opts.Env),
framework/docker/setup.go (2)

158-186: Avoid double-counting reclaimed space across retries

spaceReclaimed is incremented before deletion and outside the retry closure. If a conflict retries, the same volume’s size can be counted multiple times. Increment only on successful removal.

-			for _, vol := range volumeList.Volumes {
-				// try to get volume size before removal
-				if vol.UsageData != nil {
-					spaceReclaimed += uint64(vol.UsageData.Size)
-				}
-
-				err := cli.VolumeRemove(ctx, vol.Name, true)
+			for _, vol := range volumeList.Volumes {
+				err := cli.VolumeRemove(ctx, vol.Name, true)
 				if err != nil {
 					if errdefs.IsConflict(err) {
 						return err
 					}
 					// Log but continue with other volumes
 					t.Logf("Failed to remove volume %s: %v", vol.Name, err)
 				} else {
 					deletedCount++
+					if vol.UsageData != nil {
+						spaceReclaimed += uint64(vol.UsageData.Size)
+					}
 				}
 			}

Also applies to: 198-201


271-279: Optional: demux logs for readability

ContainerLogs returns a multiplexed stream when both stdio are requested. Consider using stdcopy.StdCopy (as in job.Wait) so logs are readable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b36fe77 and 0152e65.

📒 Files selected for processing (34)
  • framework/docker/chain_node_test.go (2 hunks)
  • framework/docker/client/client.go (1 hunks)
  • framework/docker/container/image.go (3 hunks)
  • framework/docker/container/job.go (4 hunks)
  • framework/docker/container/lifecycle.go (3 hunks)
  • framework/docker/container/node.go (4 hunks)
  • framework/docker/cosmos/chain_builder.go (2 hunks)
  • framework/docker/cosmos/chain_config.go (1 hunks)
  • framework/docker/cosmos/node.go (1 hunks)
  • framework/docker/dataavailability/config.go (2 hunks)
  • framework/docker/dataavailability/network_builder.go (3 hunks)
  • framework/docker/docker_test.go (1 hunks)
  • framework/docker/evstack/chain_builder.go (3 hunks)
  • framework/docker/evstack/config.go (2 hunks)
  • framework/docker/evstack/evmsingle/builder.go (3 hunks)
  • framework/docker/evstack/evmsingle/config.go (1 hunks)
  • framework/docker/evstack/reth/builder.go (3 hunks)
  • framework/docker/evstack/reth/config.go (1 hunks)
  • framework/docker/file/file_retriever.go (2 hunks)
  • framework/docker/file/file_writer.go (2 hunks)
  • framework/docker/ibc/relayer/hermes.go (1 hunks)
  • framework/docker/ibc_test.go (2 hunks)
  • framework/docker/ibc_transfer_test.go (0 hunks)
  • framework/docker/internal/busybox.go (2 hunks)
  • framework/docker/internal/docker_keyring.go (3 hunks)
  • framework/docker/internal/docker_keyring_test.go (3 hunks)
  • framework/docker/internal/keyring.go (2 hunks)
  • framework/docker/internal/network.go (1 hunks)
  • framework/docker/internal/startcontainer.go (2 hunks)
  • framework/docker/setup.go (5 hunks)
  • framework/docker/toml.go (1 hunks)
  • framework/docker/volume/owner.go (3 hunks)
  • framework/testutil/docker/toml.go (2 hunks)
  • framework/types/docker_client.go (1 hunks)
💤 Files with no reviewable changes (1)
  • framework/docker/ibc_transfer_test.go
🧰 Additional context used
📓 Path-based instructions (1)
framework/testutil/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Functions in framework/testutil should depend on small interfaces defined in the same package to avoid dependency cycles.

Files:

  • framework/testutil/docker/toml.go
🧠 Learnings (3)
📓 Common learnings
Learnt from: chatton
PR: celestiaorg/tastora#106
File: framework/docker/dataavailability/config.go:3-7
Timestamp: 2025-08-27T08:24:51.731Z
Learning: The tastora codebase consistently uses `github.com/moby/moby/client` for Docker client imports throughout all framework/docker packages. Do not suggest changing this to `github.com/docker/docker/client` as it would break type compatibility.
📚 Learning: 2025-08-27T08:24:51.731Z
Learnt from: chatton
PR: celestiaorg/tastora#106
File: framework/docker/dataavailability/config.go:3-7
Timestamp: 2025-08-27T08:24:51.731Z
Learning: The tastora codebase consistently uses `github.com/moby/moby/client` for Docker client imports throughout all framework/docker packages. Do not suggest changing this to `github.com/docker/docker/client` as it would break type compatibility.

Applied to files:

  • framework/docker/cosmos/node.go
  • framework/types/docker_client.go
  • framework/docker/cosmos/chain_config.go
  • framework/docker/internal/keyring.go
  • framework/docker/evstack/evmsingle/config.go
  • framework/docker/evstack/chain_builder.go
  • framework/docker/internal/startcontainer.go
  • framework/docker/docker_test.go
  • framework/docker/container/node.go
  • framework/docker/chain_node_test.go
  • framework/docker/evstack/config.go
  • framework/docker/dataavailability/network_builder.go
  • framework/docker/evstack/evmsingle/builder.go
  • framework/docker/toml.go
  • framework/docker/setup.go
  • framework/docker/client/client.go
  • framework/docker/container/image.go
  • framework/docker/evstack/reth/builder.go
  • framework/testutil/docker/toml.go
  • framework/docker/internal/docker_keyring_test.go
  • framework/docker/cosmos/chain_builder.go
  • framework/docker/internal/busybox.go
  • framework/docker/file/file_writer.go
  • framework/docker/ibc_test.go
  • framework/docker/container/lifecycle.go
  • framework/docker/volume/owner.go
  • framework/docker/file/file_retriever.go
  • framework/docker/internal/docker_keyring.go
  • framework/docker/evstack/reth/config.go
  • framework/docker/dataavailability/config.go
  • framework/docker/container/job.go
  • framework/docker/internal/network.go
📚 Learning: 2025-08-07T13:30:18.395Z
Learnt from: CR
PR: celestiaorg/tastora#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-07T13:30:18.395Z
Learning: Applies to framework/testutil/**/*.go : Functions in `framework/testutil` should depend on small interfaces defined in the same package to avoid dependency cycles.

Applied to files:

  • framework/docker/docker_test.go
🧬 Code graph analysis (33)
framework/docker/cosmos/node.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/types/docker_client.go (1)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/cosmos/chain_config.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/internal/keyring.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/evstack/evmsingle/config.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/evstack/chain_builder.go (3)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/cosmos/chain_builder.go (1)
  • ChainBuilder (109-157)
framework/docker/evstack/evmsingle/builder.go (1)
  • ChainBuilder (14-24)
framework/docker/internal/startcontainer.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/docker_test.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/container/node.go (2)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/chain_node_test.go (2)
framework/docker/cosmos/node.go (2)
  • NewChainNode (115-150)
  • ChainNodeParams (93-112)
framework/docker/client/client.go (1)
  • Client (14-17)
framework/docker/evstack/config.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/dataavailability/network_builder.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/evstack/evmsingle/builder.go (3)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/cosmos/chain_builder.go (1)
  • ChainBuilder (109-157)
framework/docker/evstack/chain_builder.go (1)
  • ChainBuilder (15-40)
framework/docker/toml.go (2)
framework/testutil/docker/toml.go (1)
  • ModifyConfigFile (16-51)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/setup.go (4)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/testutil/random/random.go (1)
  • LowerCaseLetterString (10-16)
framework/docker/client/client.go (1)
  • NewClient (22-27)
framework/docker/consts/consts.go (2)
  • CelestiaDockerPrefix (4-4)
  • CleanupLabel (6-6)
framework/docker/client/client.go (2)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/container/image.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/evstack/reth/builder.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/ibc/relayer/hermes.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/testutil/docker/toml.go (2)
framework/docker/toml.go (1)
  • ModifyConfigFile (15-50)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/internal/docker_keyring_test.go (1)
framework/docker/client/client.go (2)
  • Client (14-17)
  • NewClient (22-27)
framework/docker/cosmos/chain_builder.go (3)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/evstack/chain_builder.go (1)
  • ChainBuilder (15-40)
framework/docker/evstack/evmsingle/builder.go (1)
  • ChainBuilder (14-24)
framework/docker/internal/busybox.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/file/file_writer.go (2)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/ibc_test.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/container/lifecycle.go (3)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/port/port.go (1)
  • Listeners (15-15)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/volume/owner.go (3)
framework/docker/client/client.go (1)
  • Client (14-17)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/file/file_retriever.go (2)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/internal/docker_keyring.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/evstack/reth/config.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/dataavailability/config.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/container/job.go (2)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/internal/network.go (1)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
🔇 Additional comments (38)
framework/docker/evstack/reth/builder.go (1)

18-18: Interface-based client injection looks good

This aligns with the new cleanup-label abstraction and improves testability.

Also applies to: 54-57

framework/docker/container/node.go (1)

89-100: Volume removal implementation verified as correct

The RemoveVolumes signature has been successfully updated to remove the testName parameter, and the sole call site in node.go:99 correctly invokes it with only the context parameter, aligning with label-based cleanup via CleanupLabel.

framework/docker/cosmos/node.go (1)

114-149: Constructor interface change verified—all call sites compatible

Confirmed: tastoraclient.Client implements types.TastoraDockerClient interface (with embedded client.Client and CleanupLabel() method). All call sites pass compatible types: test code uses &tastoraclient.Client{}, production code passes b.dockerClient (typed as types.TastoraDockerClient).

framework/docker/cosmos/chain_config.go (1)

6-6: LGTM: Clean interface adoption.

The replacement of the concrete Docker client type with types.TastoraDockerClient interface is correct and aligns with the PR's objective to support labeled cleanup.

Also applies to: 14-14

framework/docker/internal/busybox.go (1)

6-6: LGTM: Interface adoption in internal utility.

The function signature update correctly adopts the TastoraDockerClient interface without affecting the internal logic.

Also applies to: 28-28

framework/docker/internal/startcontainer.go (1)

5-5: LGTM: Consistent interface adoption.

The StartContainer function signature correctly adopts the new interface without any logic changes.

Also applies to: 18-18

framework/docker/docker_test.go (1)

42-42: LGTM: Test configuration updated for labeled client.

The type change correctly adopts the new TastoraDockerClient interface. The removal of explicit per-test cleanup registration (mentioned in the AI summary) aligns with the PR's objective—cleanup is now handled automatically via the labeled client mechanism.

framework/docker/internal/keyring.go (1)

7-7: LGTM: Keyring utility updated correctly.

The function signature correctly adopts the TastoraDockerClient interface with no changes to the keyring extraction logic.

Also applies to: 21-21

framework/docker/container/image.go (1)

6-6: LGTM: Image pulling interface updated.

The PullImage method signature correctly adopts the TastoraDockerClient interface without affecting the image inspection and pull logic.

Also applies to: 34-34

framework/docker/evstack/reth/config.go (1)

5-5: LGTM: Reth configuration updated.

The DockerClient field type correctly adopts the TastoraDockerClient interface, consistent with other configuration structures.

Also applies to: 12-12

framework/docker/ibc_test.go (1)

18-18: LGTM: IBC test helpers updated consistently.

Both createCelestiaChain and createSimappChain function signatures correctly adopt the TastoraDockerClient interface, maintaining consistency across the test suite.

Also applies to: 50-50

framework/docker/chain_node_test.go (1)

33-33: Empty client instances are acceptable for hostname-only tests.

The test creates empty &tastoraclient.Client{} instances. While these would fail if Docker operations were attempted, this test only validates hostname generation logic and doesn't invoke any Docker client methods.

Also applies to: 46-46, 59-59

framework/docker/volume/owner.go (1)

19-19: Cleanup label correctly sourced from client interface.

The change from using opts.TestName to opts.Client.CleanupLabel() properly implements the labeled client pattern for volume cleanup, ensuring resources are tagged with the appropriate label for deletion.

Also applies to: 56-56

framework/docker/ibc/relayer/hermes.go (1)

39-39: LGTM: Interface migration applied correctly.

The signature change to accept types.TastoraDockerClient aligns with the broader refactoring effort and maintains backward compatibility through interface abstraction.

framework/docker/evstack/config.go (1)

14-14: LGTM: Config struct updated to use interface.

The field type change aligns with the project-wide migration to the TastoraDockerClient interface abstraction.

framework/types/docker_client.go (1)

7-12: Well-designed interface for Docker client abstraction.

The interface cleanly extends client.CommonAPIClient with the CleanupLabel() method, enabling resource tagging for proper cleanup. The documentation clearly states the purpose.

framework/docker/dataavailability/network_builder.go (1)

23-23: LGTM: Builder pattern updated for interface.

The dockerClient field and WithDockerClient method correctly adopt the TastoraDockerClient interface, maintaining the builder pattern's fluent API.

Also applies to: 100-102

framework/docker/file/file_writer.go (1)

22-22: LGTM: Consistent cleanup labeling implemented.

The migration to TastoraDockerClient and the use of w.cli.CleanupLabel() for container labels ensures proper resource tagging for cleanup operations, consistent with the PR's objectives.

Also applies to: 27-27, 56-56

framework/docker/internal/docker_keyring.go (1)

26-26: LGTM: Docker keyring updated to use interface.

The migration to TastoraDockerClient is correctly implemented. The import alias tastoratypes keeps the code readable while avoiding naming conflicts.

Also applies to: 37-43

framework/testutil/docker/toml.go (2)

19-51: LGTM! Clean migration to the interface abstraction.

The function signature update correctly adopts the TastoraDockerClient interface, maintaining the same behavior while enabling better testability and cleanup label support.


7-7: No dependency cycle introduced.

Verification confirms that framework/types contains no imports from other internal packages (only external dependencies). Therefore, there is no direct or transitive path from framework/types back to framework/testutil, and no dependency cycle is created by the new import.

framework/docker/toml.go (1)

10-10: LGTM! Consistent interface adoption.

The migration to types.TastoraDockerClient is implemented correctly, aligning with the broader refactoring across the codebase.

Also applies to: 18-50

framework/docker/evstack/evmsingle/builder.go (1)

5-5: LGTM! Builder correctly adopts the interface.

The ChainBuilder struct and its fluent API methods are updated consistently to use types.TastoraDockerClient.

Also applies to: 18-18, 54-57

framework/docker/dataavailability/config.go (1)

5-5: LGTM! Config struct updated correctly.

The DockerClient field type migration to types.TastoraDockerClient is consistent with the codebase-wide refactoring.

Also applies to: 14-14

framework/docker/evstack/chain_builder.go (1)

6-6: LGTM! Evstack ChainBuilder migrated correctly.

The builder pattern correctly adopts the types.TastoraDockerClient interface, maintaining consistency with other chain builders in the codebase.

Also applies to: 23-23, 93-96

framework/docker/cosmos/chain_builder.go (1)

117-117: LGTM! Cosmos ChainBuilder updated consistently.

The dockerClient field and WithDockerClient method are correctly migrated to use types.TastoraDockerClient, aligning with the interface abstraction pattern.

Also applies to: 249-251

framework/docker/evstack/evmsingle/config.go (1)

5-5: LGTM! Config struct migrated correctly.

The DockerClient field type update to types.TastoraDockerClient is consistent with other config structures in the codebase.

Also applies to: 12-12

framework/docker/internal/network.go (1)

6-6: LGTM! Internal network utility updated correctly.

The GetContainerInternalIP function signature correctly adopts types.TastoraDockerClient, which embeds client.CommonAPIClient and provides the necessary ContainerInspect method.

Also applies to: 12-12

framework/docker/client/client.go (1)

29-32: LGTM; wrapper cleanly satisfies TastoraDockerClient

Embedding moby client and exposing CleanupLabel() matches the interface; import uses github.com/moby/moby/client as in the rest of the codebase. Based on learnings

framework/docker/container/lifecycle.go (1)

99-105: Correct label usage

Tagging the container with {consts.CleanupLabel: c.client.CleanupLabel()} is exactly what enables precise cleanup.

framework/docker/container/job.go (3)

29-35: Interface migration looks good

Swapping to types.TastoraDockerClient and keeping testName for naming is consistent with the new cleanup model.


180-181: Good: containers labeled with client cleanup label

This aligns container lifecycle with the new per-run cleanup.


45-78: All NewJob call sites are compliant with the updated signature.

Verification confirms all three invocations of NewJob correctly pass types.TastoraDockerClient:

  • file_writer_test.go:30 and file_retriever_test.go:30 pass cli from docker.DockerSetup(t), which returns types.TastoraDockerClient
  • node.go:67 passes n.DockerClient, which is of type types.TastoraDockerClient
framework/docker/setup.go (5)

58-66: Nice: unique per-run cleanup label and labeled network

Network creation carries the same label for targeted cleanup.


71-74: t.Cleanup wiring is correct

Using DockerCleanup(t, dockerClient) ensures the label travels with the client.


149-151: Helper mirrors new model

Forwarding to the test-name variant via cli.CleanupLabel() keeps the public API simple.


77-147: Cleanup filters follow label correctly

Container selection, stop/wait/remove flow, and deferring volume/network pruning to labeled routines are sound.


50-74: No action required — API change properly verified across all callers

All four call sites of DockerSetup() have been correctly updated:

  • ibc_transfer_test.go:51 and docker_test.go:66 properly destructure the return tuple and pass dockerClient to downstream APIs
  • file_retriever_test.go:22 and file_writer_test.go:22 use cli with compatible VolumeCreate() calls
  • types.TastoraDockerClient interface extends client.CommonAPIClient, maintaining method compatibility
  • All downstream usage patterns confirmed compatible with the new return type

Comment on lines +21 to +27
// NewClient creates a new Client with the given Docker client and cleanup label.
func NewClient(c *client.Client, cleanupLabel string) *Client {
return &Client{
Client: c,
cleanupLabel: cleanupLabel,
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Panic early on nil underlying client

Defend against accidental nil by validating the passed *client.Client.

 func NewClient(c *client.Client, cleanupLabel string) *Client {
+	if c == nil {
+		panic("nil docker client")
+	}
 	return &Client{
 		Client:       c,
 		cleanupLabel: cleanupLabel,
 	}
 }
🤖 Prompt for AI Agents
In framework/docker/client/client.go around lines 21 to 27, NewClient currently
accepts a *client.Client that may be nil; add a nil check and panic (or return
an error if API design prefers) early to fail fast. Update NewClient to validate
the incoming c parameter and panic with a clear message if c == nil (or change
signature to return (*Client, error) and return an error) so the package defends
against accidental nil underlying client.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
framework/docker/volume/owner.go (1)

18-25: Remove unused TestName field from OwnerOptions struct.

The TestName field is no longer used in the SetOwner function—cleanup labels are now sourced from opts.Client.CleanupLabel(). Remove the field from the struct definition and update the instantiation at framework/docker/container/node.go:182 where it's being passed.

🧹 Nitpick comments (1)
framework/docker/file/file_writer.go (1)

21-25: Interface migration is correct. Remove unused testName field.

The change from *client.Client to types.TastoraDockerClient interface is sound and properly enables the labeled cleanup functionality. However, the testName field is never used in any Writer methods—it's set in the constructor but never read. This appears to be residual code that should be removed.

Remove the testName field from the Writer struct (line 24) and from the NewWriter function signature and initialization (lines 28-29).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0152e65 and 60e3f53.

📒 Files selected for processing (4)
  • framework/docker/cosmos/node.go (1 hunks)
  • framework/docker/file/file_retriever.go (3 hunks)
  • framework/docker/file/file_writer.go (2 hunks)
  • framework/docker/volume/owner.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • framework/docker/file/file_retriever.go
  • framework/docker/cosmos/node.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: chatton
PR: celestiaorg/tastora#106
File: framework/docker/dataavailability/config.go:3-7
Timestamp: 2025-08-27T08:24:51.731Z
Learning: The tastora codebase consistently uses `github.com/moby/moby/client` for Docker client imports throughout all framework/docker packages. Do not suggest changing this to `github.com/docker/docker/client` as it would break type compatibility.
📚 Learning: 2025-08-27T08:24:51.731Z
Learnt from: chatton
PR: celestiaorg/tastora#106
File: framework/docker/dataavailability/config.go:3-7
Timestamp: 2025-08-27T08:24:51.731Z
Learning: The tastora codebase consistently uses `github.com/moby/moby/client` for Docker client imports throughout all framework/docker packages. Do not suggest changing this to `github.com/docker/docker/client` as it would break type compatibility.

Applied to files:

  • framework/docker/volume/owner.go
  • framework/docker/file/file_writer.go
🧬 Code graph analysis (2)
framework/docker/volume/owner.go (3)
framework/docker/client/client.go (1)
  • Client (14-17)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
framework/docker/file/file_writer.go (2)
framework/types/docker_client.go (1)
  • TastoraDockerClient (9-12)
framework/docker/consts/consts.go (1)
  • CleanupLabel (6-6)
🔇 Additional comments (6)
framework/docker/volume/owner.go (3)

11-11: LGTM!

The import is necessary for the new types.TastoraDockerClient interface.


42-43: LGTM!

Minor readability improvement.


57-57: LGTM! Cleanup label now sourced from the client.

This change centralizes the cleanup label management by sourcing it from the client interface rather than the test name, which aligns with the PR's objective to fix volume cleanup issues in subtests.

framework/docker/file/file_writer.go (3)

13-13: LGTM: Import addition supports the interface migration.

The new import is necessary for the types.TastoraDockerClient interface.


28-30: LGTM: Constructor signature updated to accept interface.

The signature change from *client.Client to types.TastoraDockerClient is a breaking API change but aligns with the PR objectives to enable proper cleanup via labeled clients. The interface-based design is more flexible and testable.


57-57: LGTM: Core cleanup fix implemented correctly.

The label now uses w.cli.CleanupLabel() to get a per-run cleanup label value, enabling proper resource cleanup. This directly addresses the PR objective of ensuring volumes and containers created in tests are properly removed.

Copy link
Collaborator

@mojtaba-esk mojtaba-esk left a comment

Choose a reason for hiding this comment

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

LGTM! thanks for the great work!
Left a few nits

s.Require().NoError(err)

s.dockerClient = dockerClient
s.dockerClient = tastoraclient.NewClient(dockerClient, "docker-keyring-test-suite")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Q: is the "docker-keyring-test-suite" fixed for all tests? is it safe to do so if two tests are running concurrently on the same machine? will they share their keyring?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oh good call, I think we need to move this to SetupTest and add a random element to the name

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

actually I think in this case it doesn't make a difference since we aren't using the label for anything

func DockerCleanup(t DockerSetupTestingT, cli *client.Client) func() {
return DockerCleanupWithTestName(t, cli, t.Name())
func DockerCleanup(t DockerSetupTestingT, cli types.TastoraDockerClient) func() {
return DockerCleanupWithTestName(t, cli, cli.CleanupLabel())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: we could probably rename this func: DockerCleanupWithTestName

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

since we are changing names maybe we can actually use this opportunity to remove the Docker prefix from the names since the package is already docker. so we get docker.Setup instead of docker.DockerSetup etc.

}

func PruneVolumesWithRetryAndTestName(ctx context.Context, t DockerSetupTestingT, cli *client.Client, testName string) {
func PruneVolumesWithRetryAndTestName(ctx context.Context, t DockerSetupTestingT, cli types.TastoraDockerClient, testName string) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: Also here instead of testname here PruneVolumesWithRetryAndTestName we refer to a cleanup label

for _, vol := range volumeList.Volumes {
// try to get volume size before removal
if vol.UsageData != nil {
spaceReclaimed += uint64(vol.UsageData.Size)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: to have it more accurate, one could add it to the total spaceReclaimed after being successfully deleted.

Copy link
Collaborator

Choose a reason for hiding this comment

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

this way it adds it before, and if retry to remove it, it will be added again and again.

@chatton chatton merged commit 7defa8b into main Nov 10, 2025
5 of 6 checks passed
@chatton chatton deleted the cian/ensure-proper-volume-cleanup branch November 10, 2025 12:04
@chatton
Copy link
Collaborator Author

chatton commented Nov 10, 2025

merged as the failure is still the jwt-secret one which is being fixed in a separate branch

@chatton chatton mentioned this pull request Nov 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants