...

Source file src/github.com/DATA-DOG/go-sqlmock/sqlmock_go18_test.go

Documentation: github.com/DATA-DOG/go-sqlmock

     1  //go:build go1.8
     2  // +build go1.8
     3  
     4  package sqlmock
     5  
     6  import (
     7  	"context"
     8  	"database/sql"
     9  	"errors"
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  func TestContextExecCancel(t *testing.T) {
    15  	t.Parallel()
    16  	db, mock, err := New()
    17  	if err != nil {
    18  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
    19  	}
    20  	defer db.Close()
    21  
    22  	mock.ExpectExec("DELETE FROM users").
    23  		WillDelayFor(time.Second).
    24  		WillReturnResult(NewResult(1, 1))
    25  
    26  	ctx, cancel := context.WithCancel(context.Background())
    27  
    28  	go func() {
    29  		time.Sleep(time.Millisecond * 10)
    30  		cancel()
    31  	}()
    32  
    33  	_, err = db.ExecContext(ctx, "DELETE FROM users")
    34  	if err == nil {
    35  		t.Error("error was expected, but there was none")
    36  	}
    37  
    38  	if err != ErrCancelled {
    39  		t.Errorf("was expecting cancel error, but got: %v", err)
    40  	}
    41  
    42  	_, err = db.ExecContext(ctx, "DELETE FROM users")
    43  	if err != context.Canceled {
    44  		t.Error("error was expected since context was already done, but there was none")
    45  	}
    46  
    47  	if err := mock.ExpectationsWereMet(); err != nil {
    48  		t.Errorf("there were unfulfilled expectations: %s", err)
    49  	}
    50  }
    51  
    52  func TestPreparedStatementContextExecCancel(t *testing.T) {
    53  	t.Parallel()
    54  	db, mock, err := New()
    55  	if err != nil {
    56  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
    57  	}
    58  	defer db.Close()
    59  
    60  	mock.ExpectPrepare("DELETE FROM users").
    61  		ExpectExec().
    62  		WillDelayFor(time.Second).
    63  		WillReturnResult(NewResult(1, 1))
    64  
    65  	ctx, cancel := context.WithCancel(context.Background())
    66  
    67  	go func() {
    68  		time.Sleep(time.Millisecond * 10)
    69  		cancel()
    70  	}()
    71  
    72  	stmt, err := db.Prepare("DELETE FROM users")
    73  	if err != nil {
    74  		t.Errorf("error was not expected, but got: %v", err)
    75  	}
    76  
    77  	_, err = stmt.ExecContext(ctx)
    78  	if err == nil {
    79  		t.Error("error was expected, but there was none")
    80  	}
    81  
    82  	if err != ErrCancelled {
    83  		t.Errorf("was expecting cancel error, but got: %v", err)
    84  	}
    85  
    86  	_, err = stmt.ExecContext(ctx)
    87  	if err != context.Canceled {
    88  		t.Error("error was expected since context was already done, but there was none")
    89  	}
    90  
    91  	if err := mock.ExpectationsWereMet(); err != nil {
    92  		t.Errorf("there were unfulfilled expectations: %s", err)
    93  	}
    94  }
    95  
    96  func TestContextExecWithNamedArg(t *testing.T) {
    97  	t.Parallel()
    98  	db, mock, err := New()
    99  	if err != nil {
   100  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   101  	}
   102  	defer db.Close()
   103  
   104  	mock.ExpectExec("DELETE FROM users").
   105  		WithArgs(sql.Named("id", 5)).
   106  		WillDelayFor(time.Second).
   107  		WillReturnResult(NewResult(1, 1))
   108  
   109  	ctx, cancel := context.WithCancel(context.Background())
   110  
   111  	go func() {
   112  		time.Sleep(time.Millisecond * 10)
   113  		cancel()
   114  	}()
   115  
   116  	_, err = db.ExecContext(ctx, "DELETE FROM users WHERE id = :id", sql.Named("id", 5))
   117  	if err == nil {
   118  		t.Error("error was expected, but there was none")
   119  	}
   120  
   121  	if err != ErrCancelled {
   122  		t.Errorf("was expecting cancel error, but got: %v", err)
   123  	}
   124  
   125  	_, err = db.ExecContext(ctx, "DELETE FROM users WHERE id = :id", sql.Named("id", 5))
   126  	if err != context.Canceled {
   127  		t.Error("error was expected since context was already done, but there was none")
   128  	}
   129  
   130  	if err := mock.ExpectationsWereMet(); err != nil {
   131  		t.Errorf("there were unfulfilled expectations: %s", err)
   132  	}
   133  }
   134  
   135  func TestContextExec(t *testing.T) {
   136  	t.Parallel()
   137  	db, mock, err := New()
   138  	if err != nil {
   139  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   140  	}
   141  	defer db.Close()
   142  
   143  	mock.ExpectExec("DELETE FROM users").
   144  		WillReturnResult(NewResult(1, 1))
   145  
   146  	ctx, cancel := context.WithCancel(context.Background())
   147  
   148  	go func() {
   149  		time.Sleep(time.Millisecond * 10)
   150  		cancel()
   151  	}()
   152  
   153  	res, err := db.ExecContext(ctx, "DELETE FROM users")
   154  	if err != nil {
   155  		t.Errorf("error was not expected, but got: %v", err)
   156  	}
   157  
   158  	affected, err := res.RowsAffected()
   159  	if affected != 1 {
   160  		t.Errorf("expected affected rows 1, but got %v", affected)
   161  	}
   162  
   163  	if err != nil {
   164  		t.Errorf("error was not expected, but got: %v", err)
   165  	}
   166  
   167  	if err := mock.ExpectationsWereMet(); err != nil {
   168  		t.Errorf("there were unfulfilled expectations: %s", err)
   169  	}
   170  }
   171  
   172  func TestContextQueryCancel(t *testing.T) {
   173  	t.Parallel()
   174  	db, mock, err := New()
   175  	if err != nil {
   176  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   177  	}
   178  	defer db.Close()
   179  
   180  	rs := NewRows([]string{"id", "title"}).AddRow(5, "hello world")
   181  
   182  	mock.ExpectQuery("SELECT (.+) FROM articles WHERE id = ?").
   183  		WithArgs(5).
   184  		WillDelayFor(time.Second).
   185  		WillReturnRows(rs)
   186  
   187  	ctx, cancel := context.WithCancel(context.Background())
   188  
   189  	go func() {
   190  		time.Sleep(time.Millisecond * 10)
   191  		cancel()
   192  	}()
   193  
   194  	_, err = db.QueryContext(ctx, "SELECT id, title FROM articles WHERE id = ?", 5)
   195  	if err == nil {
   196  		t.Error("error was expected, but there was none")
   197  	}
   198  
   199  	if err != ErrCancelled {
   200  		t.Errorf("was expecting cancel error, but got: %v", err)
   201  	}
   202  
   203  	_, err = db.QueryContext(ctx, "SELECT id, title FROM articles WHERE id = ?", 5)
   204  	if err != context.Canceled {
   205  		t.Error("error was expected since context was already done, but there was none")
   206  	}
   207  
   208  	if err := mock.ExpectationsWereMet(); err != nil {
   209  		t.Errorf("there were unfulfilled expectations: %s", err)
   210  	}
   211  }
   212  
   213  func TestPreparedStatementContextQueryCancel(t *testing.T) {
   214  	t.Parallel()
   215  	db, mock, err := New()
   216  	if err != nil {
   217  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   218  	}
   219  	defer db.Close()
   220  
   221  	rs := NewRows([]string{"id", "title"}).AddRow(5, "hello world")
   222  
   223  	mock.ExpectPrepare("SELECT (.+) FROM articles WHERE id = ?").
   224  		ExpectQuery().
   225  		WithArgs(5).
   226  		WillDelayFor(time.Second).
   227  		WillReturnRows(rs)
   228  
   229  	ctx, cancel := context.WithCancel(context.Background())
   230  
   231  	go func() {
   232  		time.Sleep(time.Millisecond * 10)
   233  		cancel()
   234  	}()
   235  
   236  	stmt, err := db.Prepare("SELECT id, title FROM articles WHERE id = ?")
   237  	if err != nil {
   238  		t.Errorf("error was not expected, but got: %v", err)
   239  	}
   240  
   241  	_, err = stmt.QueryContext(ctx, 5)
   242  	if err == nil {
   243  		t.Error("error was expected, but there was none")
   244  	}
   245  
   246  	if err != ErrCancelled {
   247  		t.Errorf("was expecting cancel error, but got: %v", err)
   248  	}
   249  
   250  	_, err = stmt.QueryContext(ctx, 5)
   251  	if err != context.Canceled {
   252  		t.Error("error was expected since context was already done, but there was none")
   253  	}
   254  
   255  	if err := mock.ExpectationsWereMet(); err != nil {
   256  		t.Errorf("there were unfulfilled expectations: %s", err)
   257  	}
   258  }
   259  
   260  func TestContextQuery(t *testing.T) {
   261  	t.Parallel()
   262  	db, mock, err := New()
   263  	if err != nil {
   264  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   265  	}
   266  	defer db.Close()
   267  
   268  	rs := NewRows([]string{"id", "title"}).AddRow(5, "hello world")
   269  
   270  	mock.ExpectQuery("SELECT (.+) FROM articles WHERE id =").
   271  		WithArgs(sql.Named("id", 5)).
   272  		WillDelayFor(time.Millisecond * 3).
   273  		WillReturnRows(rs)
   274  
   275  	ctx, cancel := context.WithCancel(context.Background())
   276  
   277  	go func() {
   278  		time.Sleep(time.Millisecond * 10)
   279  		cancel()
   280  	}()
   281  
   282  	rows, err := db.QueryContext(ctx, "SELECT id, title FROM articles WHERE id = :id", sql.Named("id", 5))
   283  	if err != nil {
   284  		t.Errorf("error was not expected, but got: %v", err)
   285  	}
   286  
   287  	if !rows.Next() {
   288  		t.Error("expected one row, but there was none")
   289  	}
   290  
   291  	if err := mock.ExpectationsWereMet(); err != nil {
   292  		t.Errorf("there were unfulfilled expectations: %s", err)
   293  	}
   294  }
   295  
   296  func TestContextBeginCancel(t *testing.T) {
   297  	t.Parallel()
   298  	db, mock, err := New()
   299  	if err != nil {
   300  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   301  	}
   302  	defer db.Close()
   303  
   304  	mock.ExpectBegin().WillDelayFor(time.Second)
   305  
   306  	ctx, cancel := context.WithCancel(context.Background())
   307  
   308  	go func() {
   309  		time.Sleep(time.Millisecond * 10)
   310  		cancel()
   311  	}()
   312  
   313  	_, err = db.BeginTx(ctx, nil)
   314  	if err == nil {
   315  		t.Error("error was expected, but there was none")
   316  	}
   317  
   318  	if err != ErrCancelled {
   319  		t.Errorf("was expecting cancel error, but got: %v", err)
   320  	}
   321  
   322  	_, err = db.BeginTx(ctx, nil)
   323  	if err != context.Canceled {
   324  		t.Error("error was expected since context was already done, but there was none")
   325  	}
   326  
   327  	if err := mock.ExpectationsWereMet(); err != nil {
   328  		t.Errorf("there were unfulfilled expectations: %s", err)
   329  	}
   330  }
   331  
   332  func TestContextBegin(t *testing.T) {
   333  	t.Parallel()
   334  	db, mock, err := New()
   335  	if err != nil {
   336  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   337  	}
   338  	defer db.Close()
   339  
   340  	mock.ExpectBegin().WillDelayFor(time.Millisecond * 3)
   341  
   342  	ctx, cancel := context.WithCancel(context.Background())
   343  
   344  	go func() {
   345  		time.Sleep(time.Millisecond * 10)
   346  		cancel()
   347  	}()
   348  
   349  	tx, err := db.BeginTx(ctx, nil)
   350  	if err != nil {
   351  		t.Errorf("error was not expected, but got: %v", err)
   352  	}
   353  
   354  	if tx == nil {
   355  		t.Error("expected tx, but there was nil")
   356  	}
   357  
   358  	if err := mock.ExpectationsWereMet(); err != nil {
   359  		t.Errorf("there were unfulfilled expectations: %s", err)
   360  	}
   361  }
   362  
   363  func TestContextPrepareCancel(t *testing.T) {
   364  	t.Parallel()
   365  	db, mock, err := New()
   366  	if err != nil {
   367  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   368  	}
   369  	defer db.Close()
   370  
   371  	mock.ExpectPrepare("SELECT").WillDelayFor(time.Second)
   372  
   373  	ctx, cancel := context.WithCancel(context.Background())
   374  
   375  	go func() {
   376  		time.Sleep(time.Millisecond * 10)
   377  		cancel()
   378  	}()
   379  
   380  	_, err = db.PrepareContext(ctx, "SELECT")
   381  	if err == nil {
   382  		t.Error("error was expected, but there was none")
   383  	}
   384  
   385  	if err != ErrCancelled {
   386  		t.Errorf("was expecting cancel error, but got: %v", err)
   387  	}
   388  
   389  	_, err = db.PrepareContext(ctx, "SELECT")
   390  	if err != context.Canceled {
   391  		t.Error("error was expected since context was already done, but there was none")
   392  	}
   393  
   394  	if err := mock.ExpectationsWereMet(); err != nil {
   395  		t.Errorf("there were unfulfilled expectations: %s", err)
   396  	}
   397  }
   398  
   399  func TestContextPrepare(t *testing.T) {
   400  	t.Parallel()
   401  	db, mock, err := New()
   402  	if err != nil {
   403  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   404  	}
   405  	defer db.Close()
   406  
   407  	mock.ExpectPrepare("SELECT").WillDelayFor(time.Millisecond * 3)
   408  
   409  	ctx, cancel := context.WithCancel(context.Background())
   410  
   411  	go func() {
   412  		time.Sleep(time.Millisecond * 10)
   413  		cancel()
   414  	}()
   415  
   416  	stmt, err := db.PrepareContext(ctx, "SELECT")
   417  	if err != nil {
   418  		t.Errorf("error was not expected, but got: %v", err)
   419  	}
   420  
   421  	if stmt == nil {
   422  		t.Error("expected stmt, but there was nil")
   423  	}
   424  
   425  	if err := mock.ExpectationsWereMet(); err != nil {
   426  		t.Errorf("there were unfulfilled expectations: %s", err)
   427  	}
   428  }
   429  
   430  func TestContextExecErrorDelay(t *testing.T) {
   431  	t.Parallel()
   432  	db, mock, err := New()
   433  	if err != nil {
   434  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   435  	}
   436  	defer db.Close()
   437  
   438  	// test that return of error is delayed
   439  	var delay time.Duration = 100 * time.Millisecond
   440  	mock.ExpectExec("^INSERT INTO articles").
   441  		WillReturnError(errors.New("slow fail")).
   442  		WillDelayFor(delay)
   443  
   444  	start := time.Now()
   445  	res, err := db.ExecContext(context.Background(), "INSERT INTO articles (title) VALUES (?)", "hello")
   446  	stop := time.Now()
   447  
   448  	if res != nil {
   449  		t.Errorf("result was not expected, was expecting nil")
   450  	}
   451  
   452  	if err == nil {
   453  		t.Errorf("error was expected, was not expecting nil")
   454  	}
   455  
   456  	if err.Error() != "slow fail" {
   457  		t.Errorf("error '%s' was not expected, was expecting '%s'", err.Error(), "slow fail")
   458  	}
   459  
   460  	elapsed := stop.Sub(start)
   461  	if elapsed < delay {
   462  		t.Errorf("expecting a delay of %v before error, actual delay was %v", delay, elapsed)
   463  	}
   464  
   465  	// also test that return of error is not delayed
   466  	mock.ExpectExec("^INSERT INTO articles").WillReturnError(errors.New("fast fail"))
   467  
   468  	start = time.Now()
   469  	db.ExecContext(context.Background(), "INSERT INTO articles (title) VALUES (?)", "hello")
   470  	stop = time.Now()
   471  
   472  	elapsed = stop.Sub(start)
   473  	if elapsed > delay {
   474  		t.Errorf("expecting a delay of less than %v before error, actual delay was %v", delay, elapsed)
   475  	}
   476  }
   477  
   478  // TestMonitorPingsDisabled verifies backwards-compatibility with behaviour of the library in which
   479  // calls to Ping are not mocked out. It verifies this persists when the user does not enable the new
   480  // behaviour.
   481  func TestMonitorPingsDisabled(t *testing.T) {
   482  	t.Parallel()
   483  	db, mock, err := New()
   484  	if err != nil {
   485  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   486  	}
   487  	defer db.Close()
   488  
   489  	// When monitoring of pings is not enabled in the mock, calling Ping should have no effect.
   490  	err = db.Ping()
   491  	if err != nil {
   492  		t.Errorf("monitoring of pings is not enabled so did not expect error from Ping, got '%s'", err)
   493  	}
   494  
   495  	// Calling ExpectPing should also not register any expectations in the mock. The return from
   496  	// ExpectPing should be nil.
   497  	expectation := mock.ExpectPing()
   498  	if expectation != nil {
   499  		t.Errorf("expected ExpectPing to return a nil pointer when monitoring of pings is not enabled")
   500  	}
   501  
   502  	err = mock.ExpectationsWereMet()
   503  	if err != nil {
   504  		t.Errorf("monitoring of pings is not enabled so ExpectPing should not register an expectation, got '%s'", err)
   505  	}
   506  }
   507  
   508  func TestPingExpectations(t *testing.T) {
   509  	t.Parallel()
   510  	db, mock, err := New(MonitorPingsOption(true))
   511  	if err != nil {
   512  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   513  	}
   514  	defer db.Close()
   515  
   516  	mock.ExpectPing()
   517  	if err := db.Ping(); err != nil {
   518  		t.Fatal(err)
   519  	}
   520  
   521  	if err := mock.ExpectationsWereMet(); err != nil {
   522  		t.Errorf("there were unfulfilled expectations: %s", err)
   523  	}
   524  }
   525  
   526  func TestPingExpectationsErrorDelay(t *testing.T) {
   527  	t.Parallel()
   528  	db, mock, err := New(MonitorPingsOption(true))
   529  	if err != nil {
   530  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   531  	}
   532  	defer db.Close()
   533  
   534  	var delay time.Duration
   535  	delay = 100 * time.Millisecond
   536  	mock.ExpectPing().
   537  		WillReturnError(errors.New("slow fail")).
   538  		WillDelayFor(delay)
   539  
   540  	start := time.Now()
   541  	err = db.Ping()
   542  	stop := time.Now()
   543  
   544  	if err == nil {
   545  		t.Errorf("result was not expected, was not expecting nil error")
   546  	}
   547  
   548  	if err.Error() != "slow fail" {
   549  		t.Errorf("error '%s' was not expected, was expecting '%s'", err.Error(), "slow fail")
   550  	}
   551  
   552  	elapsed := stop.Sub(start)
   553  	if elapsed < delay {
   554  		t.Errorf("expecting a delay of %v before error, actual delay was %v", delay, elapsed)
   555  	}
   556  
   557  	mock.ExpectPing().WillReturnError(errors.New("fast fail"))
   558  
   559  	start = time.Now()
   560  	db.Ping()
   561  	stop = time.Now()
   562  
   563  	elapsed = stop.Sub(start)
   564  	if elapsed > delay {
   565  		t.Errorf("expecting a delay of less than %v before error, actual delay was %v", delay, elapsed)
   566  	}
   567  }
   568  
   569  func TestPingExpectationsMissingPing(t *testing.T) {
   570  	t.Parallel()
   571  	db, mock, err := New(MonitorPingsOption(true))
   572  	if err != nil {
   573  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   574  	}
   575  	defer db.Close()
   576  
   577  	mock.ExpectPing()
   578  
   579  	if err = mock.ExpectationsWereMet(); err == nil {
   580  		t.Fatalf("was expecting an error, but there wasn't one")
   581  	}
   582  }
   583  
   584  func TestPingExpectationsUnexpectedPing(t *testing.T) {
   585  	t.Parallel()
   586  	db, _, err := New(MonitorPingsOption(true))
   587  	if err != nil {
   588  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   589  	}
   590  	defer db.Close()
   591  
   592  	if err = db.Ping(); err == nil {
   593  		t.Fatalf("was expecting an error, but there wasn't any")
   594  	}
   595  }
   596  
   597  func TestPingOrderedWrongOrder(t *testing.T) {
   598  	t.Parallel()
   599  	db, mock, err := New(MonitorPingsOption(true))
   600  	if err != nil {
   601  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   602  	}
   603  	defer db.Close()
   604  
   605  	mock.ExpectBegin()
   606  	mock.ExpectPing()
   607  	mock.MatchExpectationsInOrder(true)
   608  
   609  	if err = db.Ping(); err == nil {
   610  		t.Fatalf("was expecting an error, but there wasn't any")
   611  	}
   612  }
   613  
   614  func TestPingExpectationsContextTimeout(t *testing.T) {
   615  	t.Parallel()
   616  	db, mock, err := New(MonitorPingsOption(true))
   617  	if err != nil {
   618  		t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
   619  	}
   620  	defer db.Close()
   621  
   622  	mock.ExpectPing().WillDelayFor(time.Hour)
   623  
   624  	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
   625  	defer cancel()
   626  
   627  	doneCh := make(chan struct{})
   628  	go func() {
   629  		err = db.PingContext(ctx)
   630  		close(doneCh)
   631  	}()
   632  
   633  	select {
   634  	case <-doneCh:
   635  		if err != ErrCancelled {
   636  			t.Errorf("expected error '%s' to be returned from Ping, but got '%s'", ErrCancelled, err)
   637  		}
   638  	case <-time.After(time.Second):
   639  		t.Errorf("expected Ping to return after context timeout, but it did not in a timely fashion")
   640  	}
   641  }
   642  

View as plain text