1
2
3
4
5
6
7
8
9
10
11
12
13 package kivik
14
15 import (
16 "context"
17 "errors"
18 "fmt"
19 "io"
20 "net/http"
21 "testing"
22 "time"
23
24 "gitlab.com/flimzy/testy"
25
26 "github.com/go-kivik/kivik/v4/driver"
27 internal "github.com/go-kivik/kivik/v4/int/errors"
28 "github.com/go-kivik/kivik/v4/int/mock"
29 )
30
31 func TestNew(t *testing.T) {
32 tests := []struct {
33 name string
34 driver driver.Driver
35 driverName string
36 dsn string
37 expected *Client
38 status int
39 err string
40 }{
41 {
42 name: "Unregistered driver",
43 driverName: "unregistered",
44 dsn: "unf",
45 status: http.StatusBadRequest,
46 err: `kivik: unknown driver "unregistered" (forgotten import?)`,
47 },
48 {
49 name: "connection error",
50 driver: &mock.Driver{
51 NewClientFunc: func(_ string, _ driver.Options) (driver.Client, error) {
52 return nil, errors.New("connection error")
53 },
54 },
55 driverName: "foo",
56 status: http.StatusInternalServerError,
57 err: "connection error",
58 },
59 {
60 name: "success",
61 driver: &mock.Driver{
62 NewClientFunc: func(dsn string, _ driver.Options) (driver.Client, error) {
63 if dsn != "oink" {
64 return nil, fmt.Errorf("Unexpected DSN: %s", dsn)
65 }
66 return &mock.Client{ID: "foo"}, nil
67 },
68 },
69 driverName: "bar",
70 dsn: "oink",
71 expected: &Client{
72 dsn: "oink",
73 driverName: "bar",
74 driverClient: &mock.Client{ID: "foo"},
75 },
76 },
77 }
78 for _, test := range tests {
79 t.Run(test.name, func(t *testing.T) {
80 if test.driver != nil {
81 Register(test.driverName, test.driver)
82 }
83 result, err := New(test.driverName, test.dsn)
84 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
85 t.Error(d)
86 }
87 if d := testy.DiffInterface(test.expected, result); d != nil {
88 t.Error(d)
89 }
90 })
91 }
92 }
93
94 func TestClientGetters(t *testing.T) {
95 driverName := "foo"
96 dsn := "bar"
97 c := &Client{
98 driverName: driverName,
99 dsn: dsn,
100 }
101
102 t.Run("Driver", func(t *testing.T) {
103 result := c.Driver()
104 if result != driverName {
105 t.Errorf("Unexpected result: %s", result)
106 }
107 })
108
109 t.Run("DSN", func(t *testing.T) {
110 result := c.DSN()
111 if result != dsn {
112 t.Errorf("Unexpected result: %s", result)
113 }
114 })
115 }
116
117 func TestVersion(t *testing.T) {
118 tests := []struct {
119 name string
120 client *Client
121 expected *ServerVersion
122 status int
123 err string
124 }{
125 {
126 name: "db error",
127 client: &Client{
128 driverClient: &mock.Client{
129 VersionFunc: func(context.Context) (*driver.Version, error) {
130 return nil, errors.New("db error")
131 },
132 },
133 },
134 status: http.StatusInternalServerError,
135 err: "db error",
136 },
137 {
138 name: "success",
139 client: &Client{
140 driverClient: &mock.Client{
141 VersionFunc: func(context.Context) (*driver.Version, error) {
142 return &driver.Version{Version: "foo"}, nil
143 },
144 },
145 },
146 expected: &ServerVersion{Version: "foo"},
147 },
148 {
149 name: "closed",
150 client: &Client{
151 closed: true,
152 },
153 status: http.StatusServiceUnavailable,
154 err: "kivik: client closed",
155 },
156 }
157 for _, test := range tests {
158 t.Run(test.name, func(t *testing.T) {
159 result, err := test.client.Version(context.Background())
160 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
161 t.Error(d)
162 }
163 if d := testy.DiffInterface(test.expected, result); d != nil {
164 t.Error(d)
165 }
166 })
167 }
168 }
169
170 func TestDB(t *testing.T) {
171 type Test struct {
172 name string
173 client *Client
174 dbName string
175 options Option
176 expected *DB
177 status int
178 err string
179 }
180 tests := []Test{
181 {
182 name: "db error",
183 client: &Client{
184 driverClient: &mock.Client{
185 DBFunc: func(string, driver.Options) (driver.DB, error) {
186 return nil, errors.New("db error")
187 },
188 },
189 },
190 status: http.StatusInternalServerError,
191 err: "db error",
192 },
193 func() Test {
194 client := &Client{
195 driverClient: &mock.Client{
196 DBFunc: func(dbName string, opts driver.Options) (driver.DB, error) {
197 expectedDBName := "foo"
198 gotOpts := map[string]interface{}{}
199 opts.Apply(gotOpts)
200 wantOpts := map[string]interface{}{"foo": 123}
201 if dbName != expectedDBName {
202 return nil, fmt.Errorf("Unexpected dbname: %s", dbName)
203 }
204 if d := testy.DiffInterface(wantOpts, gotOpts); d != nil {
205 return nil, fmt.Errorf("Unexpected options:\n%s", d)
206 }
207 return &mock.DB{ID: "abc"}, nil
208 },
209 },
210 }
211 return Test{
212 name: "success",
213 client: client,
214 dbName: "foo",
215 options: Param("foo", 123),
216 expected: &DB{
217 client: client,
218 name: "foo",
219 driverDB: &mock.DB{ID: "abc"},
220 },
221 }
222 }(),
223 }
224 for _, test := range tests {
225 t.Run(test.name, func(t *testing.T) {
226 result := test.client.DB(test.dbName, test.options)
227 err := result.Err()
228 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
229 t.Error(d)
230 }
231 if err != nil {
232 return
233 }
234 if d := testy.DiffInterface(test.expected, result); d != nil {
235 t.Error(d)
236 }
237 })
238 }
239 }
240
241 func TestAllDBs(t *testing.T) {
242 tests := []struct {
243 name string
244 client *Client
245 options Option
246 expected []string
247 status int
248 err string
249 }{
250 {
251 name: "db error",
252 client: &Client{
253 driverClient: &mock.Client{
254 AllDBsFunc: func(context.Context, driver.Options) ([]string, error) {
255 return nil, errors.New("db error")
256 },
257 },
258 },
259 status: http.StatusInternalServerError,
260 err: "db error",
261 },
262 {
263 name: "success",
264 client: &Client{
265 driverClient: &mock.Client{
266 AllDBsFunc: func(_ context.Context, options driver.Options) ([]string, error) {
267 gotOptions := map[string]interface{}{}
268 options.Apply(gotOptions)
269 expectedOptions := map[string]interface{}{"foo": 123}
270 if d := testy.DiffInterface(expectedOptions, gotOptions); d != nil {
271 return nil, fmt.Errorf("Unexpected options:\n%s", d)
272 }
273 return []string{"a", "b", "c"}, nil
274 },
275 },
276 },
277 options: Param("foo", 123),
278 expected: []string{"a", "b", "c"},
279 },
280 {
281 name: "closed",
282 client: &Client{
283 closed: true,
284 },
285 status: http.StatusServiceUnavailable,
286 err: "kivik: client closed",
287 },
288 }
289 for _, test := range tests {
290 t.Run(test.name, func(t *testing.T) {
291 result, err := test.client.AllDBs(context.Background(), test.options)
292 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
293 t.Error(d)
294 }
295 if d := testy.DiffInterface(test.expected, result); d != nil {
296 t.Error(d)
297 }
298 })
299 }
300 }
301
302 func TestDBExists(t *testing.T) {
303 tests := []struct {
304 name string
305 client *Client
306 dbName string
307 options Option
308 expected bool
309 status int
310 err string
311 }{
312 {
313 name: "db error",
314 client: &Client{
315 driverClient: &mock.Client{
316 DBExistsFunc: func(context.Context, string, driver.Options) (bool, error) {
317 return false, errors.New("db error")
318 },
319 },
320 },
321 status: http.StatusInternalServerError,
322 err: "db error",
323 },
324 {
325 name: "success",
326 client: &Client{
327 driverClient: &mock.Client{
328 DBExistsFunc: func(_ context.Context, dbName string, opts driver.Options) (bool, error) {
329 expectedDBName := "foo"
330 gotOpts := map[string]interface{}{}
331 opts.Apply(gotOpts)
332 expectedOpts := map[string]interface{}{"foo": 123}
333 if dbName != expectedDBName {
334 return false, fmt.Errorf("Unexpected db name: %s", dbName)
335 }
336 if d := testy.DiffInterface(expectedOpts, gotOpts); d != nil {
337 return false, fmt.Errorf("Unexpected opts:\n%s", d)
338 }
339 return true, nil
340 },
341 },
342 },
343 dbName: "foo",
344 options: Param("foo", 123),
345 expected: true,
346 },
347 {
348 name: "closed",
349 client: &Client{
350 closed: true,
351 },
352 status: http.StatusServiceUnavailable,
353 err: "kivik: client closed",
354 },
355 }
356 for _, test := range tests {
357 t.Run(test.name, func(t *testing.T) {
358 result, err := test.client.DBExists(context.Background(), test.dbName, test.options)
359 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
360 t.Error(d)
361 }
362 if test.expected != result {
363 t.Errorf("Unexpected result: %v", result)
364 }
365 })
366 }
367 }
368
369 func TestCreateDB(t *testing.T) {
370 tests := []struct {
371 name string
372 client *Client
373 dbName string
374 options Option
375 status int
376 err string
377 }{
378 {
379 name: "db error",
380 client: &Client{
381 driverClient: &mock.Client{
382 CreateDBFunc: func(context.Context, string, driver.Options) error {
383 return errors.New("db error")
384 },
385 },
386 },
387 status: http.StatusInternalServerError,
388 err: "db error",
389 },
390 {
391 name: "success",
392 client: &Client{
393 driverClient: &mock.Client{
394 CreateDBFunc: func(_ context.Context, dbName string, options driver.Options) error {
395 expectedDBName := "foo"
396 wantOpts := map[string]interface{}{"foo": 123}
397 gotOpts := map[string]interface{}{}
398 options.Apply(gotOpts)
399 if dbName != expectedDBName {
400 return fmt.Errorf("Unexpected dbname: %s", dbName)
401 }
402 if d := testy.DiffInterface(wantOpts, gotOpts); d != nil {
403 return fmt.Errorf("Unexpected opts:\n%s", d)
404 }
405 return nil
406 },
407 DBFunc: func(string, driver.Options) (driver.DB, error) {
408 return &mock.DB{ID: "abc"}, nil
409 },
410 },
411 },
412 dbName: "foo",
413 options: Param("foo", 123),
414 },
415 {
416 name: "closed",
417 client: &Client{
418 closed: true,
419 },
420 status: http.StatusServiceUnavailable,
421 err: "kivik: client closed",
422 },
423 }
424 for _, test := range tests {
425 t.Run(test.name, func(t *testing.T) {
426 opts := test.options
427 if opts == nil {
428 opts = mock.NilOption
429 }
430 err := test.client.CreateDB(context.Background(), test.dbName, opts)
431 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
432 t.Error(d)
433 }
434 })
435 }
436 }
437
438 func TestDestroyDB(t *testing.T) {
439 tests := []struct {
440 name string
441 client *Client
442 dbName string
443 options Option
444 status int
445 err string
446 }{
447 {
448 name: "db error",
449 client: &Client{
450 driverClient: &mock.Client{
451 DestroyDBFunc: func(context.Context, string, driver.Options) error {
452 return errors.New("db error")
453 },
454 },
455 },
456 status: http.StatusInternalServerError,
457 err: "db error",
458 },
459 {
460 name: "success",
461 client: &Client{
462 driverClient: &mock.Client{
463 DestroyDBFunc: func(_ context.Context, dbName string, options driver.Options) error {
464 expectedDBName := "foo"
465 gotOpts := map[string]interface{}{}
466 options.Apply(gotOpts)
467 expectedOpts := map[string]interface{}{"foo": 123}
468 if dbName != expectedDBName {
469 return fmt.Errorf("Unexpected dbname: %s", dbName)
470 }
471 if d := testy.DiffInterface(expectedOpts, gotOpts); d != nil {
472 return fmt.Errorf("Unexpected opts:\n%s", d)
473 }
474 return nil
475 },
476 },
477 },
478 dbName: "foo",
479 options: Param("foo", 123),
480 },
481 {
482 name: "closed",
483 client: &Client{
484 closed: true,
485 },
486 status: http.StatusServiceUnavailable,
487 err: "kivik: client closed",
488 },
489 }
490 for _, test := range tests {
491 t.Run(test.name, func(t *testing.T) {
492 opts := test.options
493 if opts == nil {
494 opts = mock.NilOption
495 }
496 err := test.client.DestroyDB(context.Background(), test.dbName, opts)
497 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
498 t.Error(d)
499 }
500 })
501 }
502 }
503
504 func TestDBsStats(t *testing.T) {
505 tests := []struct {
506 name string
507 client *Client
508 dbnames []string
509 expected []*DBStats
510 err string
511 status int
512 }{
513 {
514 name: "fallback to old driver",
515 client: &Client{
516 driverClient: &mock.Client{
517 DBFunc: func(name string, _ driver.Options) (driver.DB, error) {
518 switch name {
519 case "foo":
520 return &mock.DB{
521 StatsFunc: func(context.Context) (*driver.DBStats, error) {
522 return &driver.DBStats{Name: "foo", DiskSize: 123}, nil
523 },
524 }, nil
525 case "bar":
526 return &mock.DB{
527 StatsFunc: func(context.Context) (*driver.DBStats, error) {
528 return &driver.DBStats{Name: "bar", DiskSize: 321}, nil
529 },
530 }, nil
531 default:
532 return nil, errors.New("not found")
533 }
534 },
535 },
536 },
537 dbnames: []string{"foo", "bar"},
538 expected: []*DBStats{
539 {Name: "foo", DiskSize: 123},
540 {Name: "bar", DiskSize: 321},
541 },
542 },
543 {
544 name: "fallback due to old server",
545 client: &Client{
546 driverClient: &mock.Client{
547 DBFunc: func(name string, _ driver.Options) (driver.DB, error) {
548 switch name {
549 case "foo":
550 return &mock.DB{
551 StatsFunc: func(context.Context) (*driver.DBStats, error) {
552 return &driver.DBStats{Name: "foo", DiskSize: 123}, nil
553 },
554 }, nil
555 case "bar":
556 return &mock.DB{
557 StatsFunc: func(context.Context) (*driver.DBStats, error) {
558 return &driver.DBStats{Name: "bar", DiskSize: 321}, nil
559 },
560 }, nil
561 default:
562 return nil, errors.New("not found")
563 }
564 },
565 },
566 },
567 dbnames: []string{"foo", "bar"},
568 expected: []*DBStats{
569 {Name: "foo", DiskSize: 123},
570 {Name: "bar", DiskSize: 321},
571 },
572 },
573 {
574 name: "native success",
575 client: &Client{
576 driverClient: &mock.DBsStatser{
577 DBsStatsFunc: func(context.Context, []string) ([]*driver.DBStats, error) {
578 return []*driver.DBStats{
579 {Name: "foo", DiskSize: 123},
580 {Name: "bar", DiskSize: 321},
581 }, nil
582 },
583 },
584 },
585 dbnames: []string{"foo", "bar"},
586 expected: []*DBStats{
587 {Name: "foo", DiskSize: 123},
588 {Name: "bar", DiskSize: 321},
589 },
590 },
591 {
592 name: "native error",
593 client: &Client{
594 driverClient: &mock.DBsStatser{
595 DBsStatsFunc: func(context.Context, []string) ([]*driver.DBStats, error) {
596 return nil, errors.New("native failure")
597 },
598 },
599 },
600 dbnames: []string{"foo", "bar"},
601 err: "native failure",
602 status: 500,
603 },
604 {
605 name: "fallback error",
606 client: &Client{
607 driverClient: &mock.Client{
608 DBFunc: func(_ string, _ driver.Options) (driver.DB, error) {
609 return &mock.DB{
610 StatsFunc: func(context.Context) (*driver.DBStats, error) {
611 return nil, errors.New("fallback failure")
612 },
613 }, nil
614 },
615 },
616 },
617 dbnames: []string{"foo", "bar"},
618 err: "fallback failure",
619 status: http.StatusInternalServerError,
620 },
621 {
622 name: "fallback db connect error",
623 client: &Client{
624 driverClient: &mock.Client{
625 DBFunc: func(string, driver.Options) (driver.DB, error) {
626 return nil, errors.New("db conn failure")
627 },
628 },
629 },
630 dbnames: []string{"foo", "bar"},
631 err: "db conn failure",
632 status: http.StatusInternalServerError,
633 },
634 {
635 name: "closed",
636 client: &Client{
637 closed: true,
638 },
639 status: http.StatusServiceUnavailable,
640 err: "kivik: client closed",
641 },
642 }
643 for _, test := range tests {
644 t.Run(test.name, func(t *testing.T) {
645 stats, err := test.client.DBsStats(context.Background(), test.dbnames)
646 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
647 t.Error(d)
648 }
649 if d := testy.DiffInterface(test.expected, stats); d != nil {
650 t.Error(d)
651 }
652 })
653 }
654 }
655
656 func TestPing(t *testing.T) {
657 type pingTest struct {
658 name string
659 client *Client
660 expected bool
661 err string
662 }
663 tests := []pingTest{
664 {
665 name: "non-pinger",
666 client: &Client{
667 driverClient: &mock.Client{
668 VersionFunc: func(context.Context) (*driver.Version, error) {
669 return &driver.Version{}, nil
670 },
671 },
672 },
673 expected: true,
674 },
675 {
676 name: "pinger",
677 client: &Client{
678 driverClient: &mock.Pinger{
679 PingFunc: func(context.Context) (bool, error) {
680 return true, nil
681 },
682 },
683 },
684 expected: true,
685 },
686 {
687 name: "closed",
688 client: &Client{
689 closed: true,
690 },
691 err: "kivik: client closed",
692 },
693 }
694
695 for _, test := range tests {
696 t.Run(test.name, func(t *testing.T) {
697 result, err := test.client.Ping(context.Background())
698 if !testy.ErrorMatches(test.err, err) {
699 t.Errorf("Unexpected error: %s", err)
700 }
701 if result != test.expected {
702 t.Errorf("Unexpected result: %t", result)
703 }
704 })
705 }
706 }
707
708 func TestClientClose(t *testing.T) {
709 t.Parallel()
710
711 type tst struct {
712 client *Client
713 err string
714 }
715 tests := testy.NewTable()
716 tests.Add("non-closer", tst{
717 client: &Client{driverClient: &mock.Client{}},
718 })
719 tests.Add("error", tst{
720 client: &Client{driverClient: &mock.ClientCloser{
721 CloseFunc: func() error {
722 return errors.New("close err")
723 },
724 }},
725 err: "close err",
726 })
727 tests.Add("success", tst{
728 client: &Client{driverClient: &mock.ClientCloser{
729 CloseFunc: func() error {
730 return nil
731 },
732 }},
733 })
734
735 tests.Run(t, func(t *testing.T, test tst) {
736 t.Parallel()
737 err := test.client.Close()
738 if !testy.ErrorMatches(test.err, err) {
739 t.Errorf("Unexpected error: %s", err)
740 }
741 })
742
743 t.Run("blocks", func(t *testing.T) {
744 t.Parallel()
745
746 const delay = 100 * time.Millisecond
747
748 type tt struct {
749 client driver.Client
750 work func(*testing.T, *Client)
751 }
752
753 tests := testy.NewTable()
754 tests.Add("AllDBs", tt{
755 client: &mock.Client{
756 AllDBsFunc: func(context.Context, driver.Options) ([]string, error) {
757 time.Sleep(delay)
758 return nil, nil
759 },
760 },
761 work: func(_ *testing.T, c *Client) {
762 _, _ = c.AllDBs(context.Background())
763 },
764 })
765 tests.Add("DBExists", tt{
766 client: &mock.Client{
767 DBExistsFunc: func(context.Context, string, driver.Options) (bool, error) {
768 time.Sleep(delay)
769 return true, nil
770 },
771 },
772 work: func(_ *testing.T, c *Client) {
773 _, _ = c.DBExists(context.Background(), "x")
774 },
775 })
776 tests.Add("CreateDB", tt{
777 client: &mock.Client{
778 CreateDBFunc: func(context.Context, string, driver.Options) error {
779 time.Sleep(delay)
780 return nil
781 },
782 },
783 work: func(_ *testing.T, c *Client) {
784 _ = c.CreateDB(context.Background(), "x")
785 },
786 })
787 tests.Add("DestroyDB", tt{
788 client: &mock.Client{
789 DestroyDBFunc: func(context.Context, string, driver.Options) error {
790 time.Sleep(delay)
791 return nil
792 },
793 },
794 work: func(_ *testing.T, c *Client) {
795 _ = c.DestroyDB(context.Background(), "x")
796 },
797 })
798 tests.Add("DBsStats", tt{
799 client: &mock.DBsStatser{
800 DBsStatsFunc: func(context.Context, []string) ([]*driver.DBStats, error) {
801 time.Sleep(delay)
802 return nil, nil
803 },
804 },
805 work: func(_ *testing.T, c *Client) {
806 _, _ = c.DBsStats(context.Background(), nil)
807 },
808 })
809 tests.Add("Ping", tt{
810 client: &mock.Pinger{
811 PingFunc: func(context.Context) (bool, error) {
812 time.Sleep(delay)
813 return true, nil
814 },
815 },
816 work: func(_ *testing.T, c *Client) {
817 _, _ = c.Ping(context.Background())
818 },
819 })
820 tests.Add("Version", tt{
821 client: &mock.Client{
822 VersionFunc: func(context.Context) (*driver.Version, error) {
823 time.Sleep(delay)
824 return &driver.Version{}, nil
825 },
826 },
827 work: func(_ *testing.T, c *Client) {
828 _, _ = c.Version(context.Background())
829 },
830 })
831 tests.Add("DBUpdates", tt{
832 client: &mock.DBUpdater{
833 DBUpdatesFunc: func(context.Context, driver.Options) (driver.DBUpdates, error) {
834 return &mock.DBUpdates{
835 NextFunc: func(*driver.DBUpdate) error {
836 time.Sleep(delay)
837 return io.EOF
838 },
839 }, nil
840 },
841 },
842 work: func(t *testing.T, c *Client) {
843 u := c.DBUpdates(context.Background())
844 if err := u.Err(); err != nil {
845 t.Fatal(err)
846 }
847 for u.Next() {
848 }
849 if u.Err() != nil {
850 t.Fatal(u.Err())
851 }
852 },
853 })
854 tests.Add("AllDocs", tt{
855 client: &mock.Client{
856 DBFunc: func(string, driver.Options) (driver.DB, error) {
857 return &mock.DB{
858 AllDocsFunc: func(context.Context, driver.Options) (driver.Rows, error) {
859 return &mock.Rows{
860 NextFunc: func(*driver.Row) error {
861 time.Sleep(delay)
862 return io.EOF
863 },
864 }, nil
865 },
866 }, nil
867 },
868 },
869 work: func(t *testing.T, c *Client) {
870 u := c.DB("foo").AllDocs(context.Background())
871 for u.Next() {
872 }
873 if u.Err() != nil {
874 t.Fatal(u.Err())
875 }
876 },
877 })
878 tests.Add("BulkDocs", tt{
879 client: &mock.Client{
880 DBFunc: func(string, driver.Options) (driver.DB, error) {
881 return &mock.BulkDocer{
882 BulkDocsFunc: func(context.Context, []interface{}, driver.Options) ([]driver.BulkResult, error) {
883 time.Sleep(delay)
884 return nil, nil
885 },
886 }, nil
887 },
888 },
889 work: func(t *testing.T, c *Client) {
890 _, err := c.DB("foo").BulkDocs(context.Background(), []interface{}{
891 map[string]string{"_id": "foo"},
892 })
893 if err != nil {
894 t.Fatal(err)
895 }
896 },
897 })
898 tests.Add("BulkGet", tt{
899 client: &mock.Client{
900 DBFunc: func(string, driver.Options) (driver.DB, error) {
901 return &mock.BulkGetter{
902 BulkGetFunc: func(context.Context, []driver.BulkGetReference, driver.Options) (driver.Rows, error) {
903 return &mock.Rows{
904 NextFunc: func(*driver.Row) error {
905 time.Sleep(delay)
906 return io.EOF
907 },
908 }, nil
909 },
910 }, nil
911 },
912 },
913 work: func(t *testing.T, c *Client) {
914 u := c.DB("foo").BulkGet(context.Background(), []BulkGetReference{})
915 for u.Next() {
916 }
917 if u.Err() != nil {
918 t.Fatal(u.Err())
919 }
920 },
921 })
922 tests.Add("Changes", tt{
923 client: &mock.Client{
924 DBFunc: func(string, driver.Options) (driver.DB, error) {
925 return &mock.DB{
926 ChangesFunc: func(context.Context, driver.Options) (driver.Changes, error) {
927 return &mock.Changes{
928 NextFunc: func(*driver.Change) error {
929 time.Sleep(delay)
930 return io.EOF
931 },
932 }, nil
933 },
934 }, nil
935 },
936 },
937 work: func(t *testing.T, c *Client) {
938 u := c.DB("foo").Changes(context.Background())
939 if err := u.Err(); err != nil {
940 t.Fatal(err)
941 }
942 for u.Next() {
943 }
944 if u.Err() != nil {
945 t.Fatal(u.Err())
946 }
947 },
948 })
949 tests.Add("DesignDocs", tt{
950 client: &mock.Client{
951 DBFunc: func(string, driver.Options) (driver.DB, error) {
952 return &mock.DesignDocer{
953 DesignDocsFunc: func(context.Context, driver.Options) (driver.Rows, error) {
954 return &mock.Rows{
955 NextFunc: func(*driver.Row) error {
956 time.Sleep(delay)
957 return io.EOF
958 },
959 }, nil
960 },
961 }, nil
962 },
963 },
964 work: func(t *testing.T, c *Client) {
965 u := c.DB("foo").DesignDocs(context.Background())
966 for u.Next() {
967 }
968 if u.Err() != nil {
969 t.Fatal(u.Err())
970 }
971 },
972 })
973 tests.Add("LocalDocs", tt{
974 client: &mock.Client{
975 DBFunc: func(string, driver.Options) (driver.DB, error) {
976 return &mock.LocalDocer{
977 LocalDocsFunc: func(context.Context, driver.Options) (driver.Rows, error) {
978 return &mock.Rows{
979 NextFunc: func(*driver.Row) error {
980 time.Sleep(delay)
981 return io.EOF
982 },
983 }, nil
984 },
985 }, nil
986 },
987 },
988 work: func(t *testing.T, c *Client) {
989 u := c.DB("foo").LocalDocs(context.Background())
990 for u.Next() {
991 }
992 if u.Err() != nil {
993 t.Fatal(u.Err())
994 }
995 },
996 })
997 tests.Add("Query", tt{
998 client: &mock.Client{
999 DBFunc: func(string, driver.Options) (driver.DB, error) {
1000 return &mock.DB{
1001 QueryFunc: func(context.Context, string, string, driver.Options) (driver.Rows, error) {
1002 return &mock.Rows{
1003 NextFunc: func(*driver.Row) error {
1004 time.Sleep(delay)
1005 return io.EOF
1006 },
1007 }, nil
1008 },
1009 }, nil
1010 },
1011 },
1012 work: func(t *testing.T, c *Client) {
1013 u := c.DB("foo").Query(context.Background(), "", "")
1014 for u.Next() {
1015 }
1016 if u.Err() != nil {
1017 t.Fatal(u.Err())
1018 }
1019 },
1020 })
1021 tests.Add("Find", tt{
1022 client: &mock.Client{
1023 DBFunc: func(string, driver.Options) (driver.DB, error) {
1024 return &mock.Finder{
1025 FindFunc: func(context.Context, interface{}, driver.Options) (driver.Rows, error) {
1026 return &mock.Rows{
1027 NextFunc: func(*driver.Row) error {
1028 time.Sleep(delay)
1029 return io.EOF
1030 },
1031 }, nil
1032 },
1033 }, nil
1034 },
1035 },
1036 work: func(t *testing.T, c *Client) {
1037 u := c.DB("foo").Find(context.Background(), nil)
1038 for u.Next() {
1039 }
1040 if u.Err() != nil {
1041 t.Fatal(u.Err())
1042 }
1043 },
1044 })
1045 tests.Add("Get", tt{
1046 client: &mock.Client{
1047 DBFunc: func(string, driver.Options) (driver.DB, error) {
1048 return &mock.DB{
1049 GetFunc: func(context.Context, string, driver.Options) (*driver.Document, error) {
1050 time.Sleep(delay)
1051 return &driver.Document{}, nil
1052 },
1053 }, nil
1054 },
1055 },
1056 work: func(t *testing.T, c *Client) {
1057 u := c.DB("foo").Get(context.Background(), "")
1058 if u.Err() != nil {
1059 t.Fatal(u.Err())
1060 }
1061 },
1062 })
1063 tests.Add("RevsDiff", tt{
1064 client: &mock.Client{
1065 DBFunc: func(string, driver.Options) (driver.DB, error) {
1066 return &mock.RevsDiffer{
1067 RevsDiffFunc: func(context.Context, interface{}) (driver.Rows, error) {
1068 return &mock.Rows{
1069 NextFunc: func(*driver.Row) error {
1070 time.Sleep(delay)
1071 return io.EOF
1072 },
1073 }, nil
1074 },
1075 }, nil
1076 },
1077 },
1078 work: func(t *testing.T, c *Client) {
1079 u := c.DB("foo").RevsDiff(context.Background(), "")
1080 for u.Next() {
1081 }
1082 if u.Err() != nil {
1083 t.Fatal(u.Err())
1084 }
1085 },
1086 })
1087
1088 tests.Run(t, func(t *testing.T, tt tt) {
1089 t.Parallel()
1090
1091 c := &Client{
1092 driverClient: tt.client,
1093 }
1094
1095 start := time.Now()
1096 tt.work(t, c)
1097 time.Sleep(delay / 10)
1098 _ = c.Close()
1099 if elapsed := time.Since(start); elapsed < delay {
1100 t.Errorf("client.Close() didn't block long enough (%v < %v)", elapsed, delay)
1101 }
1102 })
1103 })
1104 }
1105
View as plain text