couchbase 3.2.0 → 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);