...

Source file src/github.com/go-kivik/kivik/v4/kivik_test.go

Documentation: github.com/go-kivik/kivik/v4

     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  }
  1105  

View as plain text