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  }