1
2
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
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
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
479
480
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
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
496
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