github.com/go-kivik/kivik/v4@v4.3.2/kivik_test.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 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) { //nolint:thelper // Not a helper 843 u := c.DBUpdates(context.Background()) 844 if err := u.Err(); err != nil { 845 t.Fatal(err) 846 } 847 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 870 u := c.DB("foo").AllDocs(context.Background()) 871 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 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) { //nolint:thelper // Not a helper 914 u := c.DB("foo").BulkGet(context.Background(), []BulkGetReference{}) 915 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 938 u := c.DB("foo").Changes(context.Background()) 939 if err := u.Err(); err != nil { 940 t.Fatal(err) 941 } 942 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 965 u := c.DB("foo").DesignDocs(context.Background()) 966 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 989 u := c.DB("foo").LocalDocs(context.Background()) 990 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 1013 u := c.DB("foo").Query(context.Background(), "", "") 1014 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 1037 u := c.DB("foo").Find(context.Background(), nil) 1038 for u.Next() { //nolint:revive // intentional empty block 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) { //nolint:thelper // Not a helper 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) { //nolint:thelper // Not a helper 1079 u := c.DB("foo").RevsDiff(context.Background(), "") 1080 for u.Next() { //nolint:revive // intentional empty block 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 }