github.com/scraniel/migrate@v0.0.0-20230320185700-339088f36cee/database/spanner/spanner_test.go (about) 1 package spanner 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 8 "github.com/golang-migrate/migrate/v4" 9 10 dt "github.com/golang-migrate/migrate/v4/database/testing" 11 _ "github.com/golang-migrate/migrate/v4/source/file" 12 13 "cloud.google.com/go/spanner/spannertest" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 // withSpannerEmulator is not thread-safe and cannot be used with parallel tests since it sets the emulator 19 func withSpannerEmulator(t *testing.T, testFunc func(t *testing.T)) { 20 t.Helper() 21 srv, err := spannertest.NewServer("localhost:0") 22 if err != nil { 23 t.Fatal("Failed to create Spanner emulator:", err) 24 } 25 // This is not thread-safe 26 if err := os.Setenv("SPANNER_EMULATOR_HOST", srv.Addr); err != nil { 27 t.Fatal("Failed to set SPANNER_EMULATOR_HOST env var:", err) 28 } 29 defer srv.Close() 30 testFunc(t) 31 32 } 33 34 const db = "projects/abc/instances/def/databases/testdb" 35 36 func Test(t *testing.T) { 37 withSpannerEmulator(t, func(t *testing.T) { 38 uri := fmt.Sprintf("spanner://%s", db) 39 s := &Spanner{} 40 d, err := s.Open(uri) 41 if err != nil { 42 t.Fatal(err) 43 } 44 dt.Test(t, d, []byte("CREATE TABLE test (id BOOL) PRIMARY KEY (id)")) 45 }) 46 } 47 48 func TestMigrate(t *testing.T) { 49 withSpannerEmulator(t, func(t *testing.T) { 50 s := &Spanner{} 51 uri := fmt.Sprintf("spanner://%s", db) 52 d, err := s.Open(uri) 53 if err != nil { 54 t.Fatal(err) 55 } 56 m, err := migrate.NewWithDatabaseInstance("file://./examples/migrations", uri, d) 57 if err != nil { 58 t.Fatal(err) 59 } 60 dt.TestMigrate(t, m) 61 }) 62 } 63 64 func TestCleanStatements(t *testing.T) { 65 testCases := []struct { 66 name string 67 multiStatement string 68 expected []string 69 }{ 70 { 71 name: "no statement", 72 multiStatement: "", 73 expected: []string{}, 74 }, 75 { 76 name: "single statement, single line, no semicolon, no comment", 77 multiStatement: "CREATE TABLE table_name (id STRING(255) NOT NULL) PRIMARY KEY (id)", 78 expected: []string{"CREATE TABLE table_name (\n id STRING(255) NOT NULL,\n) PRIMARY KEY(id)"}, 79 }, 80 { 81 name: "single statement, multi line, no semicolon, no comment", 82 multiStatement: `CREATE TABLE table_name ( 83 id STRING(255) NOT NULL, 84 ) PRIMARY KEY (id)`, 85 expected: []string{"CREATE TABLE table_name (\n id STRING(255) NOT NULL,\n) PRIMARY KEY(id)"}, 86 }, 87 { 88 name: "single statement, single line, with semicolon, no comment", 89 multiStatement: "CREATE TABLE table_name (id STRING(255) NOT NULL) PRIMARY KEY (id);", 90 expected: []string{"CREATE TABLE table_name (\n id STRING(255) NOT NULL,\n) PRIMARY KEY(id)"}, 91 }, 92 { 93 name: "single statement, multi line, with semicolon, no comment", 94 multiStatement: `CREATE TABLE table_name ( 95 id STRING(255) NOT NULL, 96 ) PRIMARY KEY (id);`, 97 expected: []string{"CREATE TABLE table_name (\n id STRING(255) NOT NULL,\n) PRIMARY KEY(id)"}, 98 }, 99 { 100 name: "multi statement, with trailing semicolon. no comment", 101 // From https://github.com/mattes/migrate/pull/281 102 multiStatement: `CREATE TABLE table_name ( 103 id STRING(255) NOT NULL, 104 ) PRIMARY KEY(id); 105 106 CREATE INDEX table_name_id_idx ON table_name (id);`, 107 expected: []string{`CREATE TABLE table_name ( 108 id STRING(255) NOT NULL, 109 ) PRIMARY KEY(id)`, "CREATE INDEX table_name_id_idx ON table_name(id)"}, 110 }, 111 { 112 name: "multi statement, no trailing semicolon, no comment", 113 // From https://github.com/mattes/migrate/pull/281 114 multiStatement: `CREATE TABLE table_name ( 115 id STRING(255) NOT NULL, 116 ) PRIMARY KEY(id); 117 118 CREATE INDEX table_name_id_idx ON table_name (id)`, 119 expected: []string{`CREATE TABLE table_name ( 120 id STRING(255) NOT NULL, 121 ) PRIMARY KEY(id)`, "CREATE INDEX table_name_id_idx ON table_name(id)"}, 122 }, 123 { 124 name: "multi statement, no trailing semicolon, standalone comment", 125 // From https://github.com/mattes/migrate/pull/281 126 multiStatement: `CREATE TABLE table_name ( 127 -- standalone comment 128 id STRING(255) NOT NULL, 129 ) PRIMARY KEY(id); 130 131 CREATE INDEX table_name_id_idx ON table_name (id)`, 132 expected: []string{`CREATE TABLE table_name ( 133 id STRING(255) NOT NULL, 134 ) PRIMARY KEY(id)`, "CREATE INDEX table_name_id_idx ON table_name(id)"}, 135 }, 136 { 137 name: "multi statement, no trailing semicolon, inline comment", 138 // From https://github.com/mattes/migrate/pull/281 139 multiStatement: `CREATE TABLE table_name ( 140 id STRING(255) NOT NULL, -- inline comment 141 ) PRIMARY KEY(id); 142 143 CREATE INDEX table_name_id_idx ON table_name (id)`, 144 expected: []string{`CREATE TABLE table_name ( 145 id STRING(255) NOT NULL, 146 ) PRIMARY KEY(id)`, "CREATE INDEX table_name_id_idx ON table_name(id)"}, 147 }, 148 { 149 name: "alter table with SET OPTIONS", 150 multiStatement: `ALTER TABLE users ALTER COLUMN created 151 SET OPTIONS (allow_commit_timestamp=true);`, 152 expected: []string{"ALTER TABLE users ALTER COLUMN created SET OPTIONS (allow_commit_timestamp = true)"}, 153 }, 154 { 155 name: "column with NUMERIC type", 156 multiStatement: `CREATE TABLE table_name ( 157 id STRING(255) NOT NULL, 158 sum NUMERIC, 159 ) PRIMARY KEY (id)`, 160 expected: []string{"CREATE TABLE table_name (\n id STRING(255) NOT NULL,\n sum NUMERIC,\n) PRIMARY KEY(id)"}, 161 }, 162 } 163 164 for _, tc := range testCases { 165 t.Run(tc.name, func(t *testing.T) { 166 stmts, err := cleanStatements([]byte(tc.multiStatement)) 167 require.NoError(t, err, "Error cleaning statements") 168 assert.Equal(t, tc.expected, stmts) 169 }) 170 } 171 }