Repository: supabase/cli
Pull request #1261 (2023-06-28 21:20:00)

fix: db start should apply internal migrations
## What kind of change does this PR introduce?

Bug fix https://github.com/supabase/cli/issues/1255

## What is the new behavior?

Unifies the way database is setup between supabase start, db start, and db diff.

## Additional context

Add any other context or screenshots.


coveralls: ## Pull Request Test Coverage Report for [Build 5406733784](https://coveralls.io/builds/61030343)

* **48** of **48**   **(100.0%)**  changed or added relevant lines in **3** files are covered.
* **7** unchanged lines in **1** file lost coverage.
* Overall coverage increased (+**0.07%**) to **61.814%**

---


|  Files with Coverage Reduction | New Missed Lines | % |
| :-----|--------------|--: |
| [internal/gen/keys/keys.go](https://coveralls.io/builds/61030343/source?filename=internal%2Fgen%2Fkeys%2Fkeys.go#L94) | 7 | 7.94% |
<!-- | **Total:** | **7** |  | -->

|  Totals | [![Coverage Status](https://coveralls.io/builds/61030343/badge)](https://coveralls.io/builds/61030343) |
| :-- | --: |
| Change from base [Build 5400236630](https://coveralls.io/builds/61012702): |  0.07% |
| Covered Lines: | 4743 |
| Relevant Lines: | 7673 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/internal/db/diff/migra.go b/internal/db/diff/migra.go
index 3afd6dc5..90ab8c26 100644
--- a/internal/db/diff/migra.go
+++ b/internal/db/diff/migra.go
@@ -141,64 +141,10 @@ func MigrateShadowDatabaseVersions(ctx context.Context, container string, migrat
 		return err
 	}
 	defer conn.Close(context.Background())
-	if utils.Config.Db.MajorVersion <= 14 {
-		if err := initShadow14(ctx, conn, fsys); err != nil {
-			return err
-		}
-	} else {
-		if err := initShadow15(ctx, conn, container[:12], fsys); err != nil {
-			return err
-		}
-	}
-	return apply.MigrateUp(ctx, conn, migrations, fsys)
-}
-
-func initShadow14(ctx context.Context, conn *pgx.Conn, fsys afero.Fs) error {
-	if err := apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.GlobalsSql)); err != nil {
+	if err := start.SetupDatabase(ctx, conn, container[:12], os.Stderr, fsys); err != nil {
 		return err
 	}
-	if roles, err := fsys.Open(utils.CustomRolesPath); err == nil {
-		if err := apply.BatchExecDDL(ctx, conn, roles); err != nil {
-			return err
-		}
-	} else if !errors.Is(err, os.ErrNotExist) {
-		return err
-	}
-	return apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.InitialSchemaSql))
-}
-
-func initShadow15(ctx context.Context, conn *pgx.Conn, shadowHost string, fsys afero.Fs) error {
-	// Apply service migrations
-	if err := utils.DockerRunOnceWithStream(ctx, utils.StorageImage, []string{
-		"ANON_KEY=" + utils.Config.Auth.AnonKey,
-		"SERVICE_KEY=" + utils.Config.Auth.ServiceRoleKey,
-		"PGRST_JWT_SECRET=" + utils.Config.Auth.JwtSecret,
-		fmt.Sprintf("DATABASE_URL=postgresql://supabase_storage_admin:%s@%s:5432/postgres", utils.Config.Db.Password, shadowHost),
-		fmt.Sprintf("FILE_SIZE_LIMIT=%v", utils.Config.Storage.FileSizeLimit),
-		"STORAGE_BACKEND=file",
-		"TENANT_ID=stub",
-		// TODO: https://github.com/supabase/storage-api/issues/55
-		"REGION=stub",
-		"GLOBAL_S3_BUCKET=stub",
-	}, []string{"node", "dist/scripts/migrate-call.js"}, io.Discard, os.Stderr); err != nil {
-		return err
-	}
-	if err := utils.DockerRunOnceWithStream(ctx, utils.GotrueImage, []string{
-		"GOTRUE_LOG_LEVEL=error",
-		"GOTRUE_DB_DRIVER=postgres",
-		fmt.Sprintf("GOTRUE_DB_DATABASE_URL=postgresql://supabase_auth_admin:%s@%s:5432/postgres", utils.Config.Db.Password, shadowHost),
-		"GOTRUE_SITE_URL=" + utils.Config.Auth.SiteUrl,
-		"GOTRUE_JWT_SECRET=" + utils.Config.Auth.JwtSecret,
-	}, []string{"gotrue", "migrate"}, io.Discard, os.Stderr); err != nil {
-		return err
-	}
-	// Apply user migrations
-	if roles, err := fsys.Open(utils.CustomRolesPath); err == nil {
-		return apply.BatchExecDDL(ctx, conn, roles)
-	} else if !errors.Is(err, os.ErrNotExist) {
-		return err
-	}
-	return nil
+	return apply.MigrateUp(ctx, conn, migrations, fsys)
 }
 
 // Diffs local database schema against shadow, dumps output to stdout.
diff --git a/internal/db/start/start.go b/internal/db/start/start.go
index 74610ccf..38f52c83 100644
--- a/internal/db/start/start.go
+++ b/internal/db/start/start.go
@@ -73,8 +73,6 @@ EOF
 	return config
 }
 
-var noBackupVolume bool = true
-
 func StartDatabase(ctx context.Context, fsys afero.Fs, w io.Writer, options ...func(*pgx.ConnConfig)) error {
 	config := NewContainerConfig()
 	hostPort := strconv.FormatUint(uint64(utils.Config.Db.Port), 10)
@@ -93,7 +91,7 @@ func StartDatabase(ctx context.Context, fsys afero.Fs, w io.Writer, options ...f
 	}
 	// Creating volume will not override existing volume, so we must inspect explicitly
 	_, err := utils.Docker.VolumeInspect(ctx, utils.DbId)
-	noBackupVolume = client.IsErrNotFound(err)
+	noBackupVolume := client.IsErrNotFound(err)
 	if noBackupVolume {
 		fmt.Fprintln(w, "Starting database...")
 	} else {
@@ -106,8 +104,8 @@ func StartDatabase(ctx context.Context, fsys afero.Fs, w io.Writer, options ...f
 		fmt.Fprintln(os.Stderr, "Database is not healthy.")
 	}
 	// Initialise if we are on PG14 and there's no existing db volume
-	if noBackupVolume && utils.Config.Db.MajorVersion <= 14 {
-		if err := initDatabase(ctx, w, options...); err != nil {
+	if noBackupVolume {
+		if err := setupDatabase(ctx, fsys, w, options...); err != nil {
 			return err
 		}
 	}
@@ -137,39 +135,68 @@ func initCurrentBranch(fsys afero.Fs) error {
 	return afero.WriteFile(fsys, utils.CurrBranchPath, []byte("main"), 0644)
 }
 
-func initDatabase(ctx context.Context, w io.Writer, options ...func(*pgx.ConnConfig)) error {
-	// Initialise globals
-	conn, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{}, options...)
-	if err != nil {
-		return err
-	}
-	defer conn.Close(context.Background())
+func initSchema(ctx context.Context, conn *pgx.Conn, host string, w io.Writer) error {
 	fmt.Fprintln(w, "Setting up initial schema...")
+	if utils.Config.Db.MajorVersion <= 14 {
+		return initSchema14(ctx, conn)
+	}
+	return initSchema15(ctx, host)
+}
+
+func initSchema14(ctx context.Context, conn *pgx.Conn) error {
 	if err := apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.GlobalsSql)); err != nil {
 		return err
 	}
 	return apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.InitialSchemaSql))
 }
 
-func SetupDatabase(ctx context.Context, dbConfig pgconn.Config, fsys afero.Fs, w io.Writer, options ...func(*pgx.ConnConfig)) error {
-	if !noBackupVolume {
-		return nil
-	}
-	if dbConfig.Host != utils.DbId {
-		return nil
+func initSchema15(ctx context.Context, host string) error {
+	// Apply service migrations
+	if err := utils.DockerRunOnceWithStream(ctx, utils.StorageImage, []string{
+		"ANON_KEY=" + utils.Config.Auth.AnonKey,
+		"SERVICE_KEY=" + utils.Config.Auth.ServiceRoleKey,
+		"PGRST_JWT_SECRET=" + utils.Config.Auth.JwtSecret,
+		fmt.Sprintf("DATABASE_URL=postgresql://supabase_storage_admin:%s@%s:5432/postgres", utils.Config.Db.Password, host),
+		fmt.Sprintf("FILE_SIZE_LIMIT=%v", utils.Config.Storage.FileSizeLimit),
+		"STORAGE_BACKEND=file",
+		"TENANT_ID=stub",
+		// TODO: https://github.com/supabase/storage-api/issues/55
+		"REGION=stub",
+		"GLOBAL_S3_BUCKET=stub",
+	}, []string{"node", "dist/scripts/migrate-call.js"}, io.Discard, os.Stderr); err != nil {
+		return err
 	}
+	return utils.DockerRunOnceWithStream(ctx, utils.GotrueImage, []string{
+		"GOTRUE_LOG_LEVEL=error",
+		"GOTRUE_DB_DRIVER=postgres",
+		fmt.Sprintf("GOTRUE_DB_DATABASE_URL=postgresql://supabase_auth_admin:%s@%s:5432/postgres", utils.Config.Db.Password, host),
+		"GOTRUE_SITE_URL=" + utils.Config.Auth.SiteUrl,
+		"GOTRUE_JWT_SECRET=" + utils.Config.Auth.JwtSecret,
+	}, []string{"gotrue", "migrate"}, io.Discard, os.Stderr)
+}
+
+func setupDatabase(ctx context.Context, fsys afero.Fs, w io.Writer, options ...func(*pgx.ConnConfig)) error {
 	conn, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{}, options...)
 	if err != nil {
 		return err
 	}
 	defer conn.Close(context.Background())
-	if roles, err := fsys.Open(utils.CustomRolesPath); err == nil {
-		fmt.Fprintln(w, "Creating custom roles "+utils.Bold(utils.CustomRolesPath)+"...")
-		if err := apply.BatchExecDDL(ctx, conn, roles); err != nil {
-			return err
-		}
-	} else if !errors.Is(err, os.ErrNotExist) {
+	if err := SetupDatabase(ctx, conn, utils.DbId, w, fsys); err != nil {
 		return err
 	}
 	return reset.InitialiseDatabase(ctx, conn, fsys)
 }
+
+func SetupDatabase(ctx context.Context, conn *pgx.Conn, host string, w io.Writer, fsys afero.Fs) error {
+	if err := initSchema(ctx, conn, host, w); err != nil {
+		return err
+	}
+	roles, err := fsys.Open(utils.CustomRolesPath)
+	if errors.Is(err, os.ErrNotExist) {
+		return nil
+	} else if err != nil {
+		return err
+	}
+	fmt.Fprintln(w, "Creating custom roles "+utils.Bold(utils.CustomRolesPath)+"...")
+	return apply.BatchExecDDL(ctx, conn, roles)
+}
diff --git a/internal/start/start.go b/internal/start/start.go
index 38dc6ee5..1cbf25c2 100644
--- a/internal/start/start.go
+++ b/internal/start/start.go
@@ -646,12 +646,7 @@ EOF
 		started = append(started, utils.StudioId)
 	}
 
-	if err := waitForServiceReady(ctx, started); err != nil {
-		return err
-	}
-
-	// Setup database after all services are up
-	return start.SetupDatabase(ctx, dbConfig, fsys, os.Stderr, options...)
+	return waitForServiceReady(ctx, started)
 }
 
 func isContainerExcluded(imageName string, excluded map[string]bool) bool {


Test patch:
diff --git a/internal/db/diff/migra_test.go b/internal/db/diff/migra_test.go
index 02b9e147..452a92db 100644
--- a/internal/db/diff/migra_test.go
+++ b/internal/db/diff/migra_test.go
@@ -137,6 +137,40 @@ func TestRunMigra(t *testing.T) {
 func TestMigrateShadow(t *testing.T) {
 	utils.Config.Db.MajorVersion = 14
 
+	t.Run("migrates shadow database", func(t *testing.T) {
+		utils.Config.Db.ShadowPort = 54320
+		utils.GlobalsSql = "create schema public"
+		utils.InitialSchemaSql = "create schema private"
+		// Setup in-memory fs
+		fsys := afero.NewMemMapFs()
+		path := filepath.Join(utils.MigrationsDir, "0_test.sql")
+		sql := "create schema test"
+		require.NoError(t, afero.WriteFile(fsys, path, []byte(sql), 0644))
+		// Setup mock postgres
+		conn := pgtest.NewConn()
+		defer conn.Close(t)
+		conn.Query(utils.GlobalsSql).
+			Reply("CREATE SCHEMA").
+			Query(utils.InitialSchemaSql).
+			Reply("CREATE SCHEMA").
+			Query(repair.CREATE_VERSION_SCHEMA).
+			Reply("CREATE SCHEMA").
+			Query(repair.CREATE_VERSION_TABLE).
+			Reply("CREATE TABLE").
+			Query(repair.ADD_STATEMENTS_COLUMN).
+			Reply("ALTER TABLE").
+			Query(repair.ADD_NAME_COLUMN).
+			Reply("ALTER TABLE").
+			Query(sql).
+			Reply("CREATE SCHEMA").
+			Query(repair.INSERT_MIGRATION_VERSION, "0", "test", fmt.Sprintf("{%s}", sql)).
+			Reply("INSERT 0 1")
+		// Run test
+		err := MigrateShadowDatabase(context.Background(), "test-shadow-db", fsys, conn.Intercept)
+		// Check error
+		assert.NoError(t, err)
+	})
+
 	t.Run("throws error on timeout", func(t *testing.T) {
 		utils.Config.Db.ShadowPort = 54320
 		// Setup in-memory fs
@@ -150,37 +184,27 @@ func TestMigrateShadow(t *testing.T) {
 		assert.ErrorContains(t, err, "operation was canceled")
 	})
 
-	t.Run("throws error on globals schema", func(t *testing.T) {
-		utils.Config.Db.ShadowPort = 54320
-		utils.GlobalsSql = "create schema public"
+	t.Run("throws error on permission denied", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
-		// Setup mock postgres
-		conn := pgtest.NewConn()
-		defer conn.Close(t)
-		conn.Query(utils.GlobalsSql).
-			ReplyError(pgerrcode.DuplicateSchema, `schema "public" already exists`)
+		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
 		// Run test
-		err := MigrateShadowDatabase(context.Background(), "", fsys, conn.Intercept)
+		err := MigrateShadowDatabase(context.Background(), "", fsys)
 		// Check error
-		assert.ErrorContains(t, err, `ERROR: schema "public" already exists (SQLSTATE 42P06)`)
+		assert.ErrorIs(t, err, os.ErrPermission)
 	})
 
-	t.Run("throws error on initial schema", func(t *testing.T) {
+	t.Run("throws error on globals schema", func(t *testing.T) {
 		utils.Config.Db.ShadowPort = 54320
 		utils.GlobalsSql = "create schema public"
-		utils.InitialSchemaSql = "create schema private"
 		// Setup in-memory fs
 		fsys := afero.NewMemMapFs()
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
 		conn.Query(utils.GlobalsSql).
-			Reply("CREATE SCHEMA").
-			Query(utils.InitialSchemaSql).
 			ReplyError(pgerrcode.DuplicateSchema, `schema "public" already exists`)
 		// Run test
-		err := MigrateShadowDatabase(context.Background(), "", fsys, conn.Intercept)
+		err := MigrateShadowDatabase(context.Background(), "test-shadow-db", fsys, conn.Intercept)
 		// Check error
 		assert.ErrorContains(t, err, `ERROR: schema "public" already exists (SQLSTATE 42P06)`)
 	})
diff --git a/internal/db/start/start_test.go b/internal/db/start/start_test.go
index d0bd0367..f8c9a5e8 100644
--- a/internal/db/start/start_test.go
+++ b/internal/db/start/start_test.go
@@ -10,8 +10,6 @@ import (
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/volume"
-	"github.com/jackc/pgconn"
-	"github.com/jackc/pgerrcode"
 	"github.com/spf13/afero"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -51,30 +49,6 @@ func TestInitBranch(t *testing.T) {
 	})
 }
 
-func TestInitDatabase(t *testing.T) {
-	t.Run("throws error on connect failure", func(t *testing.T) {
-		utils.Config.Db.Port = 0
-		// Run test
-		err := initDatabase(context.Background(), io.Discard)
-		// Check error
-		assert.ErrorContains(t, err, "invalid port (outside range)")
-	})
-
-	t.Run("throws error on exec failure", func(t *testing.T) {
-		utils.Config.Db.Port = 5432
-		utils.GlobalsSql = "create role postgres"
-		// Setup mock postgres
-		conn := pgtest.NewConn()
-		defer conn.Close(t)
-		conn.Query(utils.GlobalsSql).
-			ReplyError(pgerrcode.DuplicateObject, `role "postgres" already exists`)
-		// Run test
-		err := initDatabase(context.Background(), io.Discard, conn.Intercept)
-		// Check error
-		assert.ErrorContains(t, err, `ERROR: role "postgres" already exists (SQLSTATE 42710)`)
-	})
-}
-
 func TestStartDatabase(t *testing.T) {
 	teardown := func() {
 		utils.Containers = []string{}
@@ -90,6 +64,10 @@ func TestStartDatabase(t *testing.T) {
 		utils.Config.Db.Port = 5432
 		// Setup in-memory fs
 		fsys := afero.NewMemMapFs()
+		roles := "create role test"
+		require.NoError(t, afero.WriteFile(fsys, utils.CustomRolesPath, []byte(roles), 0644))
+		seed := "INSERT INTO employees(name) VALUES ('Alice')"
+		require.NoError(t, afero.WriteFile(fsys, utils.SeedDataPath, []byte(seed), 0644))
 		// Setup mock docker
 		require.NoError(t, apitest.MockDocker(utils.Docker))
 		defer gock.OffAll()
@@ -107,8 +85,19 @@ func TestStartDatabase(t *testing.T) {
 					Health:  &types.Health{Status: "healthy"},
 				},
 			}})
+		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.GotrueImage), "test-auth")
+		require.NoError(t, apitest.MockDockerLogs(utils.Docker, "test-auth", ""))
+		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.StorageImage), "test-storage")
+		require.NoError(t, apitest.MockDockerLogs(utils.Docker, "test-storage", ""))
+		// Setup mock postgres
+		conn := pgtest.NewConn()
+		defer conn.Close(t)
+		conn.Query(roles).
+			Reply("CREATE ROLE").
+			Query(seed).
+			Reply("INSERT 0 1")
 		// Run test
-		err := StartDatabase(context.Background(), fsys, io.Discard)
+		err := StartDatabase(context.Background(), fsys, io.Discard, conn.Intercept)
 		// Check error
 		assert.NoError(t, err)
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -121,8 +110,10 @@ func TestStartDatabase(t *testing.T) {
 	t.Run("recover from backup volume", func(t *testing.T) {
 		defer teardown()
 		utils.DbImage = utils.Pg15Image
-		utils.Config.Db.MajorVersion = 15
+		utils.Config.Db.MajorVersion = 14
 		utils.DbId = "supabase_db_test"
+		utils.ConfigId = "supabase_config_test"
+		utils.Config.Db.Port = 5432
 		// Setup in-memory fs
 		fsys := afero.NewMemMapFs()
 		// Setup mock docker
@@ -214,13 +205,13 @@ func TestStartCommand(t *testing.T) {
 		// Setup mock docker
 		require.NoError(t, apitest.MockDocker(utils.Docker))
 		defer gock.OffAll()
-		gock.New("http:///var/run/docker.sock").
+		gock.New(utils.Docker.DaemonHost()).
 			Head("/_ping").
 			Reply(http.StatusOK).
 			SetHeader("API-Version", utils.Docker.ClientVersion()).
 			SetHeader("OSType", "linux")
 		gock.New(utils.Docker.DaemonHost()).
-			Get("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId + "/json").
+			Get("/v" + utils.Docker.ClientVersion() + "/containers/").
 			Reply(http.StatusOK).
 			JSON(types.ContainerJSON{})
 		// Run test
@@ -237,17 +228,17 @@ func TestStartCommand(t *testing.T) {
 		// Setup mock docker
 		require.NoError(t, apitest.MockDocker(utils.Docker))
 		defer gock.OffAll()
-		gock.New("http:///var/run/docker.sock").
+		gock.New(utils.Docker.DaemonHost()).
 			Head("/_ping").
 			Reply(http.StatusOK).
 			SetHeader("API-Version", utils.Docker.ClientVersion()).
 			SetHeader("OSType", "linux")
 		gock.New(utils.Docker.DaemonHost()).
-			Get("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId + "/json").
+			Get("/v" + utils.Docker.ClientVersion() + "/containers/").
 			Reply(http.StatusNotFound)
 		// Fail to start
 		gock.New(utils.Docker.DaemonHost()).
-			Get("/v" + utils.Docker.ClientVersion() + "/volumes/" + utils.DbId).
+			Get("/v" + utils.Docker.ClientVersion() + "/volumes/").
 			ReplyError(errors.New("network error"))
 		gock.New(utils.Docker.DaemonHost()).
 			Get("/v" + utils.Docker.ClientVersion() + "/images/" + utils.GetRegistryImageUrl(utils.Pg15Image) + "/json").
@@ -265,68 +256,77 @@ func TestStartCommand(t *testing.T) {
 }
 
 func TestSetupDatabase(t *testing.T) {
-	config := pgconn.Config{Host: utils.DbId}
-
-	t.Run("skips when backup exists", func(t *testing.T) {
-		noBackupVolume = false
-		// Run test
-		err := SetupDatabase(context.Background(), config, nil, io.Discard)
-		// Check error
-		assert.NoError(t, err)
-		// Reset variable
-		noBackupVolume = true
-	})
+	utils.Config.Db.MajorVersion = 15
 
-	t.Run("initialises database", func(t *testing.T) {
+	t.Run("initialises database 14", func(t *testing.T) {
+		utils.Config.Db.MajorVersion = 14
+		defer func() {
+			utils.Config.Db.MajorVersion = 15
+		}()
 		utils.Config.Db.Port = 5432
+		utils.GlobalsSql = "create schema public"
+		utils.InitialSchemaSql = "create schema private"
 		// Setup in-memory fs
 		fsys := afero.NewMemMapFs()
+		roles := "create role postgres"
+		require.NoError(t, afero.WriteFile(fsys, utils.CustomRolesPath, []byte(roles), 0644))
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
+		conn.Query(utils.GlobalsSql).
+			Reply("CREATE SCHEMA").
+			Query(utils.InitialSchemaSql).
+			Reply("CREATE SCHEMA").
+			Query(roles).
+			Reply("CREATE ROLE")
 		// Run test
-		err := SetupDatabase(context.Background(), config, fsys, io.Discard, conn.Intercept)
+		err := setupDatabase(context.Background(), fsys, io.Discard, conn.Intercept)
 		// Check error
 		assert.NoError(t, err)
 	})
 
 	t.Run("throws error on connect failure", func(t *testing.T) {
 		utils.Config.Db.Port = 0
-		// Setup in-memory fs
-		fsys := &fstest.OpenErrorFs{DenyPath: utils.CustomRolesPath}
 		// Run test
-		err := SetupDatabase(context.Background(), config, fsys, io.Discard)
+		err := setupDatabase(context.Background(), nil, io.Discard)
 		// Check error
 		assert.ErrorContains(t, err, "invalid port (outside range)")
 	})
 
-	t.Run("throws error on read failure", func(t *testing.T) {
+	t.Run("throws error on init failure", func(t *testing.T) {
 		utils.Config.Db.Port = 5432
-		// Setup in-memory fs
-		fsys := &fstest.OpenErrorFs{DenyPath: utils.CustomRolesPath}
+		// Setup mock docker
+		require.NoError(t, apitest.MockDocker(utils.Docker))
+		defer gock.OffAll()
+		gock.New(utils.Docker.DaemonHost()).
+			Get("/v" + utils.Docker.ClientVersion() + "/images/" + utils.GetRegistryImageUrl(utils.StorageImage) + "/json").
+			ReplyError(errors.New("network error"))
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
 		// Run test
-		err := SetupDatabase(context.Background(), config, fsys, io.Discard, conn.Intercept)
+		err := setupDatabase(context.Background(), nil, io.Discard, conn.Intercept)
 		// Check error
-		assert.ErrorIs(t, err, os.ErrPermission)
+		assert.ErrorContains(t, err, "network error")
 	})
 
-	t.Run("throws error on exec failure", func(t *testing.T) {
+	t.Run("throws error on read failure", func(t *testing.T) {
 		utils.Config.Db.Port = 5432
 		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
-		sql := "create role postgres"
-		require.NoError(t, afero.WriteFile(fsys, utils.CustomRolesPath, []byte(sql), 0644))
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.CustomRolesPath}
+		// Setup mock docker
+		require.NoError(t, apitest.MockDocker(utils.Docker))
+		defer gock.OffAll()
+		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.GotrueImage), "test-auth")
+		require.NoError(t, apitest.MockDockerLogs(utils.Docker, "test-auth", ""))
+		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.StorageImage), "test-storage")
+		require.NoError(t, apitest.MockDockerLogs(utils.Docker, "test-storage", ""))
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
-		conn.Query(sql).
-			ReplyError(pgerrcode.DuplicateObject, `role "postgres" already exists`)
 		// Run test
-		err := SetupDatabase(context.Background(), config, fsys, io.Discard, conn.Intercept)
+		err := setupDatabase(context.Background(), fsys, io.Discard, conn.Intercept)
 		// Check error
-		assert.ErrorContains(t, err, `ERROR: role "postgres" already exists (SQLSTATE 42710)`)
+		assert.ErrorIs(t, err, os.ErrPermission)
 	})
 }
diff --git a/internal/start/start_test.go b/internal/start/start_test.go
index f0b0d130..31b095fc 100644
--- a/internal/start/start_test.go
+++ b/internal/start/start_test.go
@@ -151,6 +151,10 @@ func TestDatabaseStart(t *testing.T) {
 			Get("/v" + utils.Docker.ClientVersion() + "/volumes/" + utils.DbId).
 			Reply(http.StatusNotFound)
 		apitest.MockDockerStart(utils.Docker, imageUrl, utils.DbId)
+		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.GotrueImage), "test-auth")
+		require.NoError(t, apitest.MockDockerLogs(utils.Docker, "test-auth", ""))
+		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.StorageImage), "test-storage")
+		require.NoError(t, apitest.MockDockerLogs(utils.Docker, "test-storage", ""))
 		// Start services
 		utils.KongId = "test-kong"
 		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.KongImage), utils.KongId)