...

Source file src/github.com/doug-martin/goqu/v9/database_test.go

Documentation: github.com/doug-martin/goqu/v9

     1  package goqu_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  	"testing"
     8  
     9  	"github.com/DATA-DOG/go-sqlmock"
    10  	"github.com/doug-martin/goqu/v9"
    11  	"github.com/doug-martin/goqu/v9/internal/errors"
    12  	"github.com/stretchr/testify/suite"
    13  )
    14  
    15  type testActionItem struct {
    16  	Address string `db:"address"`
    17  	Name    string `db:"name"`
    18  }
    19  
    20  type dbTestMockLogger struct {
    21  	Messages []string
    22  }
    23  
    24  func (dtml *dbTestMockLogger) Printf(format string, v ...interface{}) {
    25  	dtml.Messages = append(dtml.Messages, fmt.Sprintf(format, v...))
    26  }
    27  
    28  func (dtml *dbTestMockLogger) Reset() {
    29  	dtml.Messages = dtml.Messages[0:0]
    30  }
    31  
    32  type databaseSuite struct {
    33  	suite.Suite
    34  }
    35  
    36  func (ds *databaseSuite) TestLogger() {
    37  	mDB, mock, err := sqlmock.New()
    38  	ds.NoError(err)
    39  	mock.ExpectQuery(`SELECT \* FROM "items"`).
    40  		WithArgs().
    41  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
    42  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
    43  
    44  	mock.ExpectExec(`SELECT \* FROM "items" WHERE "id" = ?`).
    45  		WithArgs(1).
    46  		WillReturnResult(sqlmock.NewResult(0, 0))
    47  
    48  	db := goqu.New("db-mock", mDB)
    49  	logger := new(dbTestMockLogger)
    50  	db.Logger(logger)
    51  	var items []testActionItem
    52  	ds.NoError(db.ScanStructs(&items, `SELECT * FROM "items"`))
    53  	_, err = db.Exec(`SELECT * FROM "items" WHERE "id" = ?`, 1)
    54  	ds.NoError(err)
    55  	db.Trace("TEST", "")
    56  	ds.Equal([]string{
    57  		"[goqu] QUERY [query:=`SELECT * FROM \"items\"`]",
    58  		"[goqu] EXEC [query:=`SELECT * FROM \"items\" WHERE \"id\" = ?` args:=[1]]",
    59  		"[goqu] TEST",
    60  	}, logger.Messages)
    61  }
    62  
    63  func (ds *databaseSuite) TestScanStructs() {
    64  	mDB, mock, err := sqlmock.New()
    65  	ds.NoError(err)
    66  	mock.ExpectQuery(`SELECT \* FROM "items"`).
    67  		WithArgs().
    68  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
    69  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
    70  	mock.ExpectQuery(`SELECT \* FROM "items"`).
    71  		WithArgs().
    72  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
    73  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
    74  	mock.ExpectQuery(`SELECT \* FROM "items"`).
    75  		WithArgs().
    76  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
    77  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
    78  	mock.ExpectQuery(`SELECT "test" FROM "items"`).
    79  		WithArgs().
    80  		WillReturnRows(sqlmock.NewRows([]string{"test"}).FromCSVString("test1\ntest2"))
    81  
    82  	db := goqu.New("db-mock", mDB)
    83  	var items []testActionItem
    84  	ds.NoError(db.ScanStructs(&items, `SELECT * FROM "items"`))
    85  	ds.Len(items, 2)
    86  	ds.Equal("111 Test Addr", items[0].Address)
    87  	ds.Equal("Test1", items[0].Name)
    88  
    89  	ds.Equal("211 Test Addr", items[1].Address)
    90  	ds.Equal("Test2", items[1].Name)
    91  
    92  	items = items[0:0]
    93  	ds.EqualError(db.ScanStructs(items, `SELECT * FROM "items"`),
    94  		"goqu: type must be a pointer to a slice when scanning into structs")
    95  	ds.EqualError(db.ScanStructs(&testActionItem{}, `SELECT * FROM "items"`),
    96  		"goqu: type must be a pointer to a slice when scanning into structs")
    97  	ds.EqualError(db.ScanStructs(&items, `SELECT "test" FROM "items"`),
    98  		`goqu: unable to find corresponding field to column "test" returned by query`)
    99  }
   100  
   101  func (ds *databaseSuite) TestScanStruct() {
   102  	mDB, mock, err := sqlmock.New()
   103  	ds.NoError(err)
   104  	mock.ExpectQuery(`SELECT \* FROM "items" LIMIT 1`).
   105  		WithArgs().
   106  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1"))
   107  
   108  	mock.ExpectQuery(`SELECT "test" FROM "items" LIMIT 1`).
   109  		WithArgs().
   110  		WillReturnRows(sqlmock.NewRows([]string{"test"}).FromCSVString("test1\ntest2"))
   111  
   112  	db := goqu.New("mock", mDB)
   113  	var item testActionItem
   114  	found, err := db.ScanStruct(&item, `SELECT * FROM "items" LIMIT 1`)
   115  	ds.NoError(err)
   116  	ds.True(found)
   117  	ds.Equal("111 Test Addr", item.Address)
   118  	ds.Equal("Test1", item.Name)
   119  
   120  	_, err = db.ScanStruct(item, `SELECT * FROM "items" LIMIT 1`)
   121  	ds.EqualError(err, "goqu: type must be a pointer to a struct when scanning into a struct")
   122  	_, err = db.ScanStruct([]testActionItem{}, `SELECT * FROM "items" LIMIT 1`)
   123  	ds.EqualError(err, "goqu: type must be a pointer to a struct when scanning into a struct")
   124  	_, err = db.ScanStruct(&item, `SELECT "test" FROM "items" LIMIT 1`)
   125  	ds.EqualError(err, `goqu: unable to find corresponding field to column "test" returned by query`)
   126  }
   127  
   128  func (ds *databaseSuite) TestScanVals() {
   129  	mDB, mock, err := sqlmock.New()
   130  	ds.NoError(err)
   131  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   132  		WithArgs().
   133  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("1\n2\n3\n4\n5"))
   134  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   135  		WithArgs().
   136  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("1\n2\n3\n4\n5"))
   137  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   138  		WithArgs().
   139  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("1\n2\n3\n4\n5"))
   140  
   141  	db := goqu.New("mock", mDB)
   142  	var ids []uint32
   143  	ds.NoError(db.ScanVals(&ids, `SELECT "id" FROM "items"`))
   144  	ds.Len(ids, 5)
   145  
   146  	ds.EqualError(db.ScanVals([]uint32{}, `SELECT "id" FROM "items"`),
   147  		"goqu: type must be a pointer to a slice when scanning into vals")
   148  	ds.EqualError(db.ScanVals(testActionItem{}, `SELECT "id" FROM "items"`),
   149  		"goqu: type must be a pointer to a slice when scanning into vals")
   150  }
   151  
   152  func (ds *databaseSuite) TestScanVal() {
   153  	mDB, mock, err := sqlmock.New()
   154  	ds.NoError(err)
   155  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   156  		WithArgs().
   157  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("10"))
   158  
   159  	db := goqu.New("mock", mDB)
   160  	var id int64
   161  	found, err := db.ScanVal(&id, `SELECT "id" FROM "items"`)
   162  	ds.NoError(err)
   163  	ds.Equal(int64(10), id)
   164  	ds.True(found)
   165  
   166  	found, err = db.ScanVal([]int64{}, `SELECT "id" FROM "items"`)
   167  	ds.False(found)
   168  	ds.EqualError(err, "goqu: type must be a pointer when scanning into val")
   169  	found, err = db.ScanVal(10, `SELECT "id" FROM "items"`)
   170  	ds.False(found)
   171  	ds.EqualError(err, "goqu: type must be a pointer when scanning into val")
   172  }
   173  
   174  func (ds *databaseSuite) TestExec() {
   175  	mDB, mock, err := sqlmock.New()
   176  	ds.NoError(err)
   177  	mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
   178  		WithArgs().
   179  		WillReturnResult(sqlmock.NewResult(0, 0))
   180  
   181  	mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
   182  		WithArgs().
   183  		WillReturnError(errors.New("mock error"))
   184  
   185  	db := goqu.New("mock", mDB)
   186  	_, err = db.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
   187  	ds.NoError(err)
   188  	_, err = db.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
   189  	ds.EqualError(err, "goqu: mock error")
   190  }
   191  
   192  func (ds *databaseSuite) TestQuery() {
   193  	mDB, mock, err := sqlmock.New()
   194  	ds.NoError(err)
   195  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   196  		WithArgs().
   197  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   198  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   199  
   200  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   201  		WithArgs().
   202  		WillReturnError(errors.New("mock error"))
   203  
   204  	db := goqu.New("mock", mDB)
   205  	_, err = db.Query(`SELECT * FROM "items"`)
   206  	ds.NoError(err, "goqu - mock error")
   207  
   208  	_, err = db.Query(`SELECT * FROM "items"`)
   209  	ds.EqualError(err, "goqu: mock error")
   210  }
   211  
   212  func (ds *databaseSuite) TestQueryRow() {
   213  	mDB, mock, err := sqlmock.New()
   214  	ds.NoError(err)
   215  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   216  		WithArgs().
   217  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   218  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   219  
   220  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   221  		WithArgs().
   222  		WillReturnError(errors.New("mock error"))
   223  
   224  	db := goqu.New("mock", mDB)
   225  	rows := db.QueryRow(`SELECT * FROM "items"`)
   226  	var address string
   227  	var name string
   228  	ds.NoError(rows.Scan(&address, &name))
   229  
   230  	rows = db.QueryRow(`SELECT * FROM "items"`)
   231  	ds.EqualError(rows.Scan(&address, &name), "goqu: mock error")
   232  }
   233  
   234  func (ds *databaseSuite) TestPrepare() {
   235  	mDB, mock, err := sqlmock.New()
   236  	ds.NoError(err)
   237  	mock.ExpectPrepare("SELECT \\* FROM test WHERE id = \\?")
   238  	db := goqu.New("mock", mDB)
   239  	stmt, err := db.Prepare("SELECT * FROM test WHERE id = ?")
   240  	ds.NoError(err)
   241  	ds.NotNil(stmt)
   242  }
   243  
   244  func (ds *databaseSuite) TestBegin() {
   245  	mDB, mock, err := sqlmock.New()
   246  	ds.NoError(err)
   247  	mock.ExpectBegin()
   248  	mock.ExpectBegin().WillReturnError(errors.New("transaction error"))
   249  	db := goqu.New("mock", mDB)
   250  	tx, err := db.Begin()
   251  	ds.NoError(err)
   252  	ds.Equal("mock", tx.Dialect())
   253  
   254  	_, err = db.Begin()
   255  	ds.EqualError(err, "goqu: transaction error")
   256  }
   257  
   258  func (ds *databaseSuite) TestBeginTx() {
   259  	ctx := context.Background()
   260  	mDB, mock, err := sqlmock.New()
   261  	ds.NoError(err)
   262  	mock.ExpectBegin()
   263  	mock.ExpectBegin().WillReturnError(errors.New("transaction error"))
   264  	db := goqu.New("mock", mDB)
   265  	tx, err := db.BeginTx(ctx, nil)
   266  	ds.NoError(err)
   267  	ds.Equal("mock", tx.Dialect())
   268  
   269  	_, err = db.BeginTx(ctx, nil)
   270  	ds.EqualError(err, "goqu: transaction error")
   271  }
   272  
   273  func (ds *databaseSuite) TestWithTx() {
   274  	mDB, mock, err := sqlmock.New()
   275  	ds.NoError(err)
   276  
   277  	db := goqu.New("mock", mDB)
   278  
   279  	cases := []struct {
   280  		expectf func(sqlmock.Sqlmock)
   281  		f       func(*goqu.TxDatabase) error
   282  		wantErr bool
   283  		errStr  string
   284  	}{
   285  		{
   286  			expectf: func(mock sqlmock.Sqlmock) {
   287  				mock.ExpectBegin()
   288  				mock.ExpectCommit()
   289  			},
   290  			f:       func(_ *goqu.TxDatabase) error { return nil },
   291  			wantErr: false,
   292  		},
   293  		{
   294  			expectf: func(mock sqlmock.Sqlmock) {
   295  				mock.ExpectBegin().WillReturnError(errors.New("transaction begin error"))
   296  			},
   297  			f:       func(_ *goqu.TxDatabase) error { return nil },
   298  			wantErr: true,
   299  			errStr:  "goqu: transaction begin error",
   300  		},
   301  		{
   302  			expectf: func(mock sqlmock.Sqlmock) {
   303  				mock.ExpectBegin()
   304  				mock.ExpectRollback()
   305  			},
   306  			f:       func(_ *goqu.TxDatabase) error { return errors.New("transaction error") },
   307  			wantErr: true,
   308  			errStr:  "goqu: transaction error",
   309  		},
   310  		{
   311  			expectf: func(mock sqlmock.Sqlmock) {
   312  				mock.ExpectBegin()
   313  				mock.ExpectRollback().WillReturnError(errors.New("transaction rollback error"))
   314  			},
   315  			f:       func(_ *goqu.TxDatabase) error { return errors.New("something wrong") },
   316  			wantErr: true,
   317  			errStr:  "goqu: transaction rollback error",
   318  		},
   319  		{
   320  			expectf: func(mock sqlmock.Sqlmock) {
   321  				mock.ExpectBegin()
   322  				mock.ExpectCommit().WillReturnError(errors.New("commit error"))
   323  			},
   324  			f:       func(_ *goqu.TxDatabase) error { return nil },
   325  			wantErr: true,
   326  			errStr:  "goqu: commit error",
   327  		},
   328  	}
   329  	for _, c := range cases {
   330  		c.expectf(mock)
   331  		err := db.WithTx(c.f)
   332  		if c.wantErr {
   333  			ds.EqualError(err, c.errStr)
   334  		} else {
   335  			ds.NoError(err)
   336  		}
   337  	}
   338  }
   339  
   340  func (ds *databaseSuite) TestRollbackOnPanic() {
   341  	mDB, mock, err := sqlmock.New()
   342  
   343  	defer func() {
   344  		p := recover()
   345  		if p == nil {
   346  			ds.Fail("there should be a panic")
   347  		}
   348  		ds.Require().Equal("a problem has happened", p.(string))
   349  		ds.Require().NoError(mock.ExpectationsWereMet())
   350  	}()
   351  
   352  	ds.NoError(err)
   353  
   354  	mock.ExpectBegin()
   355  	mock.ExpectRollback()
   356  
   357  	db := goqu.New("mock", mDB)
   358  	_ = db.WithTx(func(_ *goqu.TxDatabase) error {
   359  		panic("a problem has happened")
   360  	})
   361  }
   362  
   363  func (ds *databaseSuite) TestDataRace() {
   364  	mDB, mock, err := sqlmock.New()
   365  	ds.NoError(err)
   366  	db := goqu.New("mock", mDB)
   367  
   368  	const concurrency = 10
   369  
   370  	for i := 0; i < concurrency; i++ {
   371  		mock.ExpectQuery(`SELECT "address", "name" FROM "items"`).
   372  			WithArgs().
   373  			WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   374  				FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   375  	}
   376  
   377  	wg := sync.WaitGroup{}
   378  	for i := 0; i < concurrency; i++ {
   379  		wg.Add(1)
   380  		go func() {
   381  			defer wg.Done()
   382  
   383  			sql := db.From("items").Limit(1)
   384  			var item testActionItem
   385  			found, err := sql.ScanStruct(&item)
   386  			ds.NoError(err)
   387  			ds.True(found)
   388  			ds.Equal(item.Address, "111 Test Addr")
   389  			ds.Equal(item.Name, "Test1")
   390  		}()
   391  	}
   392  
   393  	wg.Wait()
   394  }
   395  
   396  func TestDatabaseSuite(t *testing.T) {
   397  	suite.Run(t, new(databaseSuite))
   398  }
   399  
   400  type txdatabaseSuite struct {
   401  	suite.Suite
   402  }
   403  
   404  func (tds *txdatabaseSuite) TestLogger() {
   405  	mDB, mock, err := sqlmock.New()
   406  	tds.NoError(err)
   407  	mock.ExpectBegin()
   408  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   409  		WithArgs().
   410  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   411  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   412  
   413  	mock.ExpectExec(`SELECT \* FROM "items" WHERE "id" = ?`).
   414  		WithArgs(1).
   415  		WillReturnResult(sqlmock.NewResult(0, 0))
   416  	mock.ExpectCommit()
   417  
   418  	tx, err := goqu.New("db-mock", mDB).Begin()
   419  	tds.NoError(err)
   420  	logger := new(dbTestMockLogger)
   421  	tx.Logger(logger)
   422  	var items []testActionItem
   423  	tds.NoError(tx.ScanStructs(&items, `SELECT * FROM "items"`))
   424  	_, err = tx.Exec(`SELECT * FROM "items" WHERE "id" = ?`, 1)
   425  	tds.NoError(err)
   426  	tds.NoError(tx.Commit())
   427  	tds.Equal([]string{
   428  		"[goqu - transaction] QUERY [query:=`SELECT * FROM \"items\"`] ",
   429  		"[goqu - transaction] EXEC [query:=`SELECT * FROM \"items\" WHERE \"id\" = ?` args:=[1]] ",
   430  		"[goqu - transaction] COMMIT",
   431  	}, logger.Messages)
   432  }
   433  
   434  func (tds *txdatabaseSuite) TestLogger_FromDb() {
   435  	mDB, mock, err := sqlmock.New()
   436  	tds.NoError(err)
   437  	mock.ExpectBegin()
   438  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   439  		WithArgs().
   440  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   441  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   442  
   443  	mock.ExpectExec(`SELECT \* FROM "items" WHERE "id" = ?`).
   444  		WithArgs(1).
   445  		WillReturnResult(sqlmock.NewResult(0, 0))
   446  	mock.ExpectCommit()
   447  
   448  	db := goqu.New("db-mock", mDB)
   449  	logger := new(dbTestMockLogger)
   450  	db.Logger(logger)
   451  	tx, err := db.Begin()
   452  	tds.NoError(err)
   453  
   454  	var items []testActionItem
   455  	tds.NoError(tx.ScanStructs(&items, `SELECT * FROM "items"`))
   456  	_, err = tx.Exec(`SELECT * FROM "items" WHERE "id" = ?`, 1)
   457  	tds.NoError(err)
   458  	tds.NoError(tx.Commit())
   459  	tds.Equal([]string{
   460  		"[goqu - transaction] QUERY [query:=`SELECT * FROM \"items\"`] ",
   461  		"[goqu - transaction] EXEC [query:=`SELECT * FROM \"items\" WHERE \"id\" = ?` args:=[1]] ",
   462  		"[goqu - transaction] COMMIT",
   463  	}, logger.Messages)
   464  }
   465  
   466  func (tds *txdatabaseSuite) TestCommit() {
   467  	mDB, mock, err := sqlmock.New()
   468  	tds.NoError(err)
   469  	mock.ExpectBegin()
   470  	mock.ExpectCommit()
   471  	db := goqu.New("mock", mDB)
   472  	tx, err := db.Begin()
   473  	tds.NoError(err)
   474  	tds.NoError(tx.Commit())
   475  }
   476  
   477  func (tds *txdatabaseSuite) TestRollback() {
   478  	mDB, mock, err := sqlmock.New()
   479  	tds.NoError(err)
   480  	mock.ExpectBegin()
   481  	mock.ExpectRollback()
   482  	db := goqu.New("mock", mDB)
   483  	tx, err := db.Begin()
   484  	tds.NoError(err)
   485  	tds.NoError(tx.Rollback())
   486  }
   487  
   488  func (tds *txdatabaseSuite) TestFrom() {
   489  	mDB, mock, err := sqlmock.New()
   490  	tds.NoError(err)
   491  	mock.ExpectBegin()
   492  	mock.ExpectCommit()
   493  	db := goqu.New("mock", mDB)
   494  	tx, err := db.Begin()
   495  	tds.NoError(err)
   496  	tds.NotNil(goqu.From("test"))
   497  	tds.NoError(tx.Commit())
   498  }
   499  
   500  func (tds *txdatabaseSuite) TestScanStructs() {
   501  	mDB, mock, err := sqlmock.New()
   502  	tds.NoError(err)
   503  	mock.ExpectBegin()
   504  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   505  		WithArgs().
   506  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   507  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   508  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   509  		WithArgs().
   510  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   511  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   512  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   513  		WithArgs().
   514  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   515  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   516  	mock.ExpectQuery(`SELECT "test" FROM "items"`).
   517  		WithArgs().
   518  		WillReturnRows(sqlmock.NewRows([]string{"test"}).FromCSVString("test1\ntest2"))
   519  	mock.ExpectCommit()
   520  	db := goqu.New("mock", mDB)
   521  	tx, err := db.Begin()
   522  	tds.NoError(err)
   523  	var items []testActionItem
   524  	tds.NoError(tx.ScanStructs(&items, `SELECT * FROM "items"`))
   525  	tds.Len(items, 2)
   526  	tds.Equal("111 Test Addr", items[0].Address)
   527  	tds.Equal("Test1", items[0].Name)
   528  
   529  	tds.Equal("211 Test Addr", items[1].Address)
   530  	tds.Equal("Test2", items[1].Name)
   531  
   532  	items = items[0:0]
   533  	tds.EqualError(tx.ScanStructs(items, `SELECT * FROM "items"`),
   534  		"goqu: type must be a pointer to a slice when scanning into structs")
   535  	tds.EqualError(tx.ScanStructs(&testActionItem{}, `SELECT * FROM "items"`),
   536  		"goqu: type must be a pointer to a slice when scanning into structs")
   537  	tds.EqualError(tx.ScanStructs(&items, `SELECT "test" FROM "items"`),
   538  		`goqu: unable to find corresponding field to column "test" returned by query`)
   539  	tds.NoError(tx.Commit())
   540  }
   541  
   542  func (tds *txdatabaseSuite) TestScanStruct() {
   543  	mDB, mock, err := sqlmock.New()
   544  	tds.NoError(err)
   545  	mock.ExpectBegin()
   546  	mock.ExpectQuery(`SELECT \* FROM "items" LIMIT 1`).
   547  		WithArgs().
   548  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).FromCSVString("111 Test Addr,Test1"))
   549  
   550  	mock.ExpectQuery(`SELECT "test" FROM "items" LIMIT 1`).
   551  		WithArgs().
   552  		WillReturnRows(sqlmock.NewRows([]string{"test"}).FromCSVString("test1\ntest2"))
   553  	mock.ExpectCommit()
   554  	db := goqu.New("mock", mDB)
   555  	tx, err := db.Begin()
   556  	tds.NoError(err)
   557  	var item testActionItem
   558  	found, err := tx.ScanStruct(&item, `SELECT * FROM "items" LIMIT 1`)
   559  	tds.NoError(err)
   560  	tds.True(found)
   561  	tds.Equal("111 Test Addr", item.Address)
   562  	tds.Equal("Test1", item.Name)
   563  
   564  	_, err = tx.ScanStruct(item, `SELECT * FROM "items" LIMIT 1`)
   565  	tds.EqualError(err, "goqu: type must be a pointer to a struct when scanning into a struct")
   566  	_, err = tx.ScanStruct([]testActionItem{}, `SELECT * FROM "items" LIMIT 1`)
   567  	tds.EqualError(err, "goqu: type must be a pointer to a struct when scanning into a struct")
   568  	_, err = tx.ScanStruct(&item, `SELECT "test" FROM "items" LIMIT 1`)
   569  	tds.EqualError(err, `goqu: unable to find corresponding field to column "test" returned by query`)
   570  	tds.NoError(tx.Commit())
   571  }
   572  
   573  func (tds *txdatabaseSuite) TestScanVals() {
   574  	mDB, mock, err := sqlmock.New()
   575  	tds.NoError(err)
   576  	mock.ExpectBegin()
   577  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   578  		WithArgs().
   579  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("1\n2\n3\n4\n5"))
   580  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   581  		WithArgs().
   582  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("1\n2\n3\n4\n5"))
   583  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   584  		WithArgs().
   585  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("1\n2\n3\n4\n5"))
   586  	mock.ExpectCommit()
   587  	db := goqu.New("mock", mDB)
   588  	tx, err := db.Begin()
   589  	tds.NoError(err)
   590  	var ids []uint32
   591  	tds.NoError(tx.ScanVals(&ids, `SELECT "id" FROM "items"`))
   592  	tds.Len(ids, 5)
   593  
   594  	tds.EqualError(tx.ScanVals([]uint32{}, `SELECT "id" FROM "items"`),
   595  		"goqu: type must be a pointer to a slice when scanning into vals")
   596  	tds.EqualError(tx.ScanVals(testActionItem{}, `SELECT "id" FROM "items"`),
   597  		"goqu: type must be a pointer to a slice when scanning into vals")
   598  	tds.NoError(tx.Commit())
   599  }
   600  
   601  func (tds *txdatabaseSuite) TestScanVal() {
   602  	mDB, mock, err := sqlmock.New()
   603  	tds.NoError(err)
   604  	mock.ExpectBegin()
   605  	mock.ExpectQuery(`SELECT "id" FROM "items"`).
   606  		WithArgs().
   607  		WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("10"))
   608  	mock.ExpectCommit()
   609  	db := goqu.New("mock", mDB)
   610  	tx, err := db.Begin()
   611  	tds.NoError(err)
   612  	var id int64
   613  	found, err := tx.ScanVal(&id, `SELECT "id" FROM "items"`)
   614  	tds.NoError(err)
   615  	tds.Equal(int64(10), id)
   616  	tds.True(found)
   617  
   618  	found, err = tx.ScanVal([]int64{}, `SELECT "id" FROM "items"`)
   619  	tds.False(found)
   620  	tds.EqualError(err, "goqu: type must be a pointer when scanning into val")
   621  	found, err = tx.ScanVal(10, `SELECT "id" FROM "items"`)
   622  	tds.False(found)
   623  	tds.EqualError(err, "goqu: type must be a pointer when scanning into val")
   624  	tds.NoError(tx.Commit())
   625  }
   626  
   627  func (tds *txdatabaseSuite) TestExec() {
   628  	mDB, mock, err := sqlmock.New()
   629  	tds.NoError(err)
   630  	mock.ExpectBegin()
   631  	mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
   632  		WithArgs().
   633  		WillReturnResult(sqlmock.NewResult(0, 0))
   634  
   635  	mock.ExpectExec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE \("name" IS NULL\)`).
   636  		WithArgs().
   637  		WillReturnError(errors.New("mock error"))
   638  	mock.ExpectCommit()
   639  	db := goqu.New("mock", mDB)
   640  	tx, err := db.Begin()
   641  	tds.NoError(err)
   642  	_, err = tx.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
   643  	tds.NoError(err)
   644  	_, err = tx.Exec(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`)
   645  	tds.EqualError(err, "goqu: mock error")
   646  	tds.NoError(tx.Commit())
   647  }
   648  
   649  func (tds *txdatabaseSuite) TestQuery() {
   650  	mDB, mock, err := sqlmock.New()
   651  	tds.NoError(err)
   652  	mock.ExpectBegin()
   653  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   654  		WithArgs().
   655  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   656  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   657  
   658  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   659  		WithArgs().
   660  		WillReturnError(errors.New("mock error"))
   661  	mock.ExpectCommit()
   662  	db := goqu.New("mock", mDB)
   663  	tx, err := db.Begin()
   664  	tds.NoError(err)
   665  	_, err = tx.Query(`SELECT * FROM "items"`)
   666  	tds.NoError(err, "goqu - mock error")
   667  
   668  	_, err = tx.Query(`SELECT * FROM "items"`)
   669  	tds.EqualError(err, "goqu: mock error")
   670  	tds.NoError(tx.Commit())
   671  }
   672  
   673  func (tds *txdatabaseSuite) TestQueryRow() {
   674  	mDB, mock, err := sqlmock.New()
   675  	tds.NoError(err)
   676  	mock.ExpectBegin()
   677  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   678  		WithArgs().
   679  		WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   680  			FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   681  
   682  	mock.ExpectQuery(`SELECT \* FROM "items"`).
   683  		WithArgs().
   684  		WillReturnError(errors.New("mock error"))
   685  	mock.ExpectCommit()
   686  	db := goqu.New("mock", mDB)
   687  	tx, err := db.Begin()
   688  	tds.NoError(err)
   689  	rows := tx.QueryRow(`SELECT * FROM "items"`)
   690  	var address string
   691  	var name string
   692  	tds.NoError(rows.Scan(&address, &name))
   693  
   694  	rows = tx.QueryRow(`SELECT * FROM "items"`)
   695  	tds.EqualError(rows.Scan(&address, &name), "goqu: mock error")
   696  	tds.NoError(tx.Commit())
   697  }
   698  
   699  func (tds *txdatabaseSuite) TestWrap() {
   700  	mDB, mock, err := sqlmock.New()
   701  	tds.NoError(err)
   702  	mock.ExpectBegin()
   703  	mock.ExpectCommit()
   704  	mock.ExpectBegin()
   705  	mock.ExpectRollback()
   706  	db := goqu.New("mock", mDB)
   707  	tx, err := db.Begin()
   708  	tds.NoError(err)
   709  	tds.NoError(tx.Wrap(func() error {
   710  		return nil
   711  	}))
   712  	tx, err = db.Begin()
   713  	tds.NoError(err)
   714  	tds.EqualError(tx.Wrap(func() error {
   715  		return errors.New("tx error")
   716  	}), "goqu: tx error")
   717  }
   718  
   719  func (tds *txdatabaseSuite) TestDataRace() {
   720  	mDB, mock, err := sqlmock.New()
   721  	tds.NoError(err)
   722  	mock.ExpectBegin()
   723  	db := goqu.New("mock", mDB)
   724  	tx, err := db.Begin()
   725  	tds.NoError(err)
   726  
   727  	const concurrency = 10
   728  
   729  	for i := 0; i < concurrency; i++ {
   730  		mock.ExpectQuery(`SELECT "address", "name" FROM "items"`).
   731  			WithArgs().
   732  			WillReturnRows(sqlmock.NewRows([]string{"address", "name"}).
   733  				FromCSVString("111 Test Addr,Test1\n211 Test Addr,Test2"))
   734  	}
   735  
   736  	wg := sync.WaitGroup{}
   737  	for i := 0; i < concurrency; i++ {
   738  		wg.Add(1)
   739  		go func() {
   740  			defer wg.Done()
   741  
   742  			sql := tx.From("items").Limit(1)
   743  			var item testActionItem
   744  			found, err := sql.ScanStruct(&item)
   745  			tds.NoError(err)
   746  			tds.True(found)
   747  			tds.Equal(item.Address, "111 Test Addr")
   748  			tds.Equal(item.Name, "Test1")
   749  		}()
   750  	}
   751  
   752  	wg.Wait()
   753  	mock.ExpectCommit()
   754  	tds.NoError(tx.Commit())
   755  }
   756  
   757  func TestTxDatabaseSuite(t *testing.T) {
   758  	suite.Run(t, new(txdatabaseSuite))
   759  }
   760  

View as plain text