github.com/dynastymasra/migrate/v4@v4.11.0/database/sqlserver/sqlserver_test.go (about) 1 package sqlserver 2 3 import ( 4 "context" 5 "database/sql" 6 sqldriver "database/sql/driver" 7 "fmt" 8 "log" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/dhui/dktest" 14 "github.com/golang-migrate/migrate/v4" 15 16 dt "github.com/golang-migrate/migrate/v4/database/testing" 17 "github.com/golang-migrate/migrate/v4/dktesting" 18 19 _ "github.com/golang-migrate/migrate/v4/source/file" 20 ) 21 22 const defaultPort = 1433 23 const saPassword = "Root1234" 24 25 var ( 26 opts = dktest.Options{ 27 Env: map[string]string{"ACCEPT_EULA": "Y", "SA_PASSWORD": saPassword, "MSSQL_PID": "Express"}, 28 PortRequired: true, ReadyFunc: isReady, PullTimeout: 2 * time.Minute, 29 } 30 // Container versions: https://mcr.microsoft.com/v2/mssql/server/tags/list 31 specs = []dktesting.ContainerSpec{ 32 {ImageName: "mcr.microsoft.com/mssql/server:2017-latest", Options: opts}, 33 {ImageName: "mcr.microsoft.com/mssql/server:2019-latest", Options: opts}, 34 } 35 ) 36 37 func msConnectionString(host, port string) string { 38 return fmt.Sprintf("sqlserver://sa:%v@%v:%v?database=master", saPassword, host, port) 39 } 40 41 func isReady(ctx context.Context, c dktest.ContainerInfo) bool { 42 ip, port, err := c.Port(defaultPort) 43 if err != nil { 44 return false 45 } 46 uri := msConnectionString(ip, port) 47 db, err := sql.Open("sqlserver", uri) 48 if err != nil { 49 return false 50 } 51 defer func() { 52 if err := db.Close(); err != nil { 53 log.Println("close error:", err) 54 } 55 }() 56 if err = db.PingContext(ctx); err != nil { 57 switch err { 58 case sqldriver.ErrBadConn: 59 return false 60 default: 61 fmt.Println(err) 62 } 63 return false 64 } 65 66 return true 67 } 68 69 func Test(t *testing.T) { 70 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { 71 ip, port, err := c.Port(defaultPort) 72 if err != nil { 73 t.Fatal(err) 74 } 75 76 addr := msConnectionString(ip, port) 77 p := &SQLServer{} 78 d, err := p.Open(addr) 79 if err != nil { 80 t.Fatalf("%v", err) 81 } 82 83 defer func() { 84 if err := d.Close(); err != nil { 85 t.Error(err) 86 } 87 }() 88 89 dt.Test(t, d, []byte("SELECT 1")) 90 }) 91 } 92 93 func TestMigrate(t *testing.T) { 94 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { 95 ip, port, err := c.Port(defaultPort) 96 if err != nil { 97 t.Fatal(err) 98 } 99 100 addr := msConnectionString(ip, port) 101 p := &SQLServer{} 102 d, err := p.Open(addr) 103 if err != nil { 104 t.Fatalf("%v", err) 105 } 106 107 defer func() { 108 if err := d.Close(); err != nil { 109 t.Error(err) 110 } 111 }() 112 113 m, err := migrate.NewWithDatabaseInstance("file://./examples/migrations", "master", d) 114 if err != nil { 115 t.Fatal(err) 116 } 117 dt.TestMigrate(t, m) 118 }) 119 } 120 121 func TestMultiStatement(t *testing.T) { 122 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { 123 ip, port, err := c.FirstPort() 124 if err != nil { 125 t.Fatal(err) 126 } 127 128 addr := msConnectionString(ip, port) 129 ms := &SQLServer{} 130 d, err := ms.Open(addr) 131 if err != nil { 132 t.Fatal(err) 133 } 134 defer func() { 135 if err := d.Close(); err != nil { 136 t.Error(err) 137 } 138 }() 139 if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLE bar (bar text);")); err != nil { 140 t.Fatalf("expected err to be nil, got %v", err) 141 } 142 143 // make sure second table exists 144 var exists int 145 if err := d.(*SQLServer).conn.QueryRowContext(context.Background(), "SELECT COUNT(1) FROM information_schema.tables WHERE table_name = 'bar' AND table_schema = (SELECT schema_name()) AND table_catalog = (SELECT db_name())").Scan(&exists); err != nil { 146 t.Fatal(err) 147 } 148 if exists != 1 { 149 t.Fatalf("expected table bar to exist") 150 } 151 }) 152 } 153 154 func TestErrorParsing(t *testing.T) { 155 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { 156 ip, port, err := c.FirstPort() 157 if err != nil { 158 t.Fatal(err) 159 } 160 161 addr := msConnectionString(ip, port) 162 p := &SQLServer{} 163 d, err := p.Open(addr) 164 if err != nil { 165 t.Fatal(err) 166 } 167 defer func() { 168 if err := d.Close(); err != nil { 169 t.Error(err) 170 } 171 }() 172 173 wantErr := `migration failed: Unknown object type 'TABLEE' used in a CREATE, DROP, or ALTER statement. in line 1:` + 174 ` CREATE TABLE foo (foo text); CREATE TABLEE bar (bar text); (details: mssql: Unknown object type ` + 175 `'TABLEE' used in a CREATE, DROP, or ALTER statement.)` 176 if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLEE bar (bar text);")); err == nil { 177 t.Fatal("expected err but got nil") 178 } else if err.Error() != wantErr { 179 t.Fatalf("expected '%s' but got '%s'", wantErr, err.Error()) 180 } 181 }) 182 } 183 184 func TestLockWorks(t *testing.T) { 185 dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { 186 ip, port, err := c.Port(defaultPort) 187 if err != nil { 188 t.Fatal(err) 189 } 190 191 addr := fmt.Sprintf("sqlserver://sa:%v@%v:%v?master", saPassword, ip, port) 192 p := &SQLServer{} 193 d, err := p.Open(addr) 194 if err != nil { 195 t.Fatalf("%v", err) 196 } 197 dt.Test(t, d, []byte("SELECT 1")) 198 199 ms := d.(*SQLServer) 200 201 err = ms.Lock() 202 if err != nil { 203 t.Fatal(err) 204 } 205 err = ms.Unlock() 206 if err != nil { 207 t.Fatal(err) 208 } 209 210 // make sure the 2nd lock works (RELEASE_LOCK is very finicky) 211 err = ms.Lock() 212 if err != nil { 213 t.Fatal(err) 214 } 215 err = ms.Unlock() 216 if err != nil { 217 t.Fatal(err) 218 } 219 }) 220 }