couchbase 3.2.0 → 3.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. package/README.md +24 -18
  2. package/binding.gyp +88 -85
  3. package/deps/lcb/CMakeLists.txt +1 -1
  4. package/deps/lcb/CONTRIBUTING.md +1 -1
  5. package/deps/lcb/README.markdown +2 -2
  6. package/deps/lcb/RELEASE_NOTES.markdown +99 -14
  7. package/deps/lcb/cmake/Modules/GetVersionInfo.cmake +1 -1
  8. package/deps/lcb/contrib/cbsasl/src/scram-sha/scram_utils.cc +22 -26
  9. package/deps/lcb/contrib/lcb-jsoncpp/lcb-jsoncpp.cpp +20 -7
  10. package/deps/lcb/doc/Doxyfile +1 -1
  11. package/deps/lcb/example/CMakeLists.txt +4 -4
  12. package/deps/lcb/example/libuvdirect/main.c +39 -12
  13. package/deps/lcb/example/minimal/durability.cc +149 -0
  14. package/deps/lcb/example/minimal/query.c +11 -9
  15. package/deps/lcb/gyp_config/common/libcouchbase/configuration.h +3 -3
  16. package/deps/lcb/gyp_config/linux/arm64/config.h +243 -0
  17. package/deps/lcb/include/libcouchbase/couchbase.h +80 -5
  18. package/deps/lcb/include/libcouchbase/error.h +2 -0
  19. package/deps/lcb/include/libcouchbase/ixmgmt.h +15 -10
  20. package/deps/lcb/include/libcouchbase/tracing.h +2 -2
  21. package/deps/lcb/include/memcached/protocol_binary.h +21 -0
  22. package/deps/lcb/libcouchbase.gyp +347 -349
  23. package/deps/lcb/packaging/deb/control +1 -1
  24. package/deps/lcb/src/analytics/analytics_handle.cc +13 -5
  25. package/deps/lcb/src/analytics/analytics_handle.hh +29 -0
  26. package/deps/lcb/src/bootstrap.cc +6 -3
  27. package/deps/lcb/src/capi/cmd_analytics.cc +12 -1
  28. package/deps/lcb/src/capi/cmd_analytics.hh +30 -0
  29. package/deps/lcb/src/capi/cmd_counter.hh +23 -0
  30. package/deps/lcb/src/capi/cmd_exists.hh +24 -1
  31. package/deps/lcb/src/capi/cmd_get.hh +22 -0
  32. package/deps/lcb/src/capi/cmd_get_replica.hh +23 -0
  33. package/deps/lcb/src/capi/cmd_http.hh +7 -0
  34. package/deps/lcb/src/capi/cmd_query.cc +11 -1
  35. package/deps/lcb/src/capi/cmd_query.hh +31 -0
  36. package/deps/lcb/src/capi/cmd_remove.hh +23 -0
  37. package/deps/lcb/src/capi/cmd_search.cc +6 -0
  38. package/deps/lcb/src/capi/cmd_search.hh +23 -0
  39. package/deps/lcb/src/capi/cmd_store.hh +33 -21
  40. package/deps/lcb/src/capi/cmd_subdoc.hh +35 -0
  41. package/deps/lcb/src/capi/cmd_touch.hh +23 -0
  42. package/deps/lcb/src/capi/cmd_unlock.hh +23 -0
  43. package/deps/lcb/src/capi/cmd_view.hh +6 -0
  44. package/deps/lcb/src/capi/collection_qualifier.hh +2 -2
  45. package/deps/lcb/src/cntl.cc +45 -11
  46. package/deps/lcb/src/crypto.cc +2 -2
  47. package/deps/lcb/src/dns-srv.cc +5 -3
  48. package/deps/lcb/src/errmap.cc +5 -9
  49. package/deps/lcb/src/errmap.h +7 -3
  50. package/deps/lcb/src/handler.cc +24 -18
  51. package/deps/lcb/src/hostlist.h +2 -2
  52. package/deps/lcb/src/http/http-priv.h +2 -2
  53. package/deps/lcb/src/http/http.cc +5 -2
  54. package/deps/lcb/src/instance.cc +20 -11
  55. package/deps/lcb/src/internal.h +9 -0
  56. package/deps/lcb/src/lcbio/connect.cc +14 -2
  57. package/deps/lcb/src/lcbio/connect.h +2 -2
  58. package/deps/lcb/src/lcbio/ctx.cc +4 -2
  59. package/deps/lcb/src/lcbio/ioutils.cc +9 -10
  60. package/deps/lcb/src/lcbio/manager.cc +1 -1
  61. package/deps/lcb/src/mcserver/mcserver.cc +9 -6
  62. package/deps/lcb/src/mcserver/negotiate.cc +39 -17
  63. package/deps/lcb/src/n1ql/ixmgmt.cc +1 -2
  64. package/deps/lcb/src/n1ql/query_handle.cc +41 -19
  65. package/deps/lcb/src/n1ql/query_handle.hh +28 -1
  66. package/deps/lcb/src/operations/counter.cc +18 -5
  67. package/deps/lcb/src/operations/exists.cc +25 -4
  68. package/deps/lcb/src/operations/get.cc +39 -19
  69. package/deps/lcb/src/operations/get_replica.cc +28 -8
  70. package/deps/lcb/src/operations/observe.cc +1 -1
  71. package/deps/lcb/src/operations/ping.cc +8 -8
  72. package/deps/lcb/src/operations/pktfwd.cc +2 -1
  73. package/deps/lcb/src/operations/remove.cc +39 -22
  74. package/deps/lcb/src/operations/store.cc +18 -5
  75. package/deps/lcb/src/operations/subdoc.cc +18 -6
  76. package/deps/lcb/src/operations/touch.cc +34 -16
  77. package/deps/lcb/src/operations/unlock.cc +24 -5
  78. package/deps/lcb/src/packetutils.h +3 -2
  79. package/deps/lcb/src/retryq.cc +24 -5
  80. package/deps/lcb/src/search/search.cc +1 -0
  81. package/deps/lcb/src/search/search_handle.cc +30 -8
  82. package/deps/lcb/src/search/search_handle.hh +29 -0
  83. package/deps/lcb/src/settings.cc +1 -1
  84. package/deps/lcb/src/ssl/ssl_common.c +6 -7
  85. package/deps/lcb/src/tracing/span.cc +47 -14
  86. package/deps/lcb/src/tracing/tracer.cc +11 -2
  87. package/deps/lcb/src/tracing/tracing-internal.h +105 -93
  88. package/deps/lcb/src/utilities.cc +43 -0
  89. package/deps/lcb/src/utilities.h +53 -0
  90. package/deps/lcb/src/vbucket/vbucket.c +34 -33
  91. package/deps/lcb/src/views/view_handle.cc +13 -5
  92. package/deps/lcb/src/views/view_handle.hh +29 -0
  93. package/deps/lcb/tests/CMakeLists.txt +21 -0
  94. package/deps/lcb/tests/basic/t_ctlcodes.cc +24 -3
  95. package/deps/lcb/tests/basic/t_jsparse.cc +8 -0
  96. package/deps/lcb/tests/basic/t_n1qlstrings.cc +73 -0
  97. package/deps/lcb/tests/iotests/mock-environment.cc +30 -1
  98. package/deps/lcb/tests/iotests/mock-environment.h +49 -0
  99. package/deps/lcb/tests/iotests/mock-unit-test.cc +104 -6
  100. package/deps/lcb/tests/iotests/mock-unit-test.h +34 -0
  101. package/deps/lcb/tests/iotests/t_collections.cc +1 -1
  102. package/deps/lcb/tests/iotests/t_confmon.cc +4 -2
  103. package/deps/lcb/tests/iotests/t_get.cc +109 -7
  104. package/deps/lcb/tests/iotests/t_http.cc +9 -4
  105. package/deps/lcb/tests/iotests/t_lock.cc +18 -0
  106. package/deps/lcb/tests/iotests/t_mutate.cc +157 -63
  107. package/deps/lcb/tests/iotests/t_n1ql.cc +330 -33
  108. package/deps/lcb/tests/iotests/t_views.cc +1 -0
  109. package/deps/lcb/tests/iotests/testutil.cc +168 -0
  110. package/deps/lcb/tests/iotests/testutil.h +116 -0
  111. package/deps/lcb/tests/mocksupport/procutil.c +32 -28
  112. package/deps/lcb/tests/mocksupport/server.c +0 -1
  113. package/deps/lcb/tests/mocksupport/timeout.c +2 -2
  114. package/deps/lcb/tools/cbc.cc +7 -0
  115. package/dist/analyticsindexmanager.js +512 -524
  116. package/dist/binding.d.ts +3 -0
  117. package/dist/bindingutilities.js +4 -0
  118. package/dist/bucket.js +1 -1
  119. package/dist/bucketmanager.d.ts +31 -1
  120. package/dist/bucketmanager.js +194 -186
  121. package/dist/cluster.d.ts +7 -0
  122. package/dist/cluster.js +48 -38
  123. package/dist/collection.js +11 -17
  124. package/dist/collectionmanager.js +181 -197
  125. package/dist/connection.d.ts +3 -1
  126. package/dist/connection.js +27 -16
  127. package/dist/couchbase.d.ts +1 -0
  128. package/dist/couchbase.js +3 -13
  129. package/dist/datastructures.js +239 -310
  130. package/dist/diagnosticsexecutor.js +70 -85
  131. package/dist/errors.d.ts +70 -0
  132. package/dist/errors.js +96 -2
  133. package/dist/eventingfunctionmanager.d.ts +804 -0
  134. package/dist/eventingfunctionmanager.js +993 -0
  135. package/dist/httpexecutor.d.ts +2 -1
  136. package/dist/httpexecutor.js +30 -37
  137. package/dist/queryindexmanager.js +240 -266
  138. package/dist/scope.js +10 -4
  139. package/dist/sdspecs.d.ts +1 -1
  140. package/dist/searchexecutor.js +3 -0
  141. package/dist/searchindexmanager.js +240 -271
  142. package/dist/searchquery.d.ts +17 -0
  143. package/dist/searchquery.js +22 -1
  144. package/dist/searchtypes.d.ts +7 -2
  145. package/dist/searchtypes.js +2 -2
  146. package/dist/usermanager.js +251 -264
  147. package/dist/utilities.d.ts +2 -0
  148. package/dist/utilities.js +7 -2
  149. package/dist/viewexecutor.js +1 -1
  150. package/dist/viewindexmanager.js +131 -150
  151. package/package.json +1 -1
  152. package/src/addondata.cpp +58 -0
  153. package/src/addondata.h +40 -0
  154. package/src/binding.cpp +3 -1
  155. package/src/cas.h +2 -2
  156. package/src/connection.cpp +25 -178
  157. package/src/connection.h +8 -65
  158. package/src/connection_ops.cpp +57 -34
  159. package/src/constants.cpp +3 -0
  160. package/src/instance.cpp +235 -0
  161. package/src/instance.h +102 -0
  162. package/src/{connection_callbacks.cpp → instance_callbacks.cpp} +34 -34
  163. package/src/logger.cpp +11 -1
  164. package/src/logger.h +3 -0
  165. package/src/metrics.cpp +10 -0
  166. package/src/metrics.h +3 -0
  167. package/src/mutationtoken.h +2 -2
  168. package/src/opbuilder.h +13 -15
  169. package/src/respreader.cpp +1 -0
  170. package/src/respreader.h +6 -4
  171. package/src/tracespan.h +11 -11
  172. package/src/tracing.cpp +11 -0
  173. package/src/tracing.h +3 -0
  174. package/src/valueparser.h +5 -0
  175. package/deps/lcb/example/observe/durability.c +0 -110
@@ -165,6 +165,8 @@ class QueryUnitTest : public MockUnitTest
165
165
 
166
166
  TEST_F(QueryUnitTest, testSimple)
167
167
  {
168
+ MockEnvironment *mock = MockEnvironment::getInstance();
169
+ tracing_guard use_tracing;
168
170
  lcb_INSTANCE *instance;
169
171
  HandleWrap hw;
170
172
  if (!createQueryConnection(hw, &instance)) {
@@ -172,12 +174,26 @@ TEST_F(QueryUnitTest, testSimple)
172
174
  }
173
175
 
174
176
  N1QLResult res;
175
- makeCommand("SELECT mockrow");
177
+ const char *query = "SELECT mockrow";
178
+ makeCommand(query);
179
+
180
+ const char *context_id = "context_id";
181
+ lcb_cmdquery_client_context_id(cmd, context_id, strlen(context_id));
182
+
176
183
  lcb_STATUS rc = lcb_query(instance, &res, cmd);
177
184
  ASSERT_STATUS_EQ(LCB_SUCCESS, rc);
178
185
  lcb_wait(instance, LCB_WAIT_DEFAULT);
179
186
  ASSERT_STATUS_EQ(LCB_SUCCESS, res.rc);
180
187
  ASSERT_EQ(1, res.rows.size());
188
+
189
+ auto spans = mock->getTracer().spans;
190
+ ASSERT_EQ(1, spans.size());
191
+ auto span = spans[0];
192
+ HTTPSpanAssertions assertions;
193
+ assertions.statement = query;
194
+ assertions.operation_id = context_id;
195
+ assertions.service = "query";
196
+ assert_http_span(span, "query", assertions);
181
197
  }
182
198
 
183
199
  TEST_F(QueryUnitTest, testQueryError)
@@ -365,39 +381,286 @@ TEST_F(QueryUnitTest, testClusterwide)
365
381
  ASSERT_FALSE(res.called);
366
382
  }
367
383
 
384
+ struct upsert_result {
385
+ bool invoked{false};
386
+ lcb_STATUS rc{LCB_ERR_GENERIC};
387
+ std::string id{};
388
+ std::uint64_t cas{0};
389
+ };
390
+
368
391
  extern "C" {
369
392
  static void setCallback(lcb_INSTANCE *, lcb_CALLBACK_TYPE, const lcb_RESPSTORE *resp)
370
393
  {
371
- int *counter;
372
- lcb_respstore_cookie(resp, (void **)&counter);
394
+ upsert_result *res = nullptr;
395
+ lcb_respstore_cookie(resp, (void **)&res);
396
+ res->invoked = true;
373
397
  lcb_STORE_OPERATION op;
374
398
  lcb_respstore_operation(resp, &op);
375
399
  ASSERT_EQ(LCB_STORE_UPSERT, op);
376
- lcb_STATUS rc = lcb_respstore_status(resp);
377
- ASSERT_STATUS_EQ(LCB_SUCCESS, rc) << lcb_strerror_short(rc);
400
+ res->rc = lcb_respstore_status(resp);
401
+ lcb_respstore_cas(resp, &res->cas);
402
+ const char *ptr = nullptr;
403
+ std::size_t len = 0;
404
+ lcb_respstore_key(resp, &ptr, &len);
405
+ res->id.assign(ptr, len);
378
406
  }
379
407
  }
380
408
 
381
- string insert_doc(lcb_INSTANCE *instance, const string &scope, const string &collection)
409
+ upsert_result upsert_doc(lcb_INSTANCE *instance, const string &scope, const string &collection)
382
410
  {
383
411
  (void)lcb_install_callback(instance, LCB_CALLBACK_STORE, (lcb_RESPCALLBACK)setCallback);
384
412
 
385
413
  string key = unique_name("id");
386
- string val = unique_name("foo");
414
+ string val = R"({"key":")" + key + "\"}";
387
415
 
388
- int numcallbacks = 0;
389
416
  lcb_CMDSTORE *cmd;
390
417
  lcb_cmdstore_create(&cmd, LCB_STORE_UPSERT);
391
418
  lcb_cmdstore_collection(cmd, scope.c_str(), scope.size(), collection.c_str(), collection.size());
392
419
  lcb_cmdstore_key(cmd, key.c_str(), key.size());
393
420
  lcb_cmdstore_value(cmd, val.c_str(), val.size());
394
- EXPECT_EQ(LCB_SUCCESS, lcb_store(instance, &numcallbacks, cmd));
395
- lcb_wait(instance, LCB_WAIT_DEFAULT);
421
+ upsert_result res{};
422
+ EXPECT_EQ(LCB_SUCCESS, lcb_store(instance, &res, cmd));
396
423
  lcb_cmdstore_destroy(cmd);
397
- return key;
424
+ lcb_wait(instance, LCB_WAIT_DEFAULT);
425
+ EXPECT_TRUE(res.invoked);
426
+ EXPECT_STATUS_EQ(LCB_SUCCESS, res.rc);
427
+ return res;
428
+ }
429
+
430
+ struct query_index {
431
+ std::string id{};
432
+ std::string name{};
433
+ bool is_primary{false};
434
+ std::string keyspace_id{};
435
+ std::string namespace_id{};
436
+ std::string bucket_id{};
437
+ std::string state{};
438
+ };
439
+
440
+ struct query_index_list {
441
+ bool invoked{false};
442
+ lcb_STATUS rc{LCB_ERR_GENERIC};
443
+ std::uint16_t http_code{0};
444
+ std::string meta{};
445
+ std::string status{};
446
+ vector<std::pair<unsigned int, string>> errors{};
447
+ std::vector<query_index> indexes{};
448
+ };
449
+
450
+ extern "C" {
451
+ static void list_indexes_callback(lcb_INSTANCE *, int, const lcb_RESPQUERY *resp)
452
+ {
453
+ query_index_list *res;
454
+ lcb_respquery_cookie(resp, (void **)&res);
455
+
456
+ const char *row;
457
+ size_t nrow;
458
+ lcb_respquery_row(resp, &row, &nrow);
459
+
460
+ if (lcb_respquery_is_final(resp)) {
461
+ res->rc = lcb_respquery_status(resp);
462
+ if (row) {
463
+ res->meta.assign(row, nrow);
464
+ Json::Value meta;
465
+ if (Json::Reader().parse(res->meta, meta)) {
466
+ if (meta.isMember("status") && meta["status"].isString()) {
467
+ res->status = meta["status"].asString();
468
+ }
469
+
470
+ if (meta.isMember("errors") && meta["errors"].isArray()) {
471
+ for (auto &err : meta["errors"]) {
472
+ if (err.isObject()) {
473
+ res->errors.emplace_back(err["code"].asUInt(), err["msg"].asString());
474
+ }
475
+ }
476
+ }
477
+ }
478
+ }
479
+ const lcb_RESPHTTP *http = nullptr;
480
+ lcb_respquery_http_response(resp, &http);
481
+ if (http) {
482
+ lcb_resphttp_http_status(http, &res->http_code);
483
+ }
484
+ } else {
485
+ Json::Value index_json;
486
+ if (Json::Reader().parse(row, row + nrow, index_json)) {
487
+ query_index index{};
488
+ if (index_json.isMember("is_primary") && index_json["is_primary"].isBool()) {
489
+ index.is_primary = index_json["is_primary"].asBool();
490
+ }
491
+ if (index_json.isMember("id") && index_json["id"].isString()) {
492
+ index.id = index_json["id"].asString();
493
+ }
494
+ if (index_json.isMember("state") && index_json["state"].isString()) {
495
+ index.state = index_json["state"].asString();
496
+ }
497
+ if (index_json.isMember("name") && index_json["name"].isString()) {
498
+ index.name = index_json["name"].asString();
499
+ }
500
+ if (index_json.isMember("bucket_id") && index_json["bucket_id"].isString()) {
501
+ index.bucket_id = index_json["bucket_id"].asString();
502
+ }
503
+ if (index_json.isMember("keyspace_id") && index_json["keyspace_id"].isString()) {
504
+ index.keyspace_id = index_json["keyspace_id"].asString();
505
+ }
506
+ if (index_json.isMember("namespace_id") && index_json["namespace_id"].isString()) {
507
+ index.namespace_id = index_json["namespace_id"].asString();
508
+ }
509
+ res->indexes.emplace_back(index);
510
+ }
511
+ }
512
+ res->invoked = true;
513
+ }
514
+ }
515
+
516
+ query_index_list list_indexes(lcb_INSTANCE *instance, const std::string &bucket_name = "default")
517
+ {
518
+ const std::string param = "bucket_name";
519
+ const std::string encoded_bucket_name = Json::FastWriter().write(Json::Value(bucket_name));
520
+ std::string statement = R"(
521
+ SELECT idx.* FROM system:indexes AS idx
522
+ WHERE
523
+ (
524
+ (keyspace_id = $bucket_name AND bucket_id IS MISSING)
525
+ OR
526
+ (bucket_id = $bucket_name)
527
+ )
528
+ AND `using`="gsi"
529
+ ORDER BY is_primary DESC, name ASC)";
530
+ lcb_CMDQUERY *cmd;
531
+ lcb_cmdquery_create(&cmd);
532
+ lcb_cmdquery_statement(cmd, statement.c_str(), statement.size());
533
+ lcb_cmdquery_callback(cmd, list_indexes_callback);
534
+ EXPECT_STATUS_EQ(LCB_SUCCESS, lcb_cmdquery_named_param(cmd, param.data(), param.size(), encoded_bucket_name.data(),
535
+ encoded_bucket_name.size()));
536
+ query_index_list indexes{};
537
+ lcb_STATUS rc = lcb_query(instance, &indexes, cmd);
538
+ lcb_cmdquery_destroy(cmd);
539
+ EXPECT_STATUS_EQ(LCB_SUCCESS, rc);
540
+ lcb_wait(instance, LCB_WAIT_DEFAULT);
541
+ return indexes;
398
542
  }
399
543
 
400
- void create_index(lcb_INSTANCE *instance, const string &index, const string &scope, const string &collection)
544
+ struct index_status_result {
545
+ bool invoked{false};
546
+ lcb_STATUS rc{LCB_ERR_GENERIC};
547
+ std::uint16_t status{};
548
+ std::string body{};
549
+ };
550
+
551
+ extern "C" {
552
+ static void index_status_callback(lcb_INSTANCE *, lcb_CALLBACK_TYPE, const lcb_RESPHTTP *resp)
553
+ {
554
+ index_status_result *res = nullptr;
555
+ lcb_resphttp_cookie(resp, (void **)&res);
556
+ res->invoked = true;
557
+ res->rc = lcb_resphttp_status(resp);
558
+ const char *ptr = nullptr;
559
+ std::size_t len = 0;
560
+ lcb_resphttp_body(resp, &ptr, &len);
561
+ res->body.assign(ptr, len);
562
+ lcb_resphttp_http_status(resp, &res->status);
563
+ }
564
+ }
565
+
566
+ struct index_stats_point {
567
+ std::uint32_t timestamp{0};
568
+ std::uint32_t index_items_count{0};
569
+ };
570
+
571
+ std::vector<index_stats_point> index_status(lcb_INSTANCE *instance, const std::string &scope,
572
+ const std::string &collection, const std::string &index)
573
+ {
574
+ const std::string path{"/pools/default/stats/range"};
575
+ auto old_callback = lcb_install_callback(instance, LCB_CALLBACK_HTTP, (lcb_RESPCALLBACK)index_status_callback);
576
+
577
+ std::string payload =
578
+ R"(
579
+ [
580
+ {
581
+ "step": 3,
582
+ "start": -3,
583
+ "metric": [
584
+ {"label": "name", "value": "index_items_count"},
585
+ {"label": "bucket", "value": "default"},
586
+ {"label": "scope", "value": ")" +
587
+ scope + R"("},
588
+ {"label": "collection", "value": ")" +
589
+ collection + R"("},
590
+ {"label": "index", "value": ")" +
591
+ index + R"("}
592
+ ],
593
+ "nodesAggregation": "sum"
594
+ }
595
+ ]
596
+ )";
597
+
598
+ lcb_CMDHTTP *cmd;
599
+ lcb_cmdhttp_create(&cmd, LCB_HTTP_TYPE_MANAGEMENT);
600
+ lcb_cmdhttp_method(cmd, LCB_HTTP_METHOD_POST);
601
+ lcb_cmdhttp_path(cmd, path.data(), path.size());
602
+ lcb_cmdhttp_body(cmd, payload.data(), payload.size());
603
+
604
+ index_status_result res{};
605
+ lcb_STATUS rc = lcb_http(instance, &res, cmd);
606
+ lcb_cmdhttp_destroy(cmd);
607
+ EXPECT_STATUS_EQ(LCB_SUCCESS, rc);
608
+ lcb_wait(instance, LCB_WAIT_DEFAULT);
609
+
610
+ EXPECT_TRUE(res.invoked);
611
+ EXPECT_STATUS_EQ(LCB_SUCCESS, res.rc) << "http=" << res.status;
612
+
613
+ std::vector<index_stats_point> stats{};
614
+ Json::Value stats_json;
615
+ if (Json::Reader().parse(res.body, stats_json)) {
616
+ if (stats_json.isArray() && !stats_json.empty()) {
617
+ const auto &entry_json = stats_json[0];
618
+ if (entry_json.isObject() && entry_json.isMember("data") && entry_json["data"].isArray() &&
619
+ !entry_json["data"].empty()) {
620
+ const auto &metric_json = entry_json["data"][0];
621
+ if (metric_json.isObject() && metric_json.isMember("values") && metric_json["values"].isArray()) {
622
+ for (const auto &value : metric_json["values"]) {
623
+ if (value.isArray() && value.size() == 2) {
624
+ index_stats_point point{};
625
+ point.timestamp = value[0].asUInt();
626
+ point.index_items_count = std::stoul(value[1].asString());
627
+ stats.emplace_back(point);
628
+ }
629
+ }
630
+ }
631
+ }
632
+ }
633
+ }
634
+
635
+ std::sort(stats.begin(), stats.end(),
636
+ [](const index_stats_point &a, const index_stats_point &b) { return a.timestamp < b.timestamp; });
637
+
638
+ lcb_install_callback(instance, LCB_CALLBACK_HTTP, old_callback);
639
+ return stats;
640
+ }
641
+
642
+ /**
643
+ * Sergey(2021-08-11): For some reason scoped indexes are really slow on Jenkins, this function, checks number of
644
+ * indexed documents and return when it is greater or equals to requested. See CCBC-1443.
645
+ */
646
+ void wait_for_num_items_in_index(lcb_INSTANCE *instance, const string &scope, const string &collection,
647
+ const string &index, std::uint32_t expected)
648
+ {
649
+ std::uint32_t current = 0;
650
+ while (current < expected) {
651
+ auto stats = index_status(instance, scope, collection, index);
652
+ if (!stats.empty()) {
653
+ current = stats[stats.size() - 1].index_items_count;
654
+ if (current >= expected) {
655
+ return;
656
+ }
657
+ }
658
+ sleep(1);
659
+ };
660
+ }
661
+
662
+ void create_index(lcb_INSTANCE *instance, const string &index, const string &scope, const string &collection,
663
+ bool wait_for_index = true)
401
664
  {
402
665
  string keyspace = "`default`:`default`.`" + scope + "`.`" + collection + "`";
403
666
  string statement = "CREATE PRIMARY INDEX ";
@@ -416,6 +679,17 @@ void create_index(lcb_INSTANCE *instance, const string &index, const string &sco
416
679
  ASSERT_STATUS_EQ(LCB_SUCCESS, rc);
417
680
  ASSERT_TRUE(handle != nullptr);
418
681
  lcb_wait(instance, LCB_WAIT_DEFAULT);
682
+
683
+ while (wait_for_index) {
684
+ auto query_indexes = list_indexes(instance);
685
+ ASSERT_STATUS_EQ(LCB_SUCCESS, query_indexes.rc) << "meta = " << query_indexes.meta;
686
+ if (std::any_of(query_indexes.indexes.begin(), query_indexes.indexes.end(), [&index](const query_index &entry) {
687
+ return entry.name == index && entry.state == "online";
688
+ })) {
689
+ return;
690
+ }
691
+ usleep(100000);
692
+ }
419
693
  }
420
694
 
421
695
  /**
@@ -440,28 +714,31 @@ TEST_F(QueryUnitTest, testCollectionQuery)
440
714
  lcb_INSTANCE *instance;
441
715
  createConnection(hw, &instance);
442
716
 
717
+ // to ensure timeout comes from the query engine, and not generate by SDK
718
+ lcb_cntl_string(instance, "query_grace_period", "3" /* seconds */);
719
+
443
720
  string scope = unique_name("scope");
444
721
  string collection = unique_name("collection");
445
- string index = "test-index";
722
+ string index = unique_name("index");
446
723
 
447
724
  // Create a scope and collection
448
725
  create_scope(instance, scope);
449
726
  create_collection(instance, scope, collection);
450
- sleep(5);
451
727
 
452
728
  // Create an index on the collection
453
729
  create_index(instance, index, scope, collection);
454
- sleep(10); /* Wait for index to be available. Should replace with poll.*/
455
730
 
456
731
  // Insert a doc
457
- string id = insert_doc(instance, scope, collection);
732
+ auto upsert_res = upsert_doc(instance, scope, collection);
733
+ wait_for_num_items_in_index(instance, scope, collection, index, 1);
458
734
 
459
735
  N1QLResult res;
460
736
  lcb_CMDQUERY *cmd;
461
737
  lcb_cmdquery_create(&cmd);
462
- string query = "SELECT * FROM `" + collection + "` where meta().id=\"" + id + "\"";
738
+ string query = "SELECT * FROM `" + collection + "` WHERE meta().id=\"" + upsert_res.id + "\"";
463
739
  lcb_cmdquery_statement(cmd, query.c_str(), query.size());
464
740
  lcb_cmdquery_consistency(cmd, LCB_QUERY_CONSISTENCY_REQUEST);
741
+ lcb_cmdquery_metrics(cmd, true);
465
742
  lcb_cmdquery_callback(cmd, rowcb);
466
743
  lcb_cmdquery_scope_name(cmd, scope.c_str(), scope.size());
467
744
 
@@ -473,8 +750,8 @@ TEST_F(QueryUnitTest, testCollectionQuery)
473
750
  ASSERT_TRUE(handle != nullptr);
474
751
  lcb_wait(instance, LCB_WAIT_DEFAULT);
475
752
  ASSERT_TRUE(res.called);
476
- ASSERT_STATUS_EQ(LCB_SUCCESS, res.rc);
477
- ASSERT_EQ(1, res.rows.size());
753
+ ASSERT_STATUS_EQ(LCB_SUCCESS, res.rc) << "http=" << res.htcode << ", meta=" << res.meta;
754
+ ASSERT_EQ(1, res.rows.size()) << "http=" << res.htcode << ", meta=" << res.meta;
478
755
  drop_scope(instance, scope);
479
756
  }
480
757
 
@@ -490,30 +767,29 @@ TEST_F(QueryUnitTest, testQueryWithUnknownCollection)
490
767
  string collection = unique_name("collection1");
491
768
  string unknown_scope = unique_name("scope2");
492
769
  string unknown_collection = unique_name("collection2");
493
-
494
- string index = "test-index";
770
+ string index = unique_name("index");
495
771
 
496
772
  // Create a scope and collection
497
773
  create_scope(instance, scope);
498
774
  create_collection(instance, scope, collection);
499
- sleep(5);
500
775
 
501
776
  // Create an index on the collection
502
777
  create_index(instance, index, scope, collection);
503
- sleep(10); /* Wait for index to be available. Should replace with poll.*/
504
778
 
505
779
  // Insert a doc
506
- string id = insert_doc(instance, scope, collection);
780
+ auto upsert_res = upsert_doc(instance, scope, collection);
781
+ wait_for_num_items_in_index(instance, scope, collection, index, 1);
507
782
 
508
783
  {
509
784
  // Query with unknown scope
510
785
  N1QLResult res;
511
786
  lcb_CMDQUERY *cmd;
512
787
  lcb_cmdquery_create(&cmd);
513
- string query = "SELECT * FROM `" + collection + "` where meta().id=\"" + id + "\"";
788
+ string query = "SELECT * FROM `" + collection + "` where meta().id=\"" + upsert_res.id + "\"";
514
789
  lcb_cmdquery_statement(cmd, query.c_str(), query.size());
515
790
  lcb_cmdquery_callback(cmd, rowcb);
516
791
  lcb_cmdquery_scope_name(cmd, unknown_scope.c_str(), unknown_scope.size());
792
+ lcb_cmdquery_consistency(cmd, LCB_QUERY_CONSISTENCY_REQUEST);
517
793
 
518
794
  lcb_QUERY_HANDLE *handle = nullptr;
519
795
  lcb_cmdquery_handle(cmd, &handle);
@@ -532,7 +808,7 @@ TEST_F(QueryUnitTest, testQueryWithUnknownCollection)
532
808
  N1QLResult res;
533
809
  lcb_CMDQUERY *cmd;
534
810
  lcb_cmdquery_create(&cmd);
535
- string query = "SELECT * FROM `" + unknown_collection + "` where meta().id=\"" + id + "\"";
811
+ string query = "SELECT * FROM `" + unknown_collection + "` where meta().id=\"" + upsert_res.id + "\"";
536
812
  lcb_cmdquery_statement(cmd, query.c_str(), query.size());
537
813
  lcb_cmdquery_callback(cmd, rowcb);
538
814
  lcb_cmdquery_scope_name(cmd, scope.c_str(), scope.size());
@@ -559,31 +835,32 @@ TEST_F(QueryUnitTest, testCollectionPreparedQuery)
559
835
  HandleWrap hw;
560
836
  lcb_INSTANCE *instance;
561
837
  createConnection(hw, &instance);
838
+ lcb_cntl_string(instance, "query_grace_period", "3" /* seconds */);
562
839
 
563
840
  string scope = unique_name("scope");
564
841
  string collection = unique_name("collection");
565
- string index = "test-index";
842
+ string index = unique_name("index");
566
843
 
567
844
  // Create a scope and collection
568
845
  create_scope(instance, scope);
569
846
  create_collection(instance, scope, collection);
570
- sleep(5);
571
847
 
572
848
  // Create an index on the collection
573
849
  create_index(instance, index, scope, collection);
574
- sleep(10); /* Wait for index to be available. Should replace with poll.*/
575
850
 
576
851
  // Insert a doc
577
- string id = insert_doc(instance, scope, collection);
852
+ auto upsert_res = upsert_doc(instance, scope, collection);
853
+ wait_for_num_items_in_index(instance, scope, collection, index, 1);
578
854
 
579
855
  N1QLResult res;
580
856
  lcb_CMDQUERY *cmd;
581
857
  lcb_cmdquery_create(&cmd);
582
- string query = "SELECT * FROM `" + collection + "` where meta().id=\"" + id + "\"";
858
+ string query = "SELECT * FROM `" + collection + "` where meta().id=\"" + upsert_res.id + "\"";
583
859
  lcb_cmdquery_statement(cmd, query.c_str(), query.size());
584
860
  lcb_cmdquery_callback(cmd, rowcb);
585
861
  lcb_cmdquery_scope_name(cmd, scope.c_str(), scope.size());
586
862
  lcb_cmdquery_adhoc(cmd, false);
863
+ lcb_cmdquery_consistency(cmd, LCB_QUERY_CONSISTENCY_REQUEST);
587
864
 
588
865
  lcb_QUERY_HANDLE *handle = nullptr;
589
866
  lcb_cmdquery_handle(cmd, &handle);
@@ -593,8 +870,8 @@ TEST_F(QueryUnitTest, testCollectionPreparedQuery)
593
870
  ASSERT_TRUE(handle != nullptr);
594
871
  lcb_wait(instance, LCB_WAIT_DEFAULT);
595
872
  ASSERT_TRUE(res.called);
596
- ASSERT_STATUS_EQ(LCB_SUCCESS, res.rc) << lcb_strerror_short(res.rc);
597
- ASSERT_EQ(1, res.rows.size());
873
+ ASSERT_STATUS_EQ(LCB_SUCCESS, res.rc) << "http=" << res.htcode << ", meta=" << res.meta;
874
+ ASSERT_EQ(1, res.rows.size()) << "http=" << res.htcode << ", meta=" << res.meta;
598
875
 
599
876
  drop_scope(instance, scope);
600
877
  }
@@ -865,3 +1142,23 @@ TEST_F(QueryUnitTest, testRawQuery)
865
1142
  ASSERT_EQ("\"foo\"", res.rows[3]);
866
1143
  ASSERT_EQ("false", res.rows[4]);
867
1144
  }
1145
+
1146
+ TEST_F(QueryUnitTest, testReadOnlyWithNoResults)
1147
+ {
1148
+ SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_65)
1149
+ lcb_INSTANCE *instance;
1150
+ HandleWrap hw;
1151
+ if (!createClusterQueryConnection(hw, &instance)) {
1152
+ SKIP_CLUSTER_QUERY_TEST();
1153
+ }
1154
+ N1QLResult res;
1155
+ std::string query = "SELECT * FROM " + MockEnvironment::getInstance()->getBucket() + " LIMIT 0";
1156
+ makeCommand(query.c_str());
1157
+ lcb_cmdquery_readonly(cmd, 1);
1158
+ lcb_cmdquery_timeout(cmd, LCB_MS2US(3000));
1159
+ lcb_STATUS rc = lcb_query(instance, &res, cmd);
1160
+ ASSERT_STATUS_EQ(LCB_SUCCESS, rc);
1161
+ lcb_wait(instance, LCB_WAIT_DEFAULT);
1162
+ ASSERT_STATUS_EQ(LCB_SUCCESS, res.rc);
1163
+ ASSERT_EQ(0, res.rows.size());
1164
+ }
@@ -243,6 +243,7 @@ TEST_F(ViewsUnitTest, testSimpleView)
243
243
  {
244
244
  SKIP_UNLESS_MOCK();
245
245
  // Requires beer-sample
246
+ MockEnvironment *mock = MockEnvironment::getInstance();
246
247
  HandleWrap hw;
247
248
  lcb_INSTANCE *instance;
248
249
  connectBeerSample(hw, &instance);