github.com/supabase/cli@v1.168.1/internal/db/push/push_test.go (about)

     1  package push
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/jackc/pgconn"
    10  	"github.com/jackc/pgerrcode"
    11  	"github.com/spf13/afero"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  	"github.com/supabase/cli/internal/migration/history"
    15  	"github.com/supabase/cli/internal/migration/list"
    16  	"github.com/supabase/cli/internal/testing/fstest"
    17  	"github.com/supabase/cli/internal/testing/pgtest"
    18  	"github.com/supabase/cli/internal/utils"
    19  )
    20  
    21  var dbConfig = pgconn.Config{
    22  	Host:     "127.0.0.1",
    23  	Port:     5432,
    24  	User:     "admin",
    25  	Password: "password",
    26  	Database: "postgres",
    27  }
    28  
    29  func TestMigrationPush(t *testing.T) {
    30  	t.Run("dry run", func(t *testing.T) {
    31  		// Setup in-memory fs
    32  		fsys := afero.NewMemMapFs()
    33  		path := filepath.Join(utils.MigrationsDir, "0_test.sql")
    34  		require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644))
    35  		// Setup mock postgres
    36  		conn := pgtest.NewConn()
    37  		defer conn.Close(t)
    38  		conn.Query(list.LIST_MIGRATION_VERSION).
    39  			Reply("SELECT 0")
    40  		// Run test
    41  		err := Run(context.Background(), true, false, true, true, dbConfig, fsys, conn.Intercept)
    42  		// Check error
    43  		assert.NoError(t, err)
    44  	})
    45  
    46  	t.Run("ignores up to date", func(t *testing.T) {
    47  		// Setup in-memory fs
    48  		fsys := afero.NewMemMapFs()
    49  		// Setup mock postgres
    50  		conn := pgtest.NewConn()
    51  		defer conn.Close(t)
    52  		conn.Query(list.LIST_MIGRATION_VERSION).
    53  			Reply("SELECT 0")
    54  		// Run test
    55  		err := Run(context.Background(), false, false, false, false, dbConfig, fsys, conn.Intercept)
    56  		// Check error
    57  		assert.NoError(t, err)
    58  	})
    59  
    60  	t.Run("throws error on connect failure", func(t *testing.T) {
    61  		// Setup in-memory fs
    62  		fsys := afero.NewMemMapFs()
    63  		// Run test
    64  		err := Run(context.Background(), false, false, false, false, pgconn.Config{}, fsys)
    65  		// Check error
    66  		assert.ErrorContains(t, err, "invalid port (outside range)")
    67  	})
    68  
    69  	t.Run("throws error on remote load failure", func(t *testing.T) {
    70  		// Setup in-memory fs
    71  		fsys := afero.NewMemMapFs()
    72  		// Setup mock postgres
    73  		conn := pgtest.NewConn()
    74  		defer conn.Close(t)
    75  		conn.Query(list.LIST_MIGRATION_VERSION).
    76  			ReplyError(pgerrcode.InvalidCatalogName, `database "target" does not exist`)
    77  		// Run test
    78  		err := Run(context.Background(), false, false, false, false, pgconn.Config{
    79  			Host:     "db.supabase.co",
    80  			Port:     5432,
    81  			User:     "admin",
    82  			Password: "password",
    83  			Database: "postgres",
    84  		}, fsys, conn.Intercept)
    85  		// Check error
    86  		assert.ErrorContains(t, err, `ERROR: database "target" does not exist (SQLSTATE 3D000)`)
    87  	})
    88  
    89  	t.Run("throws error on push failure", func(t *testing.T) {
    90  		// Setup in-memory fs
    91  		fsys := afero.NewMemMapFs()
    92  		path := filepath.Join(utils.MigrationsDir, "0_test.sql")
    93  		require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644))
    94  		// Setup mock postgres
    95  		conn := pgtest.NewConn()
    96  		defer conn.Close(t)
    97  		conn.Query(list.LIST_MIGRATION_VERSION).
    98  			Reply("SELECT 0")
    99  		pgtest.MockMigrationHistory(conn)
   100  		conn.Query(history.INSERT_MIGRATION_VERSION, "0", "test", nil).
   101  			ReplyError(pgerrcode.NotNullViolation, `null value in column "version" of relation "schema_migrations"`)
   102  		// Run test
   103  		err := Run(context.Background(), false, false, false, false, dbConfig, fsys, conn.Intercept)
   104  		// Check error
   105  		assert.ErrorContains(t, err, `ERROR: null value in column "version" of relation "schema_migrations" (SQLSTATE 23502)`)
   106  		assert.ErrorContains(t, err, "At statement 0: "+history.INSERT_MIGRATION_VERSION)
   107  	})
   108  }
   109  
   110  func TestPushAll(t *testing.T) {
   111  	t.Run("ignores missing roles and seed", func(t *testing.T) {
   112  		// Setup in-memory fs
   113  		fsys := afero.NewMemMapFs()
   114  		path := filepath.Join(utils.MigrationsDir, "0_test.sql")
   115  		require.NoError(t, afero.WriteFile(fsys, path, []byte{}, 0644))
   116  		// Setup mock postgres
   117  		conn := pgtest.NewConn()
   118  		defer conn.Close(t)
   119  		conn.Query(list.LIST_MIGRATION_VERSION).
   120  			Reply("SELECT 0")
   121  		pgtest.MockMigrationHistory(conn)
   122  		conn.Query(history.INSERT_MIGRATION_VERSION, "0", "test", nil).
   123  			Reply("INSERT 0 1")
   124  		// Run test
   125  		err := Run(context.Background(), false, false, true, true, dbConfig, fsys, conn.Intercept)
   126  		// Check error
   127  		assert.NoError(t, err)
   128  	})
   129  
   130  	t.Run("throws error on cancel", func(t *testing.T) {
   131  		defer fstest.MockStdin(t, "n")()
   132  		// Setup in-memory fs
   133  		fsys := afero.NewMemMapFs()
   134  		path := filepath.Join(utils.MigrationsDir, "0_test.sql")
   135  		require.NoError(t, afero.WriteFile(fsys, path, []byte{}, 0644))
   136  		// Setup mock postgres
   137  		conn := pgtest.NewConn()
   138  		defer conn.Close(t)
   139  		conn.Query(list.LIST_MIGRATION_VERSION).
   140  			Reply("SELECT 0")
   141  		// Run test
   142  		err := Run(context.Background(), false, false, true, true, dbConfig, fsys, conn.Intercept)
   143  		// Check error
   144  		assert.ErrorIs(t, err, context.Canceled)
   145  	})
   146  
   147  	t.Run("throws error on roles failure", func(t *testing.T) {
   148  		// Setup in-memory fs
   149  		fsys := &fstest.OpenErrorFs{DenyPath: utils.CustomRolesPath}
   150  		path := filepath.Join(utils.MigrationsDir, "0_test.sql")
   151  		require.NoError(t, afero.WriteFile(fsys, path, []byte{}, 0644))
   152  		// Setup mock postgres
   153  		conn := pgtest.NewConn()
   154  		defer conn.Close(t)
   155  		conn.Query(list.LIST_MIGRATION_VERSION).
   156  			Reply("SELECT 0")
   157  		// Run test
   158  		err := Run(context.Background(), false, false, true, false, dbConfig, fsys, conn.Intercept)
   159  		// Check error
   160  		assert.ErrorIs(t, err, os.ErrPermission)
   161  	})
   162  
   163  	t.Run("throws error on seed failure", func(t *testing.T) {
   164  		// Setup in-memory fs
   165  		fsys := &fstest.OpenErrorFs{DenyPath: utils.SeedDataPath}
   166  		path := filepath.Join(utils.MigrationsDir, "0_test.sql")
   167  		require.NoError(t, afero.WriteFile(fsys, path, []byte{}, 0644))
   168  		// Setup mock postgres
   169  		conn := pgtest.NewConn()
   170  		defer conn.Close(t)
   171  		conn.Query(list.LIST_MIGRATION_VERSION).
   172  			Reply("SELECT 0")
   173  		pgtest.MockMigrationHistory(conn)
   174  		conn.Query(history.INSERT_MIGRATION_VERSION, "0", "test", nil).
   175  			Reply("INSERT 0 1")
   176  		// Run test
   177  		err := Run(context.Background(), false, false, false, true, dbConfig, fsys, conn.Intercept)
   178  		// Check error
   179  		assert.ErrorIs(t, err, os.ErrPermission)
   180  	})
   181  }