diff --git a/modules/mysql/mysql.go b/modules/mysql/mysql.go index c2e10efde7..c6b2822a67 100644 --- a/modules/mysql/mysql.go +++ b/modules/mysql/mysql.go @@ -52,53 +52,69 @@ func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomize // Run creates an instance of the MySQL container type func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*MySQLContainer, error) { - req := testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"3306/tcp", "33060/tcp"}, - Env: map[string]string{ + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("3306/tcp", "33060/tcp"), + testcontainers.WithEnv(map[string]string{ "MYSQL_USER": defaultUser, "MYSQL_PASSWORD": defaultPassword, "MYSQL_DATABASE": defaultDatabaseName, - }, - WaitingFor: wait.ForLog("port: 3306 MySQL Community Server"), + }), + testcontainers.WithWaitStrategy(wait.ForLog("port: 3306 MySQL Community Server")), } - genericContainerReq := testcontainers.GenericContainerRequest{ - ContainerRequest: req, - Started: true, - } - - opts = append(opts, WithDefaultCredentials()) + moduleOpts = append(moduleOpts, opts...) + moduleOpts = append(moduleOpts, WithDefaultCredentials()) - for _, opt := range opts { - if err := opt.Customize(&genericContainerReq); err != nil { - return nil, err + // Validate credentials after applying all options + validateCreds := func(req *testcontainers.GenericContainerRequest) error { + username, ok := req.Env["MYSQL_USER"] + if !ok { + username = rootUser } - } + password := req.Env["MYSQL_PASSWORD"] - username, ok := req.Env["MYSQL_USER"] - if !ok { - username = rootUser + if len(password) == 0 && password == "" && !strings.EqualFold(rootUser, username) { + return errors.New("empty password can be used only with the root user") + } + return nil } - password := req.Env["MYSQL_PASSWORD"] - if len(password) == 0 && password == "" && !strings.EqualFold(rootUser, username) { - return nil, errors.New("empty password can be used only with the root user") - } + moduleOpts = append(moduleOpts, testcontainers.CustomizeRequestOption(validateCreds)) - container, err := testcontainers.GenericContainer(ctx, genericContainerReq) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *MySQLContainer - if container != nil { + if ctr != nil { c = &MySQLContainer{ - Container: container, - password: password, - username: username, - database: req.Env["MYSQL_DATABASE"], + Container: ctr, + username: rootUser, // default to root, will be overridden if MYSQL_USER is set } } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run mysql: %w", err) + } + + // Retrieve credentials from container environment + inspect, err := ctr.Inspect(ctx) + if err != nil { + return c, fmt.Errorf("inspect mysql: %w", err) + } + + var foundUser, foundPass, foundDB bool + for _, env := range inspect.Config.Env { + if v, ok := strings.CutPrefix(env, "MYSQL_USER="); ok { + c.username, foundUser = v, true + } + if v, ok := strings.CutPrefix(env, "MYSQL_PASSWORD="); ok { + c.password, foundPass = v, true + } + if v, ok := strings.CutPrefix(env, "MYSQL_DATABASE="); ok { + c.database, foundDB = v, true + } + + if foundUser && foundPass && foundDB { + break + } } return c, nil diff --git a/modules/mysql/mysql_test.go b/modules/mysql/mysql_test.go index 364f2a97a8..758ed600da 100644 --- a/modules/mysql/mysql_test.go +++ b/modules/mysql/mysql_test.go @@ -54,7 +54,7 @@ func TestMySQLWithNonRootUserAndEmptyPassword(t *testing.T) { mysql.WithUsername("test"), mysql.WithPassword("")) testcontainers.CleanupContainer(t, ctr) - require.EqualError(t, err, "empty password can be used only with the root user") + require.ErrorContains(t, err, "empty password can be used only with the root user") } func TestMySQLWithRootUserAndEmptyPassword(t *testing.T) {