...

Source file src/github.com/go-kivik/kivik/v4/x/server/db_test.go

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

     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  //go:build !js
    14  
    15  package server
    16  
    17  import (
    18  	"net/http"
    19  	"strings"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/go-kivik/kivik/v4"
    24  	"github.com/go-kivik/kivik/v4/driver"
    25  	"github.com/go-kivik/kivik/v4/mockdb"
    26  )
    27  
    28  func Test_dbUpdates(t *testing.T) {
    29  	tests := serverTests{
    30  		{
    31  			name:       "db updates, unauthorized",
    32  			method:     http.MethodGet,
    33  			path:       "/_db_updates",
    34  			wantStatus: http.StatusUnauthorized,
    35  			wantJSON: map[string]interface{}{
    36  				"error":  "unauthorized",
    37  				"reason": "User not authenticated",
    38  			},
    39  		},
    40  		{
    41  			name: "db updates, two updates",
    42  			client: func() *kivik.Client {
    43  				client, mock, err := mockdb.New()
    44  				if err != nil {
    45  					t.Fatal(err)
    46  				}
    47  				mock.ExpectDBUpdates().WillReturn(mockdb.NewDBUpdates().
    48  					AddUpdate(&driver.DBUpdate{
    49  						DBName: "foo",
    50  						Type:   "created",
    51  						Seq:    "1-aaa",
    52  					}).
    53  					AddUpdate(&driver.DBUpdate{
    54  						DBName: "foo",
    55  						Type:   "deleted",
    56  						Seq:    "2-aaa",
    57  					}).LastSeq("2-aaa"))
    58  				return client
    59  			}(),
    60  			authUser:   userAdmin,
    61  			method:     http.MethodGet,
    62  			path:       "/_db_updates",
    63  			wantStatus: http.StatusOK,
    64  			wantJSON: map[string]interface{}{
    65  				"results": []interface{}{
    66  					map[string]interface{}{
    67  						"db_name": "foo",
    68  						"type":    "created",
    69  						"seq":     "1-aaa",
    70  					},
    71  					map[string]interface{}{
    72  						"db_name": "foo",
    73  						"type":    "deleted",
    74  						"seq":     "2-aaa",
    75  					},
    76  				},
    77  				"last_seq": "2-aaa",
    78  			},
    79  		},
    80  		{
    81  			name:       "continuous, invalid heartbeat",
    82  			method:     http.MethodGet,
    83  			authUser:   userAdmin,
    84  			path:       "/_db_updates?feed=continuous&heartbeat=chicken",
    85  			wantStatus: http.StatusBadRequest,
    86  			wantJSON: map[string]interface{}{
    87  				"error":  "bad_request",
    88  				"reason": "strconv.Atoi: parsing \"chicken\": invalid syntax",
    89  			},
    90  		},
    91  		{
    92  			name: "continuous, with heartbeat",
    93  			client: func() *kivik.Client {
    94  				client, mock, err := mockdb.New()
    95  				if err != nil {
    96  					t.Fatal(err)
    97  				}
    98  				mock.ExpectDBUpdates().WillReturn(mockdb.NewDBUpdates().
    99  					AddUpdate(&driver.DBUpdate{
   100  						DBName: "foo",
   101  						Type:   "created",
   102  						Seq:    "1-aaa",
   103  					}).
   104  					AddDelay(500 * time.Millisecond).
   105  					AddUpdate(&driver.DBUpdate{
   106  						DBName: "foo",
   107  						Type:   "deleted",
   108  						Seq:    "2-aaa",
   109  					}))
   110  				return client
   111  			}(),
   112  			authUser:   userAdmin,
   113  			method:     http.MethodGet,
   114  			path:       "/_db_updates?feed=continuous&heartbeat=100",
   115  			wantStatus: http.StatusOK,
   116  			wantBodyRE: "}\n+\n{",
   117  		},
   118  	}
   119  
   120  	tests.Run(t)
   121  }
   122  
   123  func Test_allDocs(t *testing.T) {
   124  	tests := serverTests{
   125  		{
   126  			name:     "GET defaults",
   127  			authUser: userAdmin,
   128  			method:   http.MethodGet,
   129  			path:     "/db1/_all_docs",
   130  			client: func() *kivik.Client {
   131  				client, mock, err := mockdb.New()
   132  				if err != nil {
   133  					t.Fatal(err)
   134  				}
   135  				db := mock.NewDB()
   136  				mock.ExpectDB().WillReturn(db)
   137  				db.ExpectSecurity().WillReturn(&driver.Security{})
   138  				mock.ExpectDB().WillReturn(db)
   139  				db.ExpectAllDocs().WillReturn(mockdb.NewRows().
   140  					AddRow(&driver.Row{
   141  						ID:    "foo",
   142  						Key:   []byte(`"foo"`),
   143  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   144  					}).
   145  					TotalRows(99),
   146  				)
   147  				return client
   148  			}(),
   149  			wantStatus: http.StatusOK,
   150  			wantJSON: map[string]interface{}{
   151  				"offset": 0,
   152  				"rows": []interface{}{
   153  					map[string]interface{}{
   154  						"id":  "foo",
   155  						"key": "foo",
   156  						"value": map[string]interface{}{
   157  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   158  						},
   159  					},
   160  				},
   161  				"total_rows": 99,
   162  			},
   163  		},
   164  		{
   165  			name:     "multi queries",
   166  			authUser: userAdmin,
   167  			method:   http.MethodPost,
   168  			path:     "/db1/_all_docs/queries",
   169  			headers: map[string]string{
   170  				"Content-Type": "application/json",
   171  			},
   172  			body: strings.NewReader(`{"queries": [{"keys": ["foo", "bar"]}]}`),
   173  			client: func() *kivik.Client {
   174  				client, mock, err := mockdb.New()
   175  				if err != nil {
   176  					t.Fatal(err)
   177  				}
   178  				db := mock.NewDB()
   179  				mock.ExpectDB().WillReturn(db)
   180  				db.ExpectSecurity().WillReturn(&driver.Security{})
   181  				mock.ExpectDB().WillReturn(db)
   182  				db.ExpectAllDocs().WillReturn(mockdb.NewRows().
   183  					AddRow(&driver.Row{
   184  						ID:    "foo",
   185  						Key:   []byte(`"foo"`),
   186  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   187  					}).
   188  					TotalRows(99),
   189  				)
   190  				return client
   191  			}(),
   192  			wantStatus: http.StatusOK,
   193  			wantJSON: map[string]interface{}{
   194  				"offset": 0,
   195  				"rows": []interface{}{
   196  					map[string]interface{}{
   197  						"id":  "foo",
   198  						"key": "foo",
   199  						"value": map[string]interface{}{
   200  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   201  						},
   202  					},
   203  				},
   204  				"total_rows": 99,
   205  			},
   206  		},
   207  		{
   208  			name:     "POST _all_docs",
   209  			authUser: userAdmin,
   210  			method:   http.MethodPost,
   211  			path:     "/db1/_all_docs",
   212  			headers: map[string]string{
   213  				"Content-Type": "application/json",
   214  			},
   215  			body: strings.NewReader(`{"keys": ["foo", "bar"]}`),
   216  			client: func() *kivik.Client {
   217  				client, mock, err := mockdb.New()
   218  				if err != nil {
   219  					t.Fatal(err)
   220  				}
   221  				db := mock.NewDB()
   222  				mock.ExpectDB().WillReturn(db)
   223  				db.ExpectSecurity().WillReturn(&driver.Security{})
   224  				mock.ExpectDB().WillReturn(db)
   225  				db.ExpectAllDocs().WillReturn(mockdb.NewRows().
   226  					AddRow(&driver.Row{
   227  						ID:    "foo",
   228  						Key:   []byte(`"foo"`),
   229  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   230  					}).
   231  					TotalRows(99),
   232  				)
   233  				return client
   234  			}(),
   235  			wantStatus: http.StatusOK,
   236  			wantJSON: map[string]interface{}{
   237  				"offset": 0,
   238  				"rows": []interface{}{
   239  					map[string]interface{}{
   240  						"id":  "foo",
   241  						"key": "foo",
   242  						"value": map[string]interface{}{
   243  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   244  						},
   245  					},
   246  				},
   247  				"total_rows": 99,
   248  			},
   249  		},
   250  	}
   251  
   252  	tests.Run(t)
   253  }
   254  
   255  func Test_localDocs(t *testing.T) {
   256  	tests := serverTests{
   257  		{
   258  			name:     "GET defaults",
   259  			authUser: userAdmin,
   260  			method:   http.MethodGet,
   261  			path:     "/db1/_local_docs",
   262  			client: func() *kivik.Client {
   263  				client, mock, err := mockdb.New()
   264  				if err != nil {
   265  					t.Fatal(err)
   266  				}
   267  				db := mock.NewDB()
   268  				mock.ExpectDB().WillReturn(db)
   269  				db.ExpectSecurity().WillReturn(&driver.Security{})
   270  				mock.ExpectDB().WillReturn(db)
   271  				db.ExpectLocalDocs().WillReturn(mockdb.NewRows().
   272  					AddRow(&driver.Row{
   273  						ID:    "foo",
   274  						Key:   []byte(`"foo"`),
   275  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   276  					}).
   277  					TotalRows(99),
   278  				)
   279  				return client
   280  			}(),
   281  			wantStatus: http.StatusOK,
   282  			wantJSON: map[string]interface{}{
   283  				"offset": 0,
   284  				"rows": []interface{}{
   285  					map[string]interface{}{
   286  						"id":  "foo",
   287  						"key": "foo",
   288  						"value": map[string]interface{}{
   289  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   290  						},
   291  					},
   292  				},
   293  				"total_rows": 99,
   294  			},
   295  		},
   296  		{
   297  			name:     "multi queries",
   298  			authUser: userAdmin,
   299  			method:   http.MethodPost,
   300  			path:     "/db1/_local_docs/queries",
   301  			headers: map[string]string{
   302  				"Content-Type": "application/json",
   303  			},
   304  			body: strings.NewReader(`{"queries": [{"keys": ["foo", "bar"]}]}`),
   305  			client: func() *kivik.Client {
   306  				client, mock, err := mockdb.New()
   307  				if err != nil {
   308  					t.Fatal(err)
   309  				}
   310  				db := mock.NewDB()
   311  				mock.ExpectDB().WillReturn(db)
   312  				db.ExpectSecurity().WillReturn(&driver.Security{})
   313  				mock.ExpectDB().WillReturn(db)
   314  				db.ExpectLocalDocs().WillReturn(mockdb.NewRows().
   315  					AddRow(&driver.Row{
   316  						ID:    "foo",
   317  						Key:   []byte(`"foo"`),
   318  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   319  					}).
   320  					TotalRows(99),
   321  				)
   322  				return client
   323  			}(),
   324  			wantStatus: http.StatusOK,
   325  			wantJSON: map[string]interface{}{
   326  				"offset": 0,
   327  				"rows": []interface{}{
   328  					map[string]interface{}{
   329  						"id":  "foo",
   330  						"key": "foo",
   331  						"value": map[string]interface{}{
   332  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   333  						},
   334  					},
   335  				},
   336  				"total_rows": 99,
   337  			},
   338  		},
   339  		{
   340  			name:     "POST _local_docs",
   341  			authUser: userAdmin,
   342  			method:   http.MethodPost,
   343  			path:     "/db1/_local_docs",
   344  			headers: map[string]string{
   345  				"Content-Type": "application/json",
   346  			},
   347  			body: strings.NewReader(`{"keys": ["foo", "bar"]}`),
   348  			client: func() *kivik.Client {
   349  				client, mock, err := mockdb.New()
   350  				if err != nil {
   351  					t.Fatal(err)
   352  				}
   353  				db := mock.NewDB()
   354  				mock.ExpectDB().WillReturn(db)
   355  				db.ExpectSecurity().WillReturn(&driver.Security{})
   356  				mock.ExpectDB().WillReturn(db)
   357  				db.ExpectLocalDocs().WillReturn(mockdb.NewRows().
   358  					AddRow(&driver.Row{
   359  						ID:    "foo",
   360  						Key:   []byte(`"foo"`),
   361  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   362  					}).
   363  					TotalRows(99),
   364  				)
   365  				return client
   366  			}(),
   367  			wantStatus: http.StatusOK,
   368  			wantJSON: map[string]interface{}{
   369  				"offset": 0,
   370  				"rows": []interface{}{
   371  					map[string]interface{}{
   372  						"id":  "foo",
   373  						"key": "foo",
   374  						"value": map[string]interface{}{
   375  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   376  						},
   377  					},
   378  				},
   379  				"total_rows": 99,
   380  			},
   381  		},
   382  	}
   383  
   384  	tests.Run(t)
   385  }
   386  
   387  func Test_designDocs(t *testing.T) {
   388  	tests := serverTests{
   389  		{
   390  			name:     "GET defaults",
   391  			authUser: userAdmin,
   392  			method:   http.MethodGet,
   393  			path:     "/db1/_design_docs",
   394  			client: func() *kivik.Client {
   395  				client, mock, err := mockdb.New()
   396  				if err != nil {
   397  					t.Fatal(err)
   398  				}
   399  				db := mock.NewDB()
   400  				mock.ExpectDB().WillReturn(db)
   401  				db.ExpectSecurity().WillReturn(&driver.Security{})
   402  				mock.ExpectDB().WillReturn(db)
   403  				db.ExpectDesignDocs().WillReturn(mockdb.NewRows().
   404  					AddRow(&driver.Row{
   405  						ID:    "foo",
   406  						Key:   []byte(`"foo"`),
   407  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   408  					}).
   409  					TotalRows(99),
   410  				)
   411  				return client
   412  			}(),
   413  			wantStatus: http.StatusOK,
   414  			wantJSON: map[string]interface{}{
   415  				"offset": 0,
   416  				"rows": []interface{}{
   417  					map[string]interface{}{
   418  						"id":  "foo",
   419  						"key": "foo",
   420  						"value": map[string]interface{}{
   421  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   422  						},
   423  					},
   424  				},
   425  				"total_rows": 99,
   426  			},
   427  		},
   428  		{
   429  			name:     "multi queries",
   430  			authUser: userAdmin,
   431  			method:   http.MethodPost,
   432  			path:     "/db1/_design_docs/queries",
   433  			headers: map[string]string{
   434  				"Content-Type": "application/json",
   435  			},
   436  			body: strings.NewReader(`{"queries": [{"keys": ["foo", "bar"]}]}`),
   437  			client: func() *kivik.Client {
   438  				client, mock, err := mockdb.New()
   439  				if err != nil {
   440  					t.Fatal(err)
   441  				}
   442  				db := mock.NewDB()
   443  				mock.ExpectDB().WillReturn(db)
   444  				db.ExpectSecurity().WillReturn(&driver.Security{})
   445  				mock.ExpectDB().WillReturn(db)
   446  				db.ExpectDesignDocs().WillReturn(mockdb.NewRows().
   447  					AddRow(&driver.Row{
   448  						ID:    "foo",
   449  						Key:   []byte(`"foo"`),
   450  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   451  					}).
   452  					TotalRows(99),
   453  				)
   454  				return client
   455  			}(),
   456  			wantStatus: http.StatusOK,
   457  			wantJSON: map[string]interface{}{
   458  				"offset": 0,
   459  				"rows": []interface{}{
   460  					map[string]interface{}{
   461  						"id":  "foo",
   462  						"key": "foo",
   463  						"value": map[string]interface{}{
   464  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   465  						},
   466  					},
   467  				},
   468  				"total_rows": 99,
   469  			},
   470  		},
   471  		{
   472  			name:     "POST _design_docs",
   473  			authUser: userAdmin,
   474  			method:   http.MethodPost,
   475  			path:     "/db1/_design_docs",
   476  			headers: map[string]string{
   477  				"Content-Type": "application/json",
   478  			},
   479  			body: strings.NewReader(`{"keys": ["foo", "bar"]}`),
   480  			client: func() *kivik.Client {
   481  				client, mock, err := mockdb.New()
   482  				if err != nil {
   483  					t.Fatal(err)
   484  				}
   485  				db := mock.NewDB()
   486  				mock.ExpectDB().WillReturn(db)
   487  				db.ExpectSecurity().WillReturn(&driver.Security{})
   488  				mock.ExpectDB().WillReturn(db)
   489  				db.ExpectDesignDocs().WillReturn(mockdb.NewRows().
   490  					AddRow(&driver.Row{
   491  						ID:    "foo",
   492  						Key:   []byte(`"foo"`),
   493  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   494  					}).
   495  					TotalRows(99),
   496  				)
   497  				return client
   498  			}(),
   499  			wantStatus: http.StatusOK,
   500  			wantJSON: map[string]interface{}{
   501  				"offset": 0,
   502  				"rows": []interface{}{
   503  					map[string]interface{}{
   504  						"id":  "foo",
   505  						"key": "foo",
   506  						"value": map[string]interface{}{
   507  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   508  						},
   509  					},
   510  				},
   511  				"total_rows": 99,
   512  			},
   513  		},
   514  	}
   515  
   516  	tests.Run(t)
   517  }
   518  
   519  func Test_queryView(t *testing.T) {
   520  	tests := serverTests{
   521  		{
   522  			name:     "GET defaults",
   523  			authUser: userAdmin,
   524  			method:   http.MethodGet,
   525  			path:     "/db1/_design/foo/_view/bar",
   526  			client: func() *kivik.Client {
   527  				client, mock, err := mockdb.New()
   528  				if err != nil {
   529  					t.Fatal(err)
   530  				}
   531  				db := mock.NewDB()
   532  				mock.ExpectDB().WillReturn(db)
   533  				db.ExpectSecurity().WillReturn(&driver.Security{})
   534  				mock.ExpectDB().WillReturn(db)
   535  				db.ExpectQuery().WillReturn(mockdb.NewRows().
   536  					AddRow(&driver.Row{
   537  						ID:    "foo",
   538  						Key:   []byte(`"foo"`),
   539  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   540  					}).
   541  					TotalRows(99),
   542  				)
   543  				return client
   544  			}(),
   545  			wantStatus: http.StatusOK,
   546  			wantJSON: map[string]interface{}{
   547  				"offset": 0,
   548  				"rows": []interface{}{
   549  					map[string]interface{}{
   550  						"id":  "foo",
   551  						"key": "foo",
   552  						"value": map[string]interface{}{
   553  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   554  						},
   555  					},
   556  				},
   557  				"total_rows": 99,
   558  			},
   559  		},
   560  		{
   561  			name:     "multi queries",
   562  			authUser: userAdmin,
   563  			method:   http.MethodPost,
   564  			path:     "/db1/_design/foo/_view/bar/queries",
   565  			headers: map[string]string{
   566  				"Content-Type": "application/json",
   567  			},
   568  			body: strings.NewReader(`{"queries": [{"keys": ["foo", "bar"]}]}`),
   569  			client: func() *kivik.Client {
   570  				client, mock, err := mockdb.New()
   571  				if err != nil {
   572  					t.Fatal(err)
   573  				}
   574  				db := mock.NewDB()
   575  				mock.ExpectDB().WillReturn(db)
   576  				db.ExpectSecurity().WillReturn(&driver.Security{})
   577  				mock.ExpectDB().WillReturn(db)
   578  				db.ExpectQuery().WillReturn(mockdb.NewRows().
   579  					AddRow(&driver.Row{
   580  						ID:    "foo",
   581  						Key:   []byte(`"foo"`),
   582  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   583  					}).
   584  					TotalRows(99),
   585  				)
   586  				return client
   587  			}(),
   588  			wantStatus: http.StatusOK,
   589  			wantJSON: map[string]interface{}{
   590  				"offset": 0,
   591  				"rows": []interface{}{
   592  					map[string]interface{}{
   593  						"id":  "foo",
   594  						"key": "foo",
   595  						"value": map[string]interface{}{
   596  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   597  						},
   598  					},
   599  				},
   600  				"total_rows": 99,
   601  			},
   602  		},
   603  		{
   604  			name:     "POST _design/foo/_view/bar",
   605  			authUser: userAdmin,
   606  			method:   http.MethodPost,
   607  			path:     "/db1/_design/foo/_view/bar",
   608  			headers: map[string]string{
   609  				"Content-Type": "application/json",
   610  			},
   611  			body: strings.NewReader(`{"keys": ["foo", "bar"]}`),
   612  			client: func() *kivik.Client {
   613  				client, mock, err := mockdb.New()
   614  				if err != nil {
   615  					t.Fatal(err)
   616  				}
   617  				db := mock.NewDB()
   618  				mock.ExpectDB().WillReturn(db)
   619  				db.ExpectSecurity().WillReturn(&driver.Security{})
   620  				mock.ExpectDB().WillReturn(db)
   621  				db.ExpectQuery().WillReturn(mockdb.NewRows().
   622  					AddRow(&driver.Row{
   623  						ID:    "foo",
   624  						Key:   []byte(`"foo"`),
   625  						Value: strings.NewReader(`{"rev": "1-beea34a62a215ab051862d1e5d93162e"}`),
   626  					}).
   627  					TotalRows(99),
   628  				)
   629  				return client
   630  			}(),
   631  			wantStatus: http.StatusOK,
   632  			wantJSON: map[string]interface{}{
   633  				"offset": 0,
   634  				"rows": []interface{}{
   635  					map[string]interface{}{
   636  						"id":  "foo",
   637  						"key": "foo",
   638  						"value": map[string]interface{}{
   639  							"rev": "1-beea34a62a215ab051862d1e5d93162e",
   640  						},
   641  					},
   642  				},
   643  				"total_rows": 99,
   644  			},
   645  		},
   646  	}
   647  
   648  	tests.Run(t)
   649  }
   650  

View as plain text