Add comprehensive test suite for file persistence and change tracking#65
Conversation
| @@ -0,0 +1,210 @@ | |||
| package environment | |||
There was a problem hiding this comment.
the unit tests will conflict with #59, but not in a way that's hard to fix i don't think, just gotta move some shit around
dd281c8 to
88bc059
Compare
aluzzardi
left a comment
There was a problem hiding this comment.
Thank you @grouville, much appreciated! Some minor comments
| @@ -0,0 +1,729 @@ | |||
| package environment | |||
There was a problem hiding this comment.
nit: MAYBE we should move these into their own package, e.g. environment/integration or something, keep the unit tests top-level. MAYBE. Thoughts?
There was a problem hiding this comment.
imo for small projects the thing he's doing with -short is quite nice and provides a similar test grouping UX. i'd like to try it out and see if there are other drawbacks that aren't yet obvious to me... the one i can see from here is it might be too easy to share helpers that turn unit tests into int tests.
There was a problem hiding this comment.
nit: MAYBE we should move these into their own package, e.g.
environment/integrationor something, keep the unit tests top-level. MAYBE. Thoughts?
Regarding the integration tests: I’ve kept them in the environment package because they need access to the private functions to thoroughly verify the implementation. Moving them to a separate package (like environment_test or environment/integration) would limit testing to the public API only, reducing coverage (or requiring to turn more of those functions public. What would be your recommended approach (I don't mind) ?
0a223b7 to
67a1630
Compare
4038593 to
6f4ec13
Compare
cwlbraa
left a comment
There was a problem hiding this comment.
lgtm, just need to decide whether this or #62 goes in first... conventional wisdom says tests go in first, but idk cc @aluzzardi
1606741 to
1c023af
Compare
aluzzardi
left a comment
There was a problem hiding this comment.
LGTM!
Left a few minor comments.
Major comment here: I think the distinction between unit and integration tests is very narrow. IMHO we should just put everything as unit, e.g. environment/environment_test.go and repository/repository_test.go?
To me integration tests would be like ... testing cu with claude for instance.
In any case -- all of this can be discussed in follow ups, IMHO this is good to go aside from the dirname comment which we need to discuss
|
|
||
| // getRepoPath returns the path for storing repository data | ||
| func (r *Repository) getRepoPath() string { | ||
| return r.getBasePath() + "/repos" |
|
|
||
| // getWorktreePath returns the path for storing worktrees | ||
| func (r *Repository) getWorktreePath() string { | ||
| return r.getBasePath() + "/worktrees" |
| if strings.Contains(err.Error(), "not a git repository") { | ||
| // Check for exit code 128 which means not a git repository | ||
| var exitErr *exec.ExitError | ||
| if errors.As(err, &exitErr) && exitErr.ExitCode() == 128 { |
There was a problem hiding this comment.
For later as a follow-up: maybe we should add this logic to RunGitCommand directly, catch all git commands that are not run from a git repository?
Although I think it's impossible since everything starts with Open()
| if errors.As(err, &exitErr) && exitErr.ExitCode() == 2 { | ||
| // Exit code 2 means the remote doesn't exist | ||
| // Use just the base name for temporary directories to avoid deeply nested paths | ||
| return homedir.Expand(filepath.Join(r.getRepoPath(), filepath.Base(repo))) |
There was a problem hiding this comment.
So actually that was done on purpose -- we used to use the directory name, but that failed if multiple repositories had the same name on different directories (e.g. ~/work/foo and ~/Documents/foo).
Was there an issue this is fixing, or was it for aesthetics?
| } | ||
|
|
||
| // getBasePath returns the base path for container-use data, using the default if not set | ||
| func (r *Repository) getBasePath() string { |
There was a problem hiding this comment.
nit: This logic is already handled by Open() (e.g. setting cuGlobalConfigPath when calling Open()).
I think it would be simpler to avoid duplication of this logic, always assume r.basePath is set, and get rid of getBasePath altogether
| @@ -0,0 +1,128 @@ | |||
| package integration | |||
There was a problem hiding this comment.
Shouldn't these go into repository/repository_test.go? We're testing Open over there and the rest here here
i'd prolly call tests involving claude e2e, but if we're integrating anything here it's probably the MCP server against repository+env |
…al behaviors users rely on: * Persistence of work across sessions (files and changes remain intact through restarts). * Automatic change tracking and audit trails for effective debugging. * Graceful handling of problematic files, including Python cache, binary files, and large files. * Isolation of multiple environments to support safe parallel operations. * Reliable persistence of environment configuration (base images, setup commands). Detailed testing includes: * Git operations, specifically handling command errors, worktree paths, and empty directories. * Selective file staging to manage Python cache and binary files appropriately. * Verification of configuration persistence and environment isolation. Adopted a behavior-driven testing approach focusing on user-experienced behaviors rather than internal implementation details. Modified git.go to support test isolation via the `CONTAINER_USE_CONFIG_DIR` environment variable. Introduced test helpers to streamline the creation of isolated test environments. Documented known limitations clearly with skipped tests for currently unresolved issues related to Python cache, binary directories, and environment variables. Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
make it work Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Updated the test to use commands that developers actually run: - Creating build directories (common in CI/CD) - Writing to build output logs (typical build process) - Creating coverage directories (test runners like pytest) These are more representative of real-world scenarios where commands produce no git-trackable changes but should still be audited. Related to issue dagger#82
The test now: - Simulates Python cache directories without needing Python installed - Verifies that development continues normally with __pycache__ present - Serves as a regression test for Python workflows - Renamed from PythonCache to PythonDevelopmentWorkflow for clarity The original bug appears to have been fixed - __pycache__ directories are properly ignored by git and don't interfere with operations.
Concurrency was properly implemented -- added a test showing that in a sequencial environment, every git operation is sequential and working Removed the impossible concurrency test Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Parallelise the tests -- rebased on top of the new function schema to open and get repos TODO: cleanup a bit the code / but it's working ! Signed-off-by: home <guillaume@dagger.io>
Signed-off-by: home <guillaume@dagger.io>
Summary
Comprehensive test suite to ensure reliable file persistence, change tracking, and environment isolation in container-use.
Key Improvements
Core Functionality Tests
Test Coverage
Implementation Notes
git.goto support test isolation viaCONTAINER_USE_CONFIG_DIRStatus
Ready for review
UPDATE 06/25/2025
Rewrote the entire test suite, following the new paradigm. The idea is to have integration tests that mimick what a
userwill do to end up in a bug / weird situationAlready ready for review
Introduced the
Repository: basePath:instead of the
CONTAINER_USE_CONFIG_DIRto isolate tests and run them in parallelThe
WithRepositoryis a helper function that spins up Dagger -- a repo with some configurable setup function and returns a userActions, which has access to the same function as the agent would. The idea is for this abstraction to also be able to mimick the CLI calls in the near future to declaratively express any user scenarioTODO: