Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [#519] Save container to a temp file #721

Merged
merged 34 commits into from
Nov 17, 2024
Merged

feat: [#519] Save container to a temp file #721

merged 34 commits into from
Nov 17, 2024

Conversation

hwbrzzl
Copy link
Contributor

@hwbrzzl hwbrzzl commented Nov 11, 2024

📑 Description

Closes goravel/goravel#519

Previously, we created a new db container for every test case, hence there are multiple same database type containers, initiating each container will spend a lot of time, the test speed in local and CI is plodding.

Currently, one database type only builds one docker container, the docker container will be saved in a temp file, it can be fetched when needed, and each test case will create its own database in the same container, the test speed will be faster.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a ContainerManager for managing Docker containers for various databases.
    • Added methods for creating and managing database connections across multiple database types (MySQL, PostgreSQL, SQLite, SQL Server).
  • Improvements

    • Enhanced error handling in database initialization and connection readiness checks.
    • Updated test suites to improve clarity and resource management, including new checks for Docker readiness.
    • Added new functions for environment checks and improved path resolution logic.
  • Bug Fixes

    • Revised skip messages in test suites for clarity, ensuring tests are appropriately skipped on Windows environments.
  • Chores

    • Cleaned up and standardized code across various files for better readability and maintainability.

✅ Checks

  • Added test cases for my code

Copy link
Contributor

coderabbitai bot commented Nov 11, 2024

Walkthrough

The pull request introduces a variety of changes across multiple files, primarily focusing on enhancing the database management and testing utilities. Key modifications include updates to the .gitignore file, alterations to database driver interfaces, and improvements in test setups to ensure Docker services are ready before running tests. New methods for managing Docker containers have been added, along with enhanced error handling and resource management in testing scenarios. Overall, these changes aim to streamline database operations and improve testing robustness.

Changes

File Change Summary
.gitignore Removed entry goravel*, allowing tracking of related files.
contracts/testing/testing.go Updated DatabaseDriver interface with new methods and comments; added ContainerID to DatabaseConfig.
database/factory/factory_test.go Refactored test setup for clarity; updated skip message for Windows.
database/gorm/query_test.go Added TearDownSuite for Docker cleanup; improved error messages in tests.
database/gorm/test_utils.go Removed TestReadWriteConfig; updated methods to use testing.DatabaseConfig.
database/gorm/to_sql_test.go Refactored setup to check Docker readiness; updated skip message.
database/migration/default_migrator_test.go Enhanced error handling and test descriptions; updated skip message.
database/migration/repository_test.go Updated skip message; ensured Docker readiness in setup.
database/migration/sql_migrator_test.go Improved skip message; added cleanup logic for SQLite.
database/orm/orm_test.go Added TearDownSuite for Docker cleanup; updated skip message.
database/schema/common_schema_test.go Updated skip message; ensured Docker readiness in setup.
database/schema/postgres_schema_test.go Updated skip message; ensured Docker readiness in setup.
database/schema/schema_test.go Updated skip message; added TearDownTest for SQLite cleanup.
foundation/application.go Introduced new import for env; modified path handling logic.
foundation/application_test.go Updated skip message; ensured Docker readiness in tests.
foundation/path.go Deleted file containing path utility functions.
mail/application_test.go Updated skip message.
queue/application_test.go Updated skip message.
support/docker/container_manager.go Introduced ContainerManager struct for managing Docker containers.
support/docker/container_manager_test.go Added test suite for ContainerManager.
support/docker/docker.go Simplified database management functions; improved error handling.
support/docker/docker_test.go Expanded test scenarios for PostgreSQL; updated skip message.
support/docker/mysql.go Standardized receiver variable naming; enhanced Database method.
support/docker/mysql_test.go Updated skip conditions and added a new test case for TestBuild.
support/docker/postgres.go Standardized receiver variable naming; introduced Database method.
support/docker/postgres_test.go Added constants for configuration; expanded test cases.
support/docker/redis_test.go Updated skip message.
support/docker/sqlite.go Standardized receiver variable naming; added Database method.
support/docker/sqlite_test.go Updated skip conditions; added new functionality in TestBuild.
support/docker/sqlserver.go Standardized receiver variable naming; introduced Database method.
support/docker/sqlserver_test.go Updated skip conditions; added new test case for Database method.
support/docker/utils.go Introduced port checking functionality; corrected port validation logic.
support/docker/utils_test.go Updated skip message.
support/env/env.go Added functions for environment checks; improved error handling in path resolution.
testing/docker/database.go Enhanced NewDatabase initialization logic with error handling.
testing/docker/database_test.go Simplified test assertions; updated skip message.
testing/docker/docker_test.go Added environment checks for Windows; improved resource cleanup.

Assessment against linked issues

Objective Addressed Explanation
Write ContainerType into a temp file, the file can be shared with all packages when testing, optimize the testing speed (#519)

Possibly related issues

  • feat: optimize cache performance #519: The changes to Docker management and container initialization may facilitate the implementation of writing ContainerType into a temp file for shared access during testing.

Possibly related PRs

Suggested reviewers

  • kkumar-gcc
  • devhaozi

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: f7010d4 Previous: 235c88e Ratio
Benchmark_Panic 0.001086 ns/op 0 B/op 0 allocs/op 0.0006841 ns/op 0 B/op 0 allocs/op 1.59
Benchmark_Panic - ns/op 0.001086 ns/op 0.0006841 ns/op 1.59
BenchmarkFile_ReadWrite 341476 ns/op 1801 B/op 21 allocs/op 204708 ns/op 1800 B/op 21 allocs/op 1.67
BenchmarkFile_ReadWrite - ns/op 341476 ns/op 204708 ns/op 1.67

This comment was automatically generated by workflow using github-action-benchmark.

Copy link

codecov bot commented Nov 11, 2024

Codecov Report

Attention: Patch coverage is 60.35242% with 180 lines in your changes missing coverage. Please review.

Project coverage is 69.72%. Comparing base (7b133e1) to head (4692896).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
support/docker/container_manager.go 63.23% 35 Missing and 15 partials ⚠️
support/env/env.go 29.54% 28 Missing and 3 partials ⚠️
support/docker/postgres.go 64.81% 13 Missing and 6 partials ⚠️
support/docker/mysql.go 70.37% 12 Missing and 4 partials ⚠️
database/gorm/test_utils.go 72.54% 7 Missing and 7 partials ⚠️
support/docker/docker.go 54.83% 11 Missing and 3 partials ⚠️
support/docker/sqlite.go 47.82% 7 Missing and 5 partials ⚠️
support/docker/sqlserver.go 71.42% 6 Missing and 6 partials ⚠️
support/docker/utils.go 40.00% 4 Missing and 2 partials ⚠️
testing/docker/database.go 25.00% 4 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #721      +/-   ##
==========================================
- Coverage   69.73%   69.72%   -0.02%     
==========================================
  Files         202      202              
  Lines       15875    16107     +232     
==========================================
+ Hits        11071    11230     +159     
- Misses       4201     4242      +41     
- Partials      603      635      +32     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Manage docker containers in a temp file, the content is:

image

Comment on lines 194 to 209
func (r *ContainerManager) lock() {
for {
if !file.Exists(r.lockFile) {
break
}
}
if err := file.Create(r.lockFile, ""); err != nil {
panic(err)
}
}

func (r *ContainerManager) unlock() {
if err := file.Remove(r.lockFile); err != nil {
panic(err)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

To avoid write temp file conflict when testing multiple packages.

}
}

func (receiver *MysqlImpl) Driver() database.Driver {
func (r *MysqlImpl) Database(name string) (testing.DatabaseDriver, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Create a new database in the existing docker container.

@hwbrzzl hwbrzzl marked this pull request as ready for review November 16, 2024 08:06
@hwbrzzl hwbrzzl requested a review from a team as a code owner November 16, 2024 08:06
Copy link
Contributor

@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: 21

🧹 Outside diff range and nitpick comments (62)
database/schema/common_schema_test.go (1)

21-21: Fix grammatical error in skip message

The skip message contains a grammatical error.

-t.Skip("Skip test that using Docker")
+t.Skip("Skip test that uses Docker")
database/schema/postgres_schema_test.go (1)

24-24: Fix grammatical error in skip message

The current skip message contains grammatical errors. Consider using one of these alternatives:

  • "Skipping tests that use Docker" (original)
  • "Skip tests using Docker"
-t.Skip("Skip test that using Docker")
+t.Skip("Skipping tests that use Docker")
contracts/testing/testing.go (2)

30-31: Well-designed method for container reuse strategy

The new Database method effectively supports the PR's goal of reusing containers by allowing creation of multiple database instances within the same container. The error return ensures robust error handling.

Consider documenting the following in the package documentation:

  1. The lifecycle management pattern (Build → Ready → Database)
  2. Best practices for error handling when creating multiple databases
  3. Guidelines for cleaning up databases created with this method

45-50: Good addition of ContainerID for container tracking

The addition of ContainerID to DatabaseConfig enables proper container instance tracking, which is essential for the container reuse strategy.

Consider adding the following features to enhance container management:

  1. Methods to validate ContainerID format
  2. Utilities to check container existence
  3. Documentation about ContainerID lifecycle and cleanup responsibilities
support/docker/sqlite.go (3)

25-26: Enhance error message clarity

Consider providing more context in the error message to help with debugging.

-	if _, err := r.connect(); err != nil {
-		return fmt.Errorf("connect Sqlite error: %v", err)
+	if _, err := r.connect(); err != nil {
+		return fmt.Errorf("failed to connect to SQLite database '%s': %v", r.database, err)

52-57: Enhance error message clarity

Consider providing more context in the error message for better debugging.

-	if _, err := r.connect(); err != nil {
-		return fmt.Errorf("connect Sqlite error when freshing: %v", err)
+	if _, err := r.connect(); err != nil {
+		return fmt.Errorf("failed to reconnect to SQLite database '%s' during refresh: %v", r.database, err)

74-75: Enhance error message clarity

Consider providing more context in the error message.

-	if err := file.Remove(r.database); err != nil {
-		return fmt.Errorf("stop Sqlite error: %v", err)
+	if err := file.Remove(r.database); err != nil {
+		return fmt.Errorf("failed to remove SQLite database file '%s': %v", r.database, err)
support/docker/sqlite_test.go (1)

70-74: Enhance test coverage for database isolation

While the test verifies basic driver functionality, consider adding assertions to ensure:

  1. The new database is actually created
  2. It's using the same container (validating container reuse)
  3. Data isolation between databases

Example enhancement:

 databaseDriver, err := s.sqlite.Database("another")
 s.NoError(err)
 s.NotNil(databaseDriver)
+
+// Verify database creation
+instance2, err := databaseDriver.(*SqliteImpl).connect()
+s.NoError(err)
+
+// Create table in "another" database
+res := instance2.Exec(`CREATE TABLE test_isolation (id INT)`)
+s.NoError(res.Error)
+
+// Verify table doesn't exist in original database
+var count int64
+res = instance.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name = 'test_isolation'").Scan(&count)
+s.NoError(res.Error)
+s.Equal(int64(0), count)
+
 s.NoError(databaseDriver.Stop())
support/docker/utils.go (2)

17-18: Consider using a test-specific approach instead of a global variable

While the global testPortUsing variable works for testing, it could lead to test isolation issues. Consider alternatives:

  1. Move this into a test configuration struct
  2. Use dependency injection for port checking behavior

Example approach:

type PortChecker interface {
    IsPortUsing(port int) bool
}

type DefaultPortChecker struct {
    testMode bool
}

20-31: Address potential race condition in port checking

While the implementation is generally sound, there's a potential race condition between checking port availability and actually using it. Another process could take the port between the check and use.

Consider:

  1. Implementing port reservation mechanism
  2. Adding retry logic with backoff
  3. Using a port range with atomic operations

Example approach:

func reservePort(port int, maxRetries int) (net.Listener, error) {
    for i := 0; i < maxRetries; i++ {
        if l, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil {
            return l, nil
        }
        time.Sleep(backoff(i))
    }
    return nil, fmt.Errorf("failed to reserve port after %d attempts", maxRetries)
}
support/docker/docker_test.go (1)

33-37: Consider maintaining consistent test organization.

The PostgreSQL test case is placed outside the TestModelNormal condition while similar "multiple" test cases for other databases remain inside. This creates an inconsistency in test organization.

Consider either:

  1. Moving all "multiple" test cases outside the condition if they should always run
  2. Keeping this test case inside the condition for consistency with other database types
support/docker/sqlserver_test.go (1)

75-78: Enhance Database method test coverage

While the basic functionality is tested, consider enhancing the test coverage to verify:

  1. The new database is actually created and accessible
  2. The new database is properly isolated from the main database
  3. The user has correct permissions on the new database

Consider adding these verifications:

 	databaseDriver, err := s.sqlserver.Database("another")
 	s.NoError(err)
 	s.NotNil(databaseDriver)
+
+	// Verify database creation
+	var dbExists int
+	instance.Raw(`
+		SELECT COUNT(*) 
+		FROM sys.databases 
+		WHERE name = 'another'
+	`).Scan(&dbExists)
+	s.Equal(1, dbExists)
+
+	// Verify database isolation
+	instance2, err := databaseDriver.Connect()
+	s.NoError(err)
+	res := instance2.Exec(`
+		CREATE TABLE test_isolation (id int);
+		INSERT INTO test_isolation VALUES (1);
+	`)
+	s.NoError(res.Error)
+
+	// Verify the table doesn't exist in main database
+	var tableExists int
+	instance.Raw(`
+		SELECT COUNT(*) 
+		FROM sys.tables 
+		WHERE name = 'test_isolation'
+	`).Scan(&tableExists)
+	s.Equal(0, tableExists)
support/docker/postgres_test.go (2)

14-18: LGTM with a minor security suggestion.

The constants are well-organized and used consistently throughout the test suite. However, consider using a simpler password for test environments as complex passwords aren't necessary here and might make the tests harder to maintain.

-	testPassword = "Framework!123"
+	testPassword = "password123"

80-82: Consider enhancing the database driver test.

While the test verifies that a new database driver can be obtained, it would be more robust to verify that the database was actually created and is usable. This ensures the container reuse functionality works as intended.

Consider adding these verifications:

 	databaseDriver, err := s.postgres.Database("another")
 	s.NoError(err)
 	s.NotNil(databaseDriver)
+	
+	// Verify the new database is created and usable
+	db, err := databaseDriver.DB()
+	s.NoError(err)
+	s.NoError(db.Ping())
+	
+	// Verify we can create and query tables in the new database
+	res := databaseDriver.Exec(`CREATE TABLE test (id SERIAL PRIMARY KEY)`)
+	s.NoError(res.Error)
support/docker/container_manager_test.go (3)

15-21: Enhance the test skip message for Windows environments.

While skipping tests on Windows is appropriate, the skip message could be more informative about why the test is being skipped.

Consider this improvement:

-		t.Skip("Skip test that using Docker")
+		t.Skip("Skipping Docker-based tests on Windows environment")

27-44: Consider enhancing container cleanup and validation.

Two potential improvements for this test method:

  1. Consider stopping all containers after retrieval, not just SQLite, to prevent resource leaks.
  2. Add validation of container configurations (port, credentials, etc.) for each retrieved container.

Example enhancement:

 func (s *ContainerManagerTestSuite) TestGet() {
+	// Helper function to verify container configuration
+	verifyContainer := func(driver ContainerDriver, expectedType ContainerType) {
+		s.NoError(err)
+		s.NotNil(driver)
+		config := driver.Config()
+		s.NotEmpty(config)
+		// Add specific configuration checks based on container type
+	}
+
 	driver, err := s.containerManager.Get(ContainerTypeMysql)
-	s.NoError(err)
-	s.NotNil(driver)
+	verifyContainer(driver, ContainerTypeMysql)
+	defer driver.Stop()
 	// ... repeat for other container types
 }

1-80: Consider implementing a test container configuration provider.

To improve the maintainability and reusability of container test configurations, consider implementing a dedicated test configuration provider that would:

  1. Manage test credentials and configuration centrally
  2. Handle dynamic port allocation to prevent conflicts
  3. Provide consistent container configuration across all database types
  4. Include retry mechanisms for container operations

This would make the tests more robust and easier to maintain.

support/env/env.go (1)

11-19: Consider making the temp path configurable

The hardcoded path "/storage/temp" in IsAir() might make the function fragile if Air's configuration changes. Consider making this path configurable or using a more reliable method to detect Air execution.

+var airTempPath = "/storage/temp"
+
 func IsAir() bool {
 	for _, arg := range os.Args {
-		if strings.Contains(filepath.ToSlash(arg), "/storage/temp") {
+		if strings.Contains(filepath.ToSlash(arg), airTempPath) {
 			return true
 		}
 	}
testing/docker/docker_test.go (1)

22-24: Enhance the test skip message for clarity

While the Windows environment check is good, the skip message could be more descriptive to help developers understand why these tests are skipped on Windows.

Consider this improvement:

-		t.Skip("Skip test that using Docker")
+		t.Skip("Skipping Docker-based tests on Windows as they may not function correctly in this environment")
database/migration/repository_test.go (2)

22-22: Consider improving the grammar in the skip message.

The current message "Skip test that using Docker" has grammatical issues. Consider using one of these alternatives:

  • "Skipping test that uses Docker"
  • "Skip test using Docker"
-		t.Skip("Skip test that using Docker")
+		t.Skip("Skipping test that uses Docker")

30-31: LGTM! Important container readiness check.

The addition of the PostgreSQL container readiness check is a crucial improvement that aligns with the PR's objective of optimizing container management. This ensures tests only proceed when the container is fully operational, preventing potential flaky tests.

This pattern of checking container readiness before tests is a good practice that should be consistently applied across all database-related test suites.

support/docker/postgres.go (2)

100-115: Simplify connection handling in Fresh method

The method works correctly but can be improved for better resource management.

Suggested improvement:

func (r *PostgresImpl) Fresh() error {
	gormDB, err := r.connect()
	if err != nil {
		return fmt.Errorf("connect Postgres error when clearing: %v", err)
	}
+	defer r.close(gormDB)

	if res := gormDB.Exec("DROP SCHEMA public CASCADE;"); res.Error != nil {
		return fmt.Errorf("drop schema of Postgres error: %v", res.Error)
	}

	if res := gormDB.Exec("CREATE SCHEMA public;"); res.Error != nil {
		return fmt.Errorf("create schema of Postgres error: %v", res.Error)
	}

-	return r.close(gormDB)
+	return nil
}

Line range hint 138-167: Consider adding timeout configuration and context support

While the connection handling works, it could be improved with more flexible timeout control.

Consider these improvements:

  1. Make retry attempts and intervals configurable
  2. Add context support for better timeout control

Example implementation:

+const (
+	defaultMaxRetries = 60
+	defaultRetryInterval = 2 * time.Second
+)

-func (r *PostgresImpl) connect() (*gormio.DB, error) {
+func (r *PostgresImpl) connect(ctx context.Context) (*gormio.DB, error) {
	var (
		instance *gormio.DB
		err      error
	)

-	for i := 0; i < 60; i++ {
+	for i := 0; i < defaultMaxRetries; i++ {
+		select {
+		case <-ctx.Done():
+			return nil, ctx.Err()
+		default:
			instance, err = gormio.Open(postgres.New(postgres.Config{
				DSN: fmt.Sprintf("postgres://%s:%s@%s:%d/%s", r.username, r.password, r.host, r.port, r.database),
			}))

			if err == nil {
				break
			}

-			time.Sleep(2 * time.Second)
+			time.Sleep(defaultRetryInterval)
+		}
	}

	return instance, err
}
database/migration/sql_migrator_test.go (2)

29-29: Fix grammatical error in skip message.

The current skip message has grammatical issues. Consider using one of these alternatives:

  • "Skipping tests that use Docker" (original)
  • "Skip tests using Docker"
-		t.Skip("Skip test that using Docker")
+		t.Skip("Skipping tests that use Docker")

41-43: Consider container cleanup for all database drivers.

While the SQLite container cleanup is good, consider implementing similar cleanup for other database drivers in driverToTestQuery to ensure complete resource cleanup after tests.

 func (s *SqlMigratorSuite) TearDownTest() {
 	s.NoError(file.Remove("database"))
-	if s.driverToTestQuery[contractsdatabase.DriverSqlite] != nil {
-		s.NoError(s.driverToTestQuery[contractsdatabase.DriverSqlite].Docker().Stop())
-	}
+	for driver, testQuery := range s.driverToTestQuery {
+		if testQuery != nil {
+			s.NoError(testQuery.Docker().Stop())
+		}
+	}
 }
support/docker/mysql.go (4)

112-118: Improve error message consistency.

Consider standardizing error messages to match the format used in other methods.

-    return fmt.Errorf("connect Mysql error when clearing: %v", err)
+    return fmt.Errorf("connect MySQL error: %v", err)
-    return fmt.Errorf("get tables of Mysql error: %v", res.Error)
+    return fmt.Errorf("get MySQL tables error: %v", res.Error)

143-147: Consider adding timeout to Ready check.

The Ready method should include a timeout to avoid indefinite waiting.

 func (r *MysqlImpl) Ready() error {
+    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+    defer cancel()
+
+    errCh := make(chan error, 1)
+    go func() {
         _, err := r.connect()
+        errCh <- err
+    }()
 
-    return err
+    select {
+    case err := <-errCh:
+        return err
+    case <-ctx.Done():
+        return fmt.Errorf("timeout waiting for MySQL to be ready")
+    }
 }

149-150: Add container existence check before stopping.

Consider verifying the container exists before attempting to stop it.

 func (r *MysqlImpl) Stop() error {
+    if r.containerID == "" {
+        return nil
+    }
     if _, err := run(fmt.Sprintf("docker stop %s", r.containerID)); err != nil {
         return fmt.Errorf("stop Mysql error: %v", err)
     }

157-171: Improve retry mechanism configuration.

Consider making retry attempts and delay configurable, and add exponential backoff.

+const (
+    maxRetries = 60
+    initialRetryDelay = 2 * time.Second
+)

 func (r *MysqlImpl) connect(username ...string) (*gormio.DB, error) {
     var (
         instance *gormio.DB
         err      error
+        retryDelay = initialRetryDelay
     )

     useUsername := r.username
     if len(username) > 0 {
         useUsername = username[0]
     }

-    for i := 0; i < 60; i++ {
+    for i := 0; i < maxRetries; i++ {
         instance, err = gormio.Open(mysql.New(mysql.Config{
             DSN: fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", useUsername, r.password, r.host, r.port, r.database),
         }))

         if err == nil {
             break
         }

-        time.Sleep(2 * time.Second)
+        time.Sleep(retryDelay)
+        retryDelay = min(retryDelay * 2, 10 * time.Second) // Exponential backoff with max delay
     }
support/docker/sqlserver.go (3)

Line range hint 81-106: Consider wrapping table cleanup in a transaction.

The Fresh method could benefit from transaction wrapping to ensure atomic cleanup operations. If an error occurs mid-cleanup, the database could be left in an inconsistent state.

func (r *SqlserverImpl) Fresh() error {
	instance, err := r.connect()
	if err != nil {
		return fmt.Errorf("connect Sqlserver error when clearing: %v", err)
	}

+	tx := instance.Begin()
+	if tx.Error != nil {
+		return fmt.Errorf("failed to begin transaction: %v", tx.Error)
+	}

-	res := instance.Raw("SELECT NAME FROM SYSOBJECTS WHERE TYPE='U';")
+	res := tx.Raw("SELECT NAME FROM SYSOBJECTS WHERE TYPE='U';")
	if res.Error != nil {
+		tx.Rollback()
		return fmt.Errorf("get tables of Sqlserver error: %v", res.Error)
	}

	var tables []string
	res = res.Scan(&tables)
	if res.Error != nil {
+		tx.Rollback()
		return fmt.Errorf("get tables of Sqlserver error: %v", res.Error)
	}

	for _, table := range tables {
-		res = instance.Exec(fmt.Sprintf("drop table %s;", table))
+		res = tx.Exec(fmt.Sprintf("drop table %s;", table))
		if res.Error != nil {
+			tx.Rollback()
			return fmt.Errorf("drop table %s of Sqlserver error: %v", table, res.Error)
		}
	}

+	if err := tx.Commit().Error; err != nil {
+		return fmt.Errorf("failed to commit transaction: %v", err)
+	}

	return nil
}

118-124: Consider adding container cleanup after stop.

The method stops the container but doesn't remove it, which could lead to orphaned containers accumulating over time.

func (r *SqlserverImpl) Stop() error {
	if _, err := run(fmt.Sprintf("docker stop %s", r.containerID)); err != nil {
		return fmt.Errorf("stop Sqlserver error: %v", err)
	}

+	if _, err := run(fmt.Sprintf("docker rm %s", r.containerID)); err != nil {
+		return fmt.Errorf("remove Sqlserver container error: %v", err)
+	}

	return nil
}

Line range hint 126-187: Consider optimizing connection retry strategy and adding transaction support.

The implementation has a few areas for potential improvement:

  1. The 2-second retry delay could significantly impact test execution time.
  2. Database and user creation operations could benefit from transaction wrapping.
  3. Consider extracting the database setup logic into a separate method for better maintainability.

Consider these optimizations:

  1. Reduce retry delay and add exponential backoff:
-		time.Sleep(2 * time.Second)
+		sleepTime := time.Duration(i * 100) * time.Millisecond
+		if sleepTime > 2 * time.Second {
+			sleepTime = 2 * time.Second
+		}
+		time.Sleep(sleepTime)
  1. Extract database setup into a separate method:
func (r *SqlserverImpl) setupDatabase(instance *gormio.DB) error {
	tx := instance.Begin()
	if tx.Error != nil {
		return fmt.Errorf("failed to begin transaction: %v", tx.Error)
	}
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// Create database if not exists
	if err := tx.Exec(fmt.Sprintf(`CREATE DATABASE "%s";`, r.database)).Error; err != nil {
		tx.Rollback()
		return err
	}

	// Create user if not exists
	if err := tx.Exec(fmt.Sprintf("CREATE LOGIN %s WITH PASSWORD = '%s'", r.username, r.password)).Error; err != nil {
		tx.Rollback()
		return err
	}

	// Setup permissions
	if err := tx.Exec(fmt.Sprintf("USE %s; CREATE USER %s FOR LOGIN %s", r.database, r.username, r.username)).Error; err != nil {
		tx.Rollback()
		return err
	}

	if err := tx.Exec(fmt.Sprintf("USE %s; ALTER ROLE db_owner ADD MEMBER %s", r.database, r.username)).Error; err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit().Error
}
database/orm/orm_test.go (2)

35-35: Fix grammatical error in skip message

The current message "Skip test that using Docker" contains grammatical errors. Consider using one of these alternatives:

  • "Skip tests that use Docker"
  • "Skipping tests using Docker"
-		t.Skip("Skip test that using Docker")
+		t.Skip("Skip tests that use Docker")

63-67: Consider cleaning up all database types in TearDownSuite

While the current implementation handles SQLite cleanup, consider extending this to clean up containers for all database types to ensure comprehensive resource management.

 func (s *OrmSuite) TearDownSuite() {
-	if s.testQueries[database.DriverSqlite] != nil {
-		s.NoError(s.testQueries[database.DriverSqlite].Docker().Stop())
+	for driver, query := range s.testQueries {
+		if query != nil && query.Docker() != nil {
+			s.NoError(query.Docker().Stop())
+		}
 	}
 }
database/factory/factory_test.go (1)

98-98: Fix grammatical error in skip message

The skip message contains a grammatical error. Consider using one of these alternatives:

  • "Skip test using Docker"
  • "Skip tests using Docker"
  • "Skipping test that uses Docker"
-t.Skip("Skip test that using Docker")
+t.Skip("Skip tests using Docker")
testing/docker/database_test.go (2)

112-113: Consider adding container reuse verification

The assertions correctly verify database creation and cleanup. However, given the PR's objective of container reuse, consider adding assertions to verify that containers are actually being reused across test cases.

 assert.NotNil(t, gotDatabase)
 assert.NoError(t, gotDatabase.Stop())
+// Verify container reuse
+firstContainerID := gotDatabase.ContainerID()
+secondDatabase, _ := NewDatabase(mockApp, tt.connection)
+assert.Equal(t, firstContainerID, secondDatabase.ContainerID(), "Container should be reused")
+assert.NoError(t, secondDatabase.Stop())

Line range hint 1-163: Consider implementing container info persistence

While the changes improve container management, the PR objective of saving container information to a temp file isn't fully implemented yet. Consider adding a mechanism to persist container information across test runs, perhaps using a singleton pattern or file-based storage.

Example approach:

  1. Create a container info manager that handles reading/writing to temp files
  2. Store container IDs and connection details
  3. Implement cleanup on process exit

This would further optimize test execution by enabling container reuse across different test packages.

Would you like me to provide a detailed implementation proposal for the container persistence mechanism?

database/schema/schema_test.go (3)

22-22: Fix grammatical error in skip message.

The skip message contains grammatical errors.

-t.Skip("Skip test that using Docker")
+t.Skip("Skip tests that use Docker")

Line range hint 89-90: Consider tracking TODO comments.

There are multiple TODO comments for unimplemented features (DropAllTypes and DropAllViews). Consider creating GitHub issues to track these implementations.

Would you like me to help create GitHub issues for tracking these TODO items?

Also applies to: 93-94


The commented-out tests are for unimplemented functionality

Based on the evidence from the codebase:

  • The methods HasColumn, GetColumns, and HasColumns are not defined in any of the schema interfaces (Schema, CommonSchema, DriverSchema)
  • While there are some test files that reference these methods, there are no actual implementations found
  • Only test stubs exist in postgres_test.go and sqlite_test.go for GetColumns

Recommendation:

  1. Create an issue to track the implementation of these column-related operations
  2. Remove the commented-out tests from schema_test.go and move them to the issue for reference
  3. Re-implement these tests once the actual functionality is developed
🔗 Analysis chain

Line range hint 186-241: Review commented-out test cases.

There are extensive commented-out test cases for column operations. Consider either:

  1. Implementing these tests now if the functionality exists
  2. Creating a separate issue to track their implementation
  3. Removing them if they're no longer relevant

This will help maintain cleaner test files and ensure all functionality is properly tested.

Let's check if these column operations are implemented:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if column operations are implemented in the schema package

# Search for HasColumn implementation
ast-grep --pattern 'func $_($$) HasColumn($_, $_) bool'

# Search for GetColumns implementation
ast-grep --pattern 'func $_($$) GetColumns($_)'

# Search for HasColumns implementation
ast-grep --pattern 'func $_($$) HasColumns($_, $_) bool'

Length of output: 166


Script:

#!/bin/bash
# Let's try a different approach using ripgrep to search for these method implementations

# Search for HasColumn implementation
echo "=== Searching for HasColumn implementation ==="
rg -l "HasColumn" --type go

# Search for GetColumns implementation
echo -e "\n=== Searching for GetColumns implementation ==="
rg -l "GetColumns" --type go

# Search for HasColumns implementation
echo -e "\n=== Searching for HasColumns implementation ==="
rg -l "HasColumns" --type go

# Let's also check the interface definition
echo -e "\n=== Checking Schema interface definition ==="
rg "type Schema interface" -A 10 --type go

Length of output: 1530


Script:

#!/bin/bash
# Let's check the CommonSchema and DriverSchema interfaces since they might contain these methods
echo "=== Checking CommonSchema interface ==="
rg "type CommonSchema interface" -A 15 --type go

echo -e "\n=== Checking DriverSchema interface ==="
rg "type DriverSchema interface" -A 15 --type go

# Let's also check if these methods are actually implemented somewhere
echo -e "\n=== Checking actual implementations ==="
rg "func.*HasColumn" -A 2 --type go
rg "func.*GetColumns" -A 2 --type go
rg "func.*HasColumns" -A 2 --type go

Length of output: 3261

database/gorm/to_sql_test.go (3)

23-23: Fix grammatical error in skip message

The current skip message has grammatical issues. Consider using one of these alternatives:

  • "Skipping tests that use Docker" (original)
  • "Skip tests using Docker"
-		t.Skip("Skip test that using Docker")
+		t.Skip("Skipping tests that use Docker")

30-33: Improve error handling for container initialization

The explicit readiness check is good, but we should also handle potential errors from container creation.

Consider adding error handling for container creation:

-	postgresDocker := docker.Postgres()
+	postgresDocker, err := docker.Postgres()
+	s.Require().NoError(err)
 	s.Require().NoError(postgresDocker.Ready())

30-33: Implementation aligns well with PR objectives

The refactored container setup supports the PR's goal of optimizing test execution by enabling container reuse. The separation of container creation and readiness check provides better control over the setup process.

Consider documenting the container reuse strategy in the test suite's comments to help other contributors understand the optimization approach.

foundation/application.go (1)

309-309: Consider documenting path resolution behavior.

Since the root path resolution is critical for container file management and affects the PR's goal of optimizing test performance, consider:

  1. Adding documentation about the expected behavior of env.CurrentAbsolutePath() in different environments (local dev, CI, tests)
  2. Including examples of how temporary container files will be resolved relative to the root path
  3. Documenting any environment-specific considerations for path resolution

This will help maintainers understand the implications of path resolution on container management.

foundation/application_test.go (1)

312-312: Fix grammatical issue in skip message

The current skip message has grammatical issues. Consider using one of these alternatives:

  • "Skip test that uses Docker"
  • "Skip test that is using Docker"
  • "Skipping test that uses Docker"
-		s.T().Skip("Skip test that using Docker")
+		s.T().Skip("Skip test that uses Docker")
database/migration/default_migrator_test.go (3)

Line range hint 56-86: Consider adding test cases for container reuse scenarios

While the existing test coverage is comprehensive, consider adding specific test cases to verify:

  1. Multiple test cases using the same container instance
  2. Database name uniqueness when reusing containers
  3. Cleanup of databases after tests

This would help validate the new container reuse functionality introduced in this PR.


Line range hint 644-668: Enhance error handling in mock implementations

Consider improving the error handling in the mock implementations by:

  1. Adding context to errors for better debugging
  2. Handling container-specific errors separately
  3. Adding cleanup mechanisms for failed operations

This would make test failures more informative and help with debugging container-related issues.


Based on the code analysis, I can now provide a final response:

Container lifecycle needs improvement for better reuse

The current implementation has some issues that could affect test performance:

  • Multiple Ready() checks are being performed on the same container instance
  • No explicit cleanup/teardown logic in TearDownTest()
  • Container is initialized in SetupTest() which runs before each test, potentially creating new containers unnecessarily

To optimize container reuse:

  • Move container initialization to SetupSuite()
  • Add proper cleanup in TearDownSuite()
  • Remove redundant Ready() checks
🔗 Analysis chain

Line range hint 1-900: Verify performance improvements from container reuse

The changes look good overall. To validate the performance improvements:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Compare test execution times before and after the changes

# Get the commit hash before these changes
git log -n 1 --format=%H -- database/migration/default_migrator_test.go

# Compare test execution times
# Note: This will help verify if the container reuse strategy improves performance
time go test -v ./database/migration/... -run TestDefaultMigratorWithDBSuite

Length of output: 300


Script:

#!/bin/bash
# Let's verify the container reuse implementation in a different way
# by checking the test structure and container lifecycle management

# Check for container reuse patterns in the test implementation
rg -A 5 -B 5 "SetupTest|TearDownTest" database/migration/default_migrator_test.go

# Look for Docker container management code
rg -A 3 "docker\." database/migration/default_migrator_test.go

# Check if there are any explicit container cleanup calls
rg "Ready\(\)|Stop\(\)|Close\(\)" database/migration/default_migrator_test.go

Length of output: 1104

testing/docker/database.go (1)

48-50: Enhance error message when database driver is not ready.

Including contextual information in the error message improves troubleshooting.

Apply this diff:

 if err = databaseDriver.Ready(); err != nil {
-	return nil, err
+	return nil, fmt.Errorf("database driver not ready: %w", err)
 }
support/docker/docker.go (1)

79-81: Correct typos in comments for better clarity

There are minor typos in the comments that can be corrected to improve readability and understanding.

Apply the following corrections:

	// Create new database in the exist docker container
+	// Create new databases in the existing Docker container

	// Sqlite should be a new database, so we can return it directly.
+	// For SQLite, we should create a new database, so we can return it directly.
support/docker/container_manager.go (1)

73-99: Remove or adjust verbose debugging statements

There are numerous color.Red().Printf statements used for debugging purposes throughout the code. In production code, excessive logging can clutter the output and may impact performance. Consider removing these statements or using a configurable logging mechanism that can be enabled or disabled based on the environment.

Apply this diff to remove the debug logs:

-	color.Red().Printf("Test-%s--Get: Ready to set lock, containerType: %v, tempfile: %s\n", carbon.Now().ToDateTimeString(), containerType, r.file)
-	color.Red().Printf("Test-%s--Get: get all containers, %+v\n", carbon.Now().ToDateTimeString(), containerTypeToDatabaseConfig)
-	color.Red().Printf("Test-%s--Get: filtered containers, databaseDriver: %+v, containerType: %v\n", carbon.Now().ToDateTimeString(), databaseDriver, containerType)
-	color.Red().Printfln("Test-%s--Get: driver is empty, going to create new container: %s", carbon.Now().ToDateTimeString(), database)
-	color.Red().Printf("Test-%s--Get: created a new container, databaseDriver: %+v, containerType: %v\n", carbon.Now().ToDateTimeString(), databaseDriver, containerType)
-	color.Red().Printf("Test-%s--Get: going to add the new container\n", carbon.Now().ToDateTimeString())
-	color.Red().Printf("Test-%s--add: get all containers: %+v, type: %v, databaseDriver: %+v\n", carbon.Now().ToDateTimeString(), containerTypeToDatabaseConfig, containerType, databaseDriver)
-	color.Red().Printf("Test-%s--add: new containers, type: %v, containerTypeToDatabaseConfig: %+v\n", carbon.Now().ToDateTimeString(), containerType, containerTypeToDatabaseConfig)
-	color.Red().Printf("Test-%s--unlock\n", carbon.Now().ToDateTimeString())

Alternatively, implement a logging system with log levels to control the output based on the environment (e.g., development or production).

Also applies to: 101-105, 121-131, 213-217

database/gorm/test_utils.go (2)

54-56: Enhance panic messages with contextual information for better debugging

Currently, when supportdocker.Ready fails, the code panics with a generic error message. Adding contextual information to the panic messages will aid in identifying which Docker container failed to initialize.

Apply the following changes:

 if err := supportdocker.Ready(postgresDockers...); err != nil {
-    panic(err)
+    panic(fmt.Sprintf("Failed to initialize Postgres dockers: %v", err))
 }

 if err := supportdocker.Ready(mysqlDockers...); err != nil {
-    panic(err)
+    panic(fmt.Sprintf("Failed to initialize MySQL dockers: %v", err))
 }

 if err := supportdocker.Ready(sqlserverDockers...); err != nil {
-    panic(err)
+    panic(fmt.Sprintf("Failed to initialize SQLServer dockers: %v", err))
 }

 if err := supportdocker.Ready(postgresDocker); err != nil {
-    panic(err)
+    panic(fmt.Sprintf("Failed to initialize Postgres docker: %v", err))
 }

 if err := supportdocker.Ready(mysqlDocker); err != nil {
-    panic(err)
+    panic(fmt.Sprintf("Failed to initialize MySQL docker: %v", err))
 }

 if err := supportdocker.Ready(sqlserverDocker); err != nil {
-    panic(err)
+    panic(fmt.Sprintf("Failed to initialize SQLServer docker: %v", err))
 }

Also applies to: 81-87, 113-115, 124-126, 137-141


272-280: Refactor ReadWrite methods to eliminate code duplication across mock drivers

The ReadWrite methods in MockMysql, MockPostgres, MockSqlite, and MockSqlserver share similar code structures for setting up mock configurations. Refactoring these methods by extracting the common logic into a shared helper function will reduce code duplication and enhance maintainability.

Also applies to: 343-350, 408-415, 471-478

database/gorm/query_test.go (9)

33-33: Consistency in Skip Message Formatting

Consider rephrasing the skip message for clarity and grammatical correctness. The current message "Skip test that using Docker" can be improved.

Apply this diff to update the skip message:

-    	t.Skip("Skip test that using Docker")
+    	t.Skip("Skipping test that uses Docker")

3547-3547: Avoid Shadowing Variables in Nested Functions

In the lambda function, the variable query is being used, which shadows the outer query variable. This can lead to confusion and potential bugs.

Apply this diff to rename the parameter:

-							return query.Where("name = ?", "with_book0").Select("id", "user_id", "name")
+							return q.Where("name = ?", "with_book0").Select("id", "user_id", "name")

And update the function signature accordingly:

With("Books", func(q contractsorm.Query) contractsorm.Query {
    // function body
})

3598-3598: Consistency in Skip Message Formatting

Similar to line 33, consider updating the skip message for grammatical correctness.

Apply this diff:

-	if env.IsWindows() {
-		t.Skip("Skip test that using Docker")
+	if env.IsWindows() {
+		t.Skip("Skipping test that uses Docker")

3602-3603: Provide Context in Error Messages

While using require.NoError, it's helpful to include a descriptive message to provide context in case of failure.

Update the assertion to include an error message:

-	require.NoError(t, postgresDocker.Ready())
+	require.NoError(t, postgresDocker.Ready(), "Failed to prepare PostgreSQL Docker container")

3640-3641: Stop All Docker Containers at the End of Tests

Ensure that all started Docker containers are stopped at the end of the test to prevent resource leaks.

Apply this diff to stop the PostgreSQL Docker container as well:

+	assert.NoError(t, postgresDocker.Stop())
 	assert.NoError(t, sqliteDocker.Stop())

3764-3764: Consistency in Skip Message Formatting

Once again, update the skip message for clarity.

-	if env.IsWindows() {
-		t.Skip("Skip test that using Docker")
+	if env.IsWindows() {
+		t.Skip("Skipping test that uses Docker")

3776-3778: Handle Errors Appropriately When Setting Up Tests

In TestReadWriteSeparate, ensure that any errors returned by QueryOfReadWrite are properly handled and provide informative error messages.

Update the error handling:

-	mixQuery, err = db["write"].QueryOfReadWrite(db["read"].Docker().Config())
+	mixQuery, err := db["write"].QueryOfReadWrite(db["read"].Docker().Config())
 	require.NoError(t, err, "Failed to create read-write query")

3810-3810: Consistency in Skip Message Formatting

Again, update the skip message for clarity.

-	if env.IsWindows() {
-		t.Skip("Skip test that using Docker")
+	if env.IsWindows() {
+		t.Skip("Skipping test that uses Docker")

3828-3831: Safely Stop Docker Containers in TearDown

When checking for nil, it's best practice to prevent potential nil pointer dereferences.

Apply this diff:

 if dbs[database.DriverSqlite] != nil {
-	assert.NoError(t, dbs[database.DriverSqlite].Docker().Stop())
+	if dbs[database.DriverSqlite].Docker() != nil {
+		assert.NoError(t, dbs[database.DriverSqlite].Docker().Stop())
+	}
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7b133e1 and 5edacb3.

⛔ Files ignored due to path filters (2)
  • mocks/testing/Database.go is excluded by !mocks/**
  • mocks/testing/DatabaseDriver.go is excluded by !mocks/**
📒 Files selected for processing (37)
  • .gitignore (0 hunks)
  • contracts/testing/testing.go (1 hunks)
  • database/factory/factory_test.go (1 hunks)
  • database/gorm/query_test.go (9 hunks)
  • database/gorm/test_utils.go (8 hunks)
  • database/gorm/to_sql_test.go (1 hunks)
  • database/migration/default_migrator_test.go (2 hunks)
  • database/migration/repository_test.go (1 hunks)
  • database/migration/sql_migrator_test.go (2 hunks)
  • database/orm/orm_test.go (2 hunks)
  • database/schema/common_schema_test.go (1 hunks)
  • database/schema/postgres_schema_test.go (1 hunks)
  • database/schema/schema_test.go (3 hunks)
  • foundation/application.go (2 hunks)
  • foundation/application_test.go (1 hunks)
  • foundation/path.go (0 hunks)
  • mail/application_test.go (1 hunks)
  • queue/application_test.go (1 hunks)
  • support/docker/container_manager.go (1 hunks)
  • support/docker/container_manager_test.go (1 hunks)
  • support/docker/docker.go (2 hunks)
  • support/docker/docker_test.go (3 hunks)
  • support/docker/mysql.go (4 hunks)
  • support/docker/mysql_test.go (2 hunks)
  • support/docker/postgres.go (5 hunks)
  • support/docker/postgres_test.go (3 hunks)
  • support/docker/redis_test.go (1 hunks)
  • support/docker/sqlite.go (1 hunks)
  • support/docker/sqlite_test.go (2 hunks)
  • support/docker/sqlserver.go (4 hunks)
  • support/docker/sqlserver_test.go (2 hunks)
  • support/docker/utils.go (2 hunks)
  • support/docker/utils_test.go (1 hunks)
  • support/env/env.go (3 hunks)
  • testing/docker/database.go (1 hunks)
  • testing/docker/database_test.go (5 hunks)
  • testing/docker/docker_test.go (4 hunks)
💤 Files with no reviewable changes (2)
  • .gitignore
  • foundation/path.go
✅ Files skipped from review due to trivial changes (4)
  • mail/application_test.go
  • queue/application_test.go
  • support/docker/redis_test.go
  • support/docker/utils_test.go
🔇 Additional comments (43)
database/schema/common_schema_test.go (1)

29-30: LGTM! Good addition of container readiness check

The added Docker readiness check is a crucial improvement that:

  1. Ensures the container is fully operational before running tests
  2. Helps prevent flaky tests due to container initialization timing
  3. Aligns with the PR's objective of optimizing container usage

The empty line after the check also improves code readability.

database/schema/postgres_schema_test.go (1)

32-33: LGTM! Good addition of container readiness check

The Docker readiness check is a crucial addition that ensures the container is properly initialized before test execution. This aligns well with the PR's objective of optimizing container management.

Let's verify consistent readiness checks across other test files:

✅ Verification successful

Docker readiness checks are consistently implemented across test files

The verification shows that all test files using Docker properly implement readiness checks after container initialization. The pattern is consistently followed in all locations:

  • All test suites use postgresDocker.Ready() immediately after container creation
  • Error handling is appropriately implemented using either Require().NoError() or NoError()
  • The only variation is in database/gorm/test_utils.go which uses a helper supportdocker.Ready(), but maintains the same error checking pattern
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if other test files properly implement Docker readiness checks
# Expected: Find other test files that use Docker and verify they have similar checks

# Search for test files using Docker
rg -l "docker\.Postgres\(\)" --type go | while read -r file; do
  echo "=== Checking $file ==="
  # Show context around Docker initialization to verify readiness checks
  rg -B 2 -A 2 "docker\.Postgres\(\)" "$file"
done

Length of output: 3614

contracts/testing/testing.go (3)

25-26: LGTM! Clear documentation improvement

The enhanced documentation clearly explains the Build method's behavior and its relationship with the Ready method, which helps prevent misuse.


32-33: Documentation position update looks good


38-39: Essential addition for container lifecycle management

The Ready method is a crucial addition that enables proper container state management. This separation of concerns between building and readiness checking is a good design pattern.

Let's verify that all implementations of DatabaseDriver properly implement this new method:

✅ Verification successful

The previous ast-grep pattern might have been too strict. Let's try a broader search to:

  1. Identify all DatabaseDriver implementations
  2. Find Ready method implementations with surrounding context

Ready method is properly implemented across all database drivers

The verification shows that the Ready method is correctly implemented in:

  • All database implementations (Postgres, MySQL, SQLite, SQLServer)
  • Mock implementations for testing
  • Each implementation follows a consistent pattern of checking connection status
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for Ready method implementations in database drivers
ast-grep --pattern 'func ($x *$type) Ready() error {
  $$$
}'

Length of output: 63


Script:

#!/bin/bash
# Let's first find all database driver implementations
rg -l "type.*DatabaseDriver" --type go

# Then search for Ready method implementations with more context
rg "func.*Ready\(\).*error" --type go -A 5

Length of output: 1724

support/docker/sqlite.go (4)

33-35: LGTM!

The Config implementation correctly returns the database configuration.


48-48: LGTM!

The Driver method correctly returns the SQLite driver type.


68-71: LGTM!

The Ready method correctly verifies database connectivity.


82-83: LGTM!

The connect method correctly establishes database connection with multi-statement support.

support/docker/utils.go (1)

20-31: Verify integration with container management system

Let's ensure the port management changes properly integrate with the container reuse mechanism described in the PR objectives.

Also applies to: 50-50

✅ Verification successful

Let me gather more context about the container management integration by checking the implementation details.


Let me check one more aspect to verify the port management integration.


Based on the gathered information, I can now provide the final response:

Port management is properly integrated with container reuse system

The port management implementation in isPortUsing is correctly integrated with the container management system:

  • The ContainerManager checks port availability before container reuse through isPortUsing(containerTypeToDatabaseConfig[containerType].Port)
  • Dynamic port allocation is handled by getValidPort() which ensures no port conflicts
  • The port configuration is properly persisted in DatabaseConfig and restored when reusing containers
  • Container creation properly manages port mappings and configurations across different database types (MySQL, Postgres, SQLServer)

The implementation ensures proper port management for both new and reused containers, supporting the PR's container reuse objectives.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for proper container port management across the codebase

# Look for container creation patterns
echo "Checking container creation patterns..."
rg -l "docker run.*-p" --type go

# Check for port conflict handling
echo "Checking port conflict handling..."
rg "net.Listen|getValidPort|isPortUsing" --type go

# Verify test setup patterns
echo "Checking test container setup..."
rg "func.*Test.*Container" --type go

Length of output: 1694


Script:

#!/bin/bash
# Check container manager implementation and port usage
echo "Container manager implementation:"
rg -A 5 "containerTypeToDatabaseConfig" support/docker/container_manager.go

echo "\nPort allocation in container creation:"
ast-grep --pattern 'func createContainer($$$) {
  $$$
}'

echo "\nContainer reuse logic:"
rg -A 10 "reuseContainer|getContainer" support/docker/container_manager.go

Length of output: 2755


Script:

#!/bin/bash
# Check port management in container creation and test setup
echo "Port management in utils.go:"
rg -A 10 "getValidPort" support/docker/utils.go

echo "\nContainer creation and port setup:"
rg -A 10 "func.*Create.*Container" --type go

echo "\nTest container configuration:"
rg -A 5 "DatabaseConfig|Port:" --type go

Length of output: 20691

support/docker/docker_test.go (3)

14-14: LGTM! Clear and concise skip message.


84-84: Verify handling of removed database parameters.

The Database function calls no longer include testDatabase, testUsername, and testPassword parameters.

#!/bin/bash
# Search for where these parameters are now handled
ast-grep --pattern 'func Database($$$) {
  $$$
}'

# Look for configuration or environment variable usage
rg -l "testDatabase|testUsername|testPassword" --type go

Also applies to: 87-87


91-95: Clarify SQLite-specific cleanup strategy.

While proper cleanup is implemented for SQLite drivers, it's unclear why similar cleanup isn't performed for other database types. This could lead to resource leaks.

✅ Verification successful

Based on the evidence gathered, I can now provide a final response:

SQLite cleanup in tests is appropriate and intentional

The SQLite-specific cleanup is correct because:

  1. Other database types (MySQL, PostgreSQL, SQLServer) use Docker containers that are automatically cleaned up by the Docker daemon
  2. Only SQLite creates actual files on the filesystem that need explicit cleanup
  3. The implementation shows all database types have Stop() methods, but calling them in tests is only necessary for SQLite to remove temporary files

This is verified by:

  • All database implementations having proper Stop() methods (from ripgrep results)
  • SQLite's unique implementation that removes files instead of stopping containers
  • Other databases using Docker containers that get cleaned up automatically
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for cleanup patterns in other database implementations
rg -A 5 "func.*Stop\(\)" --type go

# Look for other cleanup mechanisms
ast-grep --pattern 'driver.Stop($$$)'

Length of output: 3627


Script:

#!/bin/bash
# Let's examine the test file to understand the context better
cat support/docker/docker_test.go

Length of output: 2137


Script:

#!/bin/bash
# Let's examine the Database function to understand how containers are managed
cat support/docker/database.go

Length of output: 91

support/docker/mysql_test.go (2)

22-23: LGTM! Skip condition and message update looks good.

The updated skip condition and standardized skip message align well with the changes made across other test files.


72-74: Verify database isolation in the shared container.

The test for retrieving a new database driver is crucial for the container reuse feature. However, we should ensure proper database isolation.

Let's verify the isolation by checking if the test creates separate databases:

Consider adding additional test cases to verify:

  1. Concurrent access to different databases in the same container
  2. Data isolation between databases
  3. Cleanup of created databases after tests
✅ Verification successful

Based on the shell script results, I can now generate the final response:

Database isolation is properly implemented in the shared container setup

The codebase shows proper database isolation through:

  • Each database instance gets a unique name parameter via Database(name string) method
  • Separate database drivers are created for each database name
  • The implementation in mysql.go, postgres.go, and other drivers shows proper container reuse with isolated database instances
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the code properly isolates databases when sharing containers
# Expected: Find evidence of database name generation and isolation logic

# Look for database creation/isolation logic
rg -A 5 "Database\(" --type go

# Check for random/unique database name generation
ast-grep --pattern 'func $_(name string) (DatabaseDriver, error) {
  $$$
}'

Length of output: 15609

support/docker/postgres_test.go (1)

28-28: LGTM! Clear and consistent skip message.

The skip message follows the standardized format mentioned in the summary and clearly indicates why the test is being skipped.

support/docker/container_manager_test.go (2)

1-9: LGTM! Package structure and imports are well-organized.

The imports are appropriate for the testing requirements, including the necessary testing frameworks and environment utilities.


46-80: 🛠️ Refactor suggestion

Improve test data management and handle potential race conditions.

The test has several areas for improvement:

  1. Hardcoded values (port 5432, containerID "123456") should be defined as constants or test fixtures.
  2. Using a fixed port number could cause test failures if the port is already in use.
  3. Consider adding negative test cases (e.g., adding duplicate containers).

Suggested improvements:

+const (
+	testPort        = 5432
+	testContainerID = "123456"
+)
+
 func (s *ContainerManagerTestSuite) TestAddAndAll() {
-	port := 5432
-	containerID := "123456"
+	port := testPort
+	containerID := testContainerID

Let's verify if the port is commonly used in other tests:

support/env/env.go (1)

22-25: LGTM! Clean and standard implementations

The system property detection functions are well-implemented using the standard runtime package constants.

Also applies to: 49-53, 66-69

testing/docker/docker_test.go (2)

12-12: LGTM: Import added for environment detection

The added import is necessary for the new Windows environment check functionality.


54-54: Verify database cleanup strategy aligns with container reuse goal

The addition of database.Stop() calls might conflict with the PR's objective of reusing containers across tests. We need to verify that these Stop() calls only clean up the test database within the container rather than destroying the container itself.

Let's verify the implementation of the Stop() method:

Consider these architectural points:

  1. The container manager should handle container lifecycle
  2. Individual tests should only clean up their test databases
  3. Container shutdown should happen at the end of the entire test suite

Also applies to: 75-75

support/docker/postgres.go (3)

60-69: LGTM! Config structure is well-organized.

The Config method properly returns all necessary connection details.


121-128: LGTM! Connection check is well-implemented.

The Ready method effectively verifies database connectivity with proper resource cleanup.


Line range hint 44-58: LGTM! Verify container reuse functionality.

The Build method correctly initializes the container and handles errors appropriately.

Let's verify that containers are being reused across test runs:

✅ Verification successful

Container reuse is properly implemented, Build method is correct

The Build method in PostgresImpl works correctly with the container reuse mechanism implemented in ContainerManager. The ContainerManager handles container lifecycle by:

  • Caching container information in a temporary file
  • Reusing existing containers if their ports are still in use
  • Creating new containers with random database names when needed
  • Using file-based locking to prevent race conditions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for container reuse patterns in tests
# Look for test files that might use this postgres implementation
rg -l "NewPostgresImpl" --type go

# Check for potential container leaks - containers that might not be properly stopped
rg -B 2 -A 2 "docker stop" --type go

Length of output: 1459


Script:

#!/bin/bash
# Let's check the container manager implementation for reuse patterns
ast-grep --pattern 'func $_ ContainerManager {
  $$$
}'

# Check test files for container reuse patterns
rg -A 5 "NewPostgresImpl" support/docker/container_manager_test.go
rg -A 5 "NewPostgresImpl" testing/docker/database_test.go

# Check if there's a cleanup mechanism in tests
rg "defer.*Stop\(\)" --type go

Length of output: 605


Script:

#!/bin/bash
# Let's check the actual implementation of container reuse logic
rg -B 2 -A 5 "func.*Build\(\)" support/docker/postgres.go

# Check if there's any container caching/reuse mechanism
rg -l "container.*cache|reuse" --type go

# Check the container manager implementation
cat support/docker/container_manager.go

Length of output: 7301

support/docker/mysql.go (4)

13-13: LGTM!

The color package addition is appropriate for error logging in the async database creation process.


66-74: LGTM!

The addition of ContainerID to the config is well-structured and supports the container reuse strategy.


108-108: LGTM!

The Driver method correctly returns the MySQL driver type.


Line range hint 50-61: Verify container ID persistence across test runs.

The containerID storage is crucial for the container reuse strategy. Ensure it persists correctly across different test packages.

✅ Verification successful

Let me gather more information about how the containerID is being used and managed.


Let me check one more aspect about the container lifecycle management.


Based on the gathered information, I can now provide the final response:

Container ID persistence is properly implemented and managed

The containerID is:

  • Stored as a field in database driver structs (MySQL, PostgreSQL, SQLServer, Redis)
  • Properly assigned during container creation in the Build() method
  • Passed through DatabaseConfig for container management
  • Reused when creating new database instances via the Database() method
  • Properly handled during container cleanup via Stop() methods
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the containerID is being stored in a persistent location
rg -A 5 "containerID.*:=.*" 

Length of output: 1896


Script:

#!/bin/bash
# Check for container management and cleanup related code
ast-grep --pattern 'func $$$Stop($$$) {
  $$$
}'

# Check for container reuse logic
rg -B 3 -A 3 "containerID" --type go

Length of output: 11111


Script:

#!/bin/bash
# Check for container manager implementation and lifecycle management
rg -B 5 -A 5 "type ContainerManager" --type go

# Check for container cleanup/teardown logic
rg -B 3 -A 3 "func.*Teardown|func.*Cleanup" --type go

Length of output: 1437

support/docker/sqlserver.go (4)

Line range hint 42-56: LGTM! Build method implementation is solid.

The method properly handles container creation with appropriate error checking and port mapping.


58-67: LGTM! Config method now includes container tracking.

The addition of ContainerID in the config aligns with the PR's objective of container reuse across test cases.


108-116: LGTM! Ready check implementation is clean and efficient.

The Ready method effectively leverages the existing connect method which includes retry logic, making it robust for container readiness checking.


69-75: Implementation aligns perfectly with container reuse strategy.

The method enables multiple test databases to share the same container instance, which directly addresses the PR's goal of improving test performance.

✅ Verification successful

The search results show that the Database method is consistently implemented across all database drivers (MySQL, PostgreSQL, SQLServer, SQLite) and is being used correctly in their respective test files. The implementation follows the same pattern of sharing container details while allowing different database names. Let me verify the interface implementation to ensure complete consistency.


Implementation is correctly aligned with the DatabaseDriver interface and container reuse strategy

The verification confirms that:

  • The Database(name string) method is properly defined in the DatabaseDriver interface
  • All database implementations (MySQL, PostgreSQL, SQLServer, SQLite) correctly implement this method with consistent behavior
  • Test files demonstrate proper usage of the method for creating multiple database instances sharing the same container
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify that the Database method is used consistently across test files
rg -p "Database\([^)]+\)" --type go

Length of output: 2819


Script:

#!/bin/bash
# Check the DatabaseDriver interface definition and its implementations
ast-grep --pattern 'type DatabaseDriver interface {
  $$$
}'

Length of output: 1391

database/orm/orm_test.go (1)

63-67: Verify container reuse implementation

While this cleanup implementation is important, let's verify that the container reuse logic exists to fulfill the PR's objective of optimizing test speed.

database/factory/factory_test.go (1)

105-108: LGTM! Well-structured container initialization

The explicit readiness check before query creation is a good practice that aligns with the PR's objective to optimize database container management. This approach ensures the container is fully ready before proceeding with tests, preventing potential race conditions.

testing/docker/database_test.go (4)

26-28: LGTM: Good practice to skip Docker tests on Windows

The addition of the Windows environment check is a good practice to prevent test failures in environments where Docker might not be available or behave differently.


147-147: LGTM: Consistent skip message

The skip message format is consistent with other similar checks in the file.


163-163: LGTM: Important cleanup in error path

Excellent addition of cleanup in the error path. This prevents resource leaks by ensuring the database is properly stopped even when the build fails.


48-51: LGTM: Test structure simplified while maintaining coverage

The test case structure has been streamlined to focus on essential validations while still maintaining comprehensive coverage across different database types.

✅ Verification successful

Based on the git diff output showing test files, I can see that these are test case additions and improvements across various packages. The changes are focused on test coverage and do not indicate any issues with the test structure changes in testing/docker/database_test.go. The test case structure has been simplified while maintaining comprehensive test coverage.

Test structure changes are well-tested and maintain coverage

The test case structure changes are accompanied by extensive test coverage across different database types and scenarios, as evidenced by the numerous test cases added in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify test coverage hasn't decreased
# Look for any removed test assertions in git history
git log -p HEAD^..HEAD | grep -B5 -A5 'assert\.'

Length of output: 235337

database/schema/schema_test.go (1)

31-31: LGTM! Good practice to ensure Docker readiness.

Adding a readiness check for PostgreSQL Docker instance is a good practice that aligns with the PR objectives of optimizing container management.

foundation/application.go (2)

18-18: LGTM: Import aligns with centralization of path utilities.

The addition of the env package import supports the centralization of path-related functionality, improving code organization.


309-309: Verify path resolution behavior across environments.

The switch to env.CurrentAbsolutePath() is part of centralizing path resolution logic. Since this affects the core application root path, which is critical for various operations including container management, we should verify its behavior across different environments.

✅ Verification successful

Let me analyze the results and generate additional verification scripts to understand the implementation of env.CurrentAbsolutePath().


Based on the results, I can now provide a final response as we have sufficient information about the path resolution implementation.

Path resolution behavior is properly handled across environments

The implementation in env.CurrentAbsolutePath() has appropriate handling for different execution contexts:

  • Uses os.Executable() as the primary source for path resolution
  • Falls back to os.Getwd() for special cases:
    • Testing environments
    • Air live reload
    • Direct go run execution
  • Resolves symlinks correctly using filepath.EvalSymlinks

The behavior is consistent with the framework's needs and properly handles various execution environments. The change is safe.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of RootPath in the codebase to ensure compatibility

# Check for direct RootPath usage
echo "Checking direct RootPath usage..."
rg "support\.RootPath" -B 2 -A 2

# Check for ExecutablePath method usage which depends on RootPath
echo "Checking ExecutablePath usage..."
rg "ExecutablePath" -B 2 -A 2

# Look for potential test files that might be affected
echo "Checking test files that might use paths..."
fd -e test.go | xargs rg "RootPath|ExecutablePath" -l

Length of output: 5355


Script:

#!/bin/bash
# Check the implementation of CurrentAbsolutePath
echo "Checking CurrentAbsolutePath implementation..."
rg "CurrentAbsolutePath" -B 5 -A 5

# Check test coverage for path resolution
echo "Checking path resolution tests..."
rg "TestCurrentAbsolutePath|TestRootPath" -B 2 -A 5

# Check for any environment-specific path handling
echo "Checking environment-specific path handling..."
rg "os\.(Getwd|Executable)" -B 2 -A 2

Length of output: 5266

foundation/application_test.go (1)

316-317: LGTM! Important readiness check added

Good addition of the Docker readiness check. This ensures the database container is properly initialized before proceeding with the test, which is crucial for the new container reuse strategy.

database/migration/default_migrator_test.go (1)

38-38: LGTM: Container readiness check is properly implemented

The addition of the container readiness check aligns with the PR objectives to optimize container usage during tests. This ensures that the database container is fully operational before proceeding with the tests.

Also applies to: 47-48

support/docker/sqlite.go Outdated Show resolved Hide resolved
support/docker/sqlite.go Outdated Show resolved Hide resolved
support/docker/sqlite_test.go Show resolved Hide resolved
support/docker/utils.go Show resolved Hide resolved
support/docker/sqlserver_test.go Show resolved Hide resolved
support/docker/container_manager.go Show resolved Hide resolved
support/docker/container_manager.go Outdated Show resolved Hide resolved
support/docker/container_manager.go Show resolved Hide resolved
database/gorm/query_test.go Show resolved Hide resolved
database/gorm/query_test.go Show resolved Hide resolved
Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (4)
support/docker/sqlite.go (3)

38-45: Enhance error handling in Database method

The error handling could be more specific to help with debugging.

Consider this improvement:

 func (r *SqliteImpl) Database(name string) (testing.DatabaseDriver, error) {
 	sqliteImpl := NewSqliteImpl(name)
 	if err := sqliteImpl.Build(); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to build SQLite database '%s': %v", name, err)
 	}
 
 	return sqliteImpl, nil
 }

51-56: Enhance error handling in Fresh method

The error handling could be more specific for the Stop() error.

Consider this improvement:

 func (r *SqliteImpl) Fresh() error {
 	if err := r.Stop(); err != nil {
-		return err
+		return fmt.Errorf("failed to stop SQLite database during fresh: %v", err)
 	}
 
 	if _, err := r.connect(); err != nil {
 		return fmt.Errorf("connect Sqlite error when freshing: %v", err)
 	}
 
 	return nil
 }

63-64: Consider removing unnecessary Image method

The Image method is unnecessary for SQLite implementation as it doesn't use Docker containers. This appears to be technical debt from implementing a common interface with other database drivers that do use Docker.

Consider:

  1. Splitting the interface into DatabaseDriver and ContainerizedDatabaseDriver
  2. Moving Docker-specific methods like Image to ContainerizedDatabaseDriver
  3. Having SQLite implement only the base DatabaseDriver interface

This would make the architecture cleaner and more aligned with the actual requirements of each database type.

support/env/env.go (1)

11-20: Consider making the path detection more robust

The current implementation has a few potential issues:

  1. The hardcoded path "/storage/temp" might not work consistently across different platforms
  2. Using string contains for path comparison could lead to false positives

Consider this more robust implementation:

 func IsAir() bool {
 	for _, arg := range os.Args {
-		if strings.Contains(filepath.ToSlash(arg), "/storage/temp") {
+		normalized := filepath.ToSlash(arg)
+		// Air typically uses a temp directory with a specific pattern
+		if strings.Contains(normalized, "/storage/temp") || 
+		   strings.Contains(normalized, "tmp/air") {
 			return true
 		}
 	}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5edacb3 and 4692896.

📒 Files selected for processing (4)
  • support/docker/container_manager.go (1 hunks)
  • support/docker/sqlite.go (1 hunks)
  • support/docker/sqlite_test.go (2 hunks)
  • support/env/env.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • support/docker/container_manager.go
  • support/docker/sqlite_test.go
🔇 Additional comments (2)
support/docker/sqlite.go (1)

66-69: LGTM! Implementation aligns with PR objectives

The Ready method correctly implements the readiness check by attempting a connection, which aligns with the PR's goal of ensuring database availability before tests.

support/env/env.go (1)

88-105: 🛠️ Refactor suggestion

Critical: Improve error handling and add context

The current implementation has critical issues that were partially addressed in previous reviews. Additionally:

  1. The special handling for test/Air/direct run environments needs documentation explaining the rationale
  2. The error handling needs to be consistent across all code paths

The error handling issues were previously flagged. Please refer to the existing review comments for the suggested fixes.

Add documentation explaining the environment-specific behavior:

+// CurrentAbsolutePath returns the absolute path of the current executable.
+// In test, Air, or direct run environments, it returns the working directory instead
+// of the executable path. This is necessary because:
+// - In test environments: The executable is in a temporary test directory
+// - In Air: The executable is in Air's temporary directory
+// - In direct run: The executable is in Go's build cache
+// This ensures that file paths are resolved relative to the project root in these environments.
 func CurrentAbsolutePath() string {

support/env/env.go Show resolved Hide resolved
@hwbrzzl hwbrzzl merged commit 197dd26 into master Nov 17, 2024
11 of 13 checks passed
@hwbrzzl hwbrzzl deleted the bowen/#519 branch November 17, 2024 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant