github.com/go-kivik/kivik/v4@v4.3.2/x/server/db_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 //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 }