couchbase 3.4.1 → 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +2 -0
  4. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
  5. data/ext/couchbase/core/cluster_options.hxx +0 -1
  6. data/ext/couchbase/core/config_profile.cxx +23 -1
  7. data/ext/couchbase/core/config_profile.hxx +2 -12
  8. data/ext/couchbase/core/impl/analytics.cxx +236 -0
  9. data/ext/couchbase/core/impl/cluster.cxx +0 -1
  10. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
  11. data/ext/couchbase/core/impl/query.cxx +5 -5
  12. data/ext/couchbase/core/io/dns_client.cxx +225 -0
  13. data/ext/couchbase/core/io/dns_client.hxx +19 -188
  14. data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
  15. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +3 -0
  16. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +1 -1
  17. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +12 -12
  18. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
  19. data/ext/couchbase/core/transactions/transaction_context.cxx +1 -0
  20. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
  21. data/ext/couchbase/core/utils/connection_string.cxx +10 -3
  22. data/ext/couchbase/core/utils/connection_string.hxx +3 -3
  23. data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
  24. data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
  25. data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
  26. data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
  27. data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
  28. data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
  29. data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
  30. data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
  31. data/ext/couchbase/couchbase/cluster.hxx +33 -0
  32. data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
  33. data/ext/couchbase/couchbase/query_options.hxx +0 -1
  34. data/ext/couchbase/couchbase/scope.hxx +33 -0
  35. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
  36. data/ext/couchbase/test/CMakeLists.txt +1 -2
  37. data/ext/couchbase/test/test_helper.hxx +1 -1
  38. data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
  39. data/ext/couchbase/test/test_integration_crud.cxx +8 -1
  40. data/ext/couchbase/test/test_integration_examples.cxx +41 -0
  41. data/ext/couchbase/test/test_integration_management.cxx +15 -3
  42. data/ext/couchbase/test/test_integration_search.cxx +601 -0
  43. data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
  44. data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
  45. data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
  46. data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
  47. data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
  48. data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
  49. data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
  50. data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
  51. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
  52. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
  53. data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
  54. data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
  55. data/ext/couchbase/third_party/snappy/snappy.h +19 -4
  56. data/ext/couchbase.cxx +27 -6
  57. data/ext/revisions.rb +3 -3
  58. data/lib/couchbase/cluster.rb +13 -9
  59. data/lib/couchbase/cluster_registry.rb +7 -2
  60. data/lib/couchbase/configuration.rb +3 -4
  61. data/lib/couchbase/options.rb +85 -2
  62. data/lib/couchbase/search_options.rb +158 -240
  63. data/lib/couchbase/version.rb +1 -1
  64. metadata +17 -6
  65. data/ext/couchbase/core/CMakeLists.txt +0 -0
@@ -17,7 +17,7 @@
17
17
 
18
18
  #include "core/operations/management/analytics.hxx"
19
19
  #include "core/operations/management/collection_create.hxx"
20
- #include "core/operations/management/scope_create.hxx"
20
+ #include "core/operations/management/collections.hxx"
21
21
  #include "test_helper_integration.hxx"
22
22
 
23
23
  TEST_CASE("integration: analytics query")
@@ -78,7 +78,7 @@ TEST_CASE("integration: analytics query")
78
78
  REQUIRE(test::utils::wait_until([&]() {
79
79
  couchbase::core::operations::analytics_request req{};
80
80
  req.statement = fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = ?)", dataset_name);
81
- req.positional_parameters.emplace_back(couchbase::core::json_string(couchbase::core::utils::json::generate(test_value)));
81
+ req.positional_parameters.emplace_back(couchbase::core::utils::json::generate(test_value));
82
82
  resp = test::utils::execute(integration.cluster, req);
83
83
  return resp.rows.size() == 1;
84
84
  }));
@@ -130,10 +130,30 @@ TEST_CASE("integration: analytics query")
130
130
 
131
131
  SECTION("consistency")
132
132
  {
133
- couchbase::core::operations::analytics_request req{};
134
- req.statement = fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value);
135
- req.scan_consistency = couchbase::core::analytics_scan_consistency::request_plus;
136
- auto resp = test::utils::execute(integration.cluster, req);
133
+ couchbase::core::operations::analytics_response resp{};
134
+ CHECK(test::utils::wait_until([&]() {
135
+ /*
136
+ * In consistency test, always do fresh mutation
137
+ */
138
+ test_value = test::utils::uniq_id("value");
139
+ value = couchbase::core::utils::json::generate({ { "testkey", test_value } });
140
+ {
141
+ auto id = couchbase::core::document_id(integration.ctx.bucket, "_default", "_default", key);
142
+ couchbase::core::operations::upsert_request req{ id, couchbase::core::utils::to_binary(value) };
143
+ REQUIRE_SUCCESS(test::utils::execute(integration.cluster, req).ctx.ec());
144
+ }
145
+
146
+ couchbase::core::operations::analytics_request req{};
147
+ req.statement = fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value);
148
+ req.scan_consistency = couchbase::core::analytics_scan_consistency::request_plus;
149
+ resp = test::utils::execute(integration.cluster, req);
150
+ /* Analytics might give us code 23027, ignore it here
151
+ *
152
+ * "errors": [{"code": 23027, "msg": "Bucket default on link Default.Local is not connected"} ],
153
+ */
154
+ return resp.ctx.first_error_code != 23027;
155
+ }));
156
+
137
157
  REQUIRE_SUCCESS(resp.ctx.ec);
138
158
  REQUIRE(resp.rows.size() == 1);
139
159
  REQUIRE(resp.rows[0] == value);
@@ -185,13 +205,15 @@ TEST_CASE("integration: analytics scope query")
185
205
  REQUIRE(created);
186
206
  }
187
207
 
188
- {
189
- couchbase::core::operations::analytics_request req{};
190
- req.statement =
191
- fmt::format("ALTER COLLECTION `{}`.`{}`.`{}` ENABLE ANALYTICS", integration.ctx.bucket, scope_name, collection_name);
192
- auto resp = test::utils::execute(integration.cluster, req);
193
- REQUIRE_SUCCESS(resp.ctx.ec);
194
- }
208
+ CHECK(test::utils::wait_until(
209
+ [&]() {
210
+ couchbase::core::operations::analytics_request req{};
211
+ req.statement =
212
+ fmt::format("ALTER COLLECTION `{}`.`{}`.`{}` ENABLE ANALYTICS", integration.ctx.bucket, scope_name, collection_name);
213
+ auto resp = test::utils::execute(integration.cluster, req);
214
+ return !resp.ctx.ec;
215
+ },
216
+ std::chrono::minutes{ 5 }));
195
217
 
196
218
  auto key = test::utils::uniq_id("key");
197
219
  auto test_value = test::utils::uniq_id("value");
@@ -259,3 +281,257 @@ TEST_CASE("unit: analytics query")
259
281
  REQUIRE(http_req.headers.find("analytics-priority") == http_req.headers.end());
260
282
  }
261
283
  }
284
+
285
+ TEST_CASE("integration: public API analytics query")
286
+ {
287
+ test::utils::integration_test_guard integration;
288
+
289
+ if (!integration.cluster_version().supports_analytics()) {
290
+ return;
291
+ }
292
+
293
+ auto cluster = couchbase::cluster(integration.cluster);
294
+ auto bucket = cluster.bucket(integration.ctx.bucket);
295
+ auto collection = bucket.default_collection();
296
+
297
+ auto dataset_name = test::utils::uniq_id("dataset");
298
+
299
+ {
300
+ couchbase::core::operations::management::analytics_dataset_create_request req{};
301
+ req.dataset_name = dataset_name;
302
+ req.bucket_name = integration.ctx.bucket;
303
+ auto resp = test::utils::execute(integration.cluster, req);
304
+ REQUIRE_SUCCESS(resp.ctx.ec);
305
+ }
306
+
307
+ {
308
+ couchbase::core::operations::management::analytics_link_connect_request req{};
309
+ req.force = true;
310
+ auto resp = test::utils::execute(integration.cluster, req);
311
+ REQUIRE_SUCCESS(resp.ctx.ec);
312
+ }
313
+
314
+ auto key = test::utils::uniq_id("key");
315
+ auto test_value = test::utils::uniq_id("value");
316
+ tao::json::value document = {
317
+ { "testkey", test_value },
318
+ };
319
+ {
320
+ auto [ctx, resp] = collection.upsert(key, document).get();
321
+ REQUIRE_SUCCESS(ctx.ec());
322
+ }
323
+
324
+ SECTION("simple query")
325
+ {
326
+ couchbase::analytics_result resp{};
327
+ couchbase::analytics_error_context ctx{};
328
+ CHECK(test::utils::wait_until([&]() {
329
+ std::tie(ctx, resp) =
330
+ cluster.analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value))
331
+ .get();
332
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
333
+ }));
334
+ REQUIRE_SUCCESS(ctx.ec());
335
+ REQUIRE_FALSE(resp.meta_data().request_id().empty());
336
+ REQUIRE_FALSE(resp.meta_data().client_context_id().empty());
337
+ REQUIRE(resp.meta_data().status() == couchbase::analytics_status::success);
338
+ auto rows = resp.rows_as_json();
339
+ REQUIRE(rows.size() == 1);
340
+ REQUIRE(rows[0] == document);
341
+ }
342
+
343
+ SECTION("positional params")
344
+ {
345
+ couchbase::analytics_result resp{};
346
+ couchbase::analytics_error_context ctx{};
347
+ CHECK(test::utils::wait_until([&]() {
348
+ std::tie(ctx, resp) = cluster
349
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = ?)", dataset_name),
350
+ couchbase::analytics_options{}.positional_parameters(test_value))
351
+ .get();
352
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
353
+ }));
354
+ REQUIRE_SUCCESS(ctx.ec());
355
+ auto rows = resp.rows_as_json();
356
+ REQUIRE(rows.size() == 1);
357
+ REQUIRE(rows[0] == document);
358
+ }
359
+
360
+ SECTION("named params")
361
+ {
362
+ couchbase::analytics_result resp{};
363
+ couchbase::analytics_error_context ctx{};
364
+ CHECK(test::utils::wait_until([&]() {
365
+ std::tie(ctx, resp) =
366
+ cluster
367
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = $testkey)", dataset_name),
368
+ couchbase::analytics_options{}.named_parameters(std::pair{ "testkey", test_value }))
369
+ .get();
370
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
371
+ }));
372
+ REQUIRE_SUCCESS(ctx.ec());
373
+ auto rows = resp.rows_as_json();
374
+ REQUIRE(rows.size() == 1);
375
+ REQUIRE(rows[0] == document);
376
+ }
377
+
378
+ SECTION("named params preformatted")
379
+ {
380
+ couchbase::analytics_result resp{};
381
+ couchbase::analytics_error_context ctx{};
382
+ CHECK(test::utils::wait_until([&]() {
383
+ std::tie(ctx, resp) =
384
+ cluster
385
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = $testkey)", dataset_name),
386
+ couchbase::analytics_options{}.encoded_named_parameters(
387
+ { { "testkey", couchbase::core::utils::json::generate_binary(test_value) } }))
388
+ .get();
389
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
390
+ }));
391
+ REQUIRE_SUCCESS(ctx.ec());
392
+ auto rows = resp.rows_as_json();
393
+ REQUIRE(rows.size() == 1);
394
+ REQUIRE(rows[0] == document);
395
+ }
396
+
397
+ SECTION("raw")
398
+ {
399
+ couchbase::analytics_result resp{};
400
+ couchbase::analytics_error_context ctx{};
401
+ CHECK(test::utils::wait_until([&]() {
402
+ std::tie(ctx, resp) =
403
+ cluster
404
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = $testkey)", dataset_name),
405
+ couchbase::analytics_options{}.raw("$testkey", test_value))
406
+ .get();
407
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
408
+ }));
409
+ REQUIRE_SUCCESS(ctx.ec());
410
+ auto rows = resp.rows_as_json();
411
+ REQUIRE(rows.size() == 1);
412
+ REQUIRE(rows[0] == document);
413
+ }
414
+
415
+ SECTION("consistency")
416
+ {
417
+ couchbase::analytics_result resp{};
418
+ couchbase::analytics_error_context ctx{};
419
+ CHECK(test::utils::wait_until([&]() {
420
+ /*
421
+ * In consistency test, always do fresh mutation
422
+ */
423
+ test_value = test::utils::uniq_id("value");
424
+ document = {
425
+ { "testkey", test_value },
426
+ };
427
+ {
428
+ auto [ctx2, _] = collection.upsert(key, document).get();
429
+ REQUIRE_SUCCESS(ctx2.ec());
430
+ }
431
+
432
+ std::tie(ctx, resp) =
433
+ cluster
434
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value),
435
+ couchbase::analytics_options{}.scan_consistency(couchbase::analytics_scan_consistency::request_plus))
436
+ .get();
437
+ /* Analytics might give us code 23027, ignore it here
438
+ *
439
+ * "errors": [{"code": 23027, "msg": "Bucket default on link Default.Local is not connected"} ],
440
+ */
441
+ return ctx.first_error_code() != 23027;
442
+ }));
443
+
444
+ REQUIRE_SUCCESS(ctx.ec());
445
+ auto rows = resp.rows_as_json();
446
+ REQUIRE(rows.size() == 1);
447
+ REQUIRE(rows[0] == document);
448
+ }
449
+
450
+ SECTION("readonly")
451
+ {
452
+ auto [ctx, resp] =
453
+ cluster.analytics_query(fmt::format("DROP DATASET Default.`{}`", dataset_name), couchbase::analytics_options{}.readonly(true))
454
+ .get();
455
+
456
+ REQUIRE(ctx.ec() == couchbase::errc::common::internal_server_failure);
457
+ REQUIRE(resp.meta_data().status() == couchbase::analytics_status::fatal);
458
+ }
459
+
460
+ {
461
+ couchbase::core::operations::management::analytics_dataset_drop_request req{};
462
+ req.dataset_name = dataset_name;
463
+ test::utils::execute(integration.cluster, req);
464
+ }
465
+ }
466
+
467
+ TEST_CASE("integration: public API analytics scope query")
468
+ {
469
+ test::utils::integration_test_guard integration;
470
+
471
+ if (!integration.cluster_version().supports_analytics() || !integration.cluster_version().supports_collections()) {
472
+ return;
473
+ }
474
+
475
+ auto cluster = couchbase::cluster(integration.cluster);
476
+ auto bucket = cluster.bucket(integration.ctx.bucket);
477
+
478
+ auto scope_name = test::utils::uniq_id("scope");
479
+ auto collection_name = test::utils::uniq_id("collection");
480
+
481
+ {
482
+ const couchbase::core::operations::management::scope_create_request req{ integration.ctx.bucket, scope_name };
483
+ auto resp = test::utils::execute(integration.cluster, req);
484
+ REQUIRE_SUCCESS(resp.ctx.ec);
485
+ auto created = test::utils::wait_until_collection_manifest_propagated(integration.cluster, integration.ctx.bucket, resp.uid);
486
+ REQUIRE(created);
487
+ }
488
+
489
+ {
490
+ const couchbase::core::operations::management::collection_create_request req{ integration.ctx.bucket, scope_name, collection_name };
491
+ auto resp = test::utils::execute(integration.cluster, req);
492
+ REQUIRE_SUCCESS(resp.ctx.ec);
493
+ auto created = test::utils::wait_until_collection_manifest_propagated(integration.cluster, integration.ctx.bucket, resp.uid);
494
+ REQUIRE(created);
495
+ }
496
+
497
+ CHECK(test::utils::wait_until(
498
+ [&]() {
499
+ auto [ctx, resp] = cluster
500
+ .analytics_query(fmt::format(
501
+ "ALTER COLLECTION `{}`.`{}`.`{}` ENABLE ANALYTICS", integration.ctx.bucket, scope_name, collection_name))
502
+ .get();
503
+ return !ctx.ec();
504
+ },
505
+ std::chrono::minutes{ 5 }));
506
+
507
+ auto scope = bucket.scope(scope_name);
508
+ auto collection = scope.collection(collection_name);
509
+
510
+ auto key = test::utils::uniq_id("key");
511
+ auto test_value = test::utils::uniq_id("value");
512
+ const tao::json::value document = {
513
+ { "testkey", test_value },
514
+ };
515
+ {
516
+ auto [ctx, resp] = collection.upsert(key, document).get();
517
+ REQUIRE_SUCCESS(ctx.ec());
518
+ }
519
+
520
+ couchbase::analytics_result resp{};
521
+ couchbase::analytics_error_context ctx{};
522
+ CHECK(test::utils::wait_until([&]() {
523
+ std::tie(ctx, resp) =
524
+ scope.analytics_query(fmt::format(R"(SELECT testkey FROM `{}` WHERE testkey = "{}")", collection_name, test_value)).get();
525
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
526
+ }));
527
+ REQUIRE_SUCCESS(ctx.ec());
528
+ REQUIRE(resp.rows_as_json()[0] == document);
529
+ REQUIRE_FALSE(resp.meta_data().request_id().empty());
530
+ REQUIRE_FALSE(resp.meta_data().client_context_id().empty());
531
+ REQUIRE(resp.meta_data().status() == couchbase::analytics_status::success);
532
+
533
+ {
534
+ const couchbase::core::operations::management::scope_drop_request req{ integration.ctx.bucket, scope_name };
535
+ test::utils::execute(integration.cluster, req);
536
+ }
537
+ }
@@ -228,6 +228,9 @@ TEST_CASE("integration: pessimistic locking", "[integration]")
228
228
  {
229
229
  couchbase::core::operations::get_and_lock_request req{ id };
230
230
  req.lock_time = lock_time;
231
+ if (integration.ctx.deployment == test::utils::deployment_type::capella) {
232
+ req.timeout = std::chrono::seconds{ 2 };
233
+ }
231
234
  auto resp = test::utils::execute(integration.cluster, req);
232
235
  REQUIRE(resp.ctx.ec() == couchbase::errc::common::ambiguous_timeout);
233
236
  REQUIRE(resp.ctx.retried_because_of(couchbase::retry_reason::key_value_locked));
@@ -810,7 +813,11 @@ TEST_CASE("integration: pessimistic locking with public API", "[integration]")
810
813
 
811
814
  // it is not allowed to lock the same key twice
812
815
  {
813
- auto [ctx, resp] = collection.get_and_lock(id, lock_time, {}).get();
816
+ couchbase::get_and_lock_options options{};
817
+ if (integration.ctx.deployment == test::utils::deployment_type::capella) {
818
+ options.timeout(std::chrono::seconds{ 2 });
819
+ }
820
+ auto [ctx, resp] = collection.get_and_lock(id, lock_time, options).get();
814
821
  REQUIRE(ctx.ec() == couchbase::errc::common::ambiguous_timeout);
815
822
  REQUIRE(ctx.retried_because_of(couchbase::retry_reason::key_value_locked));
816
823
  }
@@ -17,6 +17,10 @@
17
17
 
18
18
  #include "test_helper_integration.hxx"
19
19
 
20
+ #include "core/operations/management/query_index_build.hxx"
21
+ #include "core/operations/management/query_index_create.hxx"
22
+ #include "core/operations/management/query_index_get_all.hxx"
23
+
20
24
  #include <couchbase/cluster.hxx>
21
25
  #include <couchbase/fmt/cas.hxx>
22
26
  #include <couchbase/fmt/mutation_token.hxx>
@@ -129,6 +133,43 @@ TEST_CASE("example: start using", "[integration]")
129
133
  return;
130
134
  }
131
135
 
136
+ {
137
+ couchbase::core::operations::management::query_index_create_request req{};
138
+ req.index_name = "def_inventory_airline_primary";
139
+ req.bucket_name = "travel-sample";
140
+ req.scope_name = "inventory";
141
+ req.collection_name = "airline";
142
+ req.is_primary = true;
143
+ req.ignore_if_exists = true;
144
+ auto resp = test::utils::execute(integration.cluster, req);
145
+ REQUIRE_FALSE(resp.ctx.ec);
146
+ }
147
+
148
+ {
149
+ couchbase::core::operations::management::query_index_build_request req{};
150
+ req.index_names = { "def_inventory_airline_primary" };
151
+ req.bucket_name = "travel-sample";
152
+ req.scope_name = "inventory";
153
+ req.collection_name = "airline";
154
+ auto resp = test::utils::execute(integration.cluster, req);
155
+ REQUIRE_FALSE(resp.ctx.ec);
156
+ }
157
+
158
+ CHECK(test::utils::wait_until(
159
+ [&integration]() {
160
+ couchbase::core::operations::management::query_index_get_all_request req{};
161
+ req.bucket_name = "travel-sample";
162
+ req.scope_name = "inventory";
163
+ auto resp = test::utils::execute(integration.cluster, req);
164
+ if (resp.ctx.ec) {
165
+ return false;
166
+ }
167
+ return std::any_of(resp.indexes.begin(), resp.indexes.end(), [](const auto& index) {
168
+ return index.collection_name == "airline" && index.is_primary && index.state == "online";
169
+ });
170
+ },
171
+ std::chrono::minutes{ 5 }));
172
+
132
173
  const auto env = test::utils::test_context::load_from_environment();
133
174
  const char* argv[] = {
134
175
  "start_using", // name of the "executable"
@@ -2851,11 +2851,23 @@ wait_for_search_pindexes_ready(test::utils::integration_test_guard& integration,
2851
2851
  return false;
2852
2852
  }
2853
2853
  auto stats = couchbase::core::utils::json::parse(resp.stats);
2854
- const auto* num_pindexes_actual = stats.find(fmt::format("{}:{}:num_pindexes_actual", integration.ctx.bucket, index_name));
2854
+
2855
+ const auto num_pindexes_actual_key = fmt::format("{}:{}:num_pindexes_actual", integration.ctx.bucket, index_name);
2856
+ const auto num_pindexes_target_key = fmt::format("{}:{}:num_pindexes_target", integration.ctx.bucket, index_name);
2857
+ const auto* num_pindexes_actual = stats.find(num_pindexes_actual_key);
2858
+ const auto* num_pindexes_target = stats.find(num_pindexes_target_key);
2859
+ CB_LOG_DEBUG(
2860
+ "wait_for_search_pindexes_ready: {}={}, {}={}",
2861
+ num_pindexes_actual_key,
2862
+ (num_pindexes_actual == nullptr || !num_pindexes_actual->is_number()) ? "missing"
2863
+ : std::to_string(num_pindexes_actual->get_unsigned()),
2864
+ num_pindexes_target_key,
2865
+ (num_pindexes_target == nullptr || !num_pindexes_target->is_number()) ? "missing"
2866
+ : std::to_string(num_pindexes_target->get_unsigned()));
2867
+
2855
2868
  if (num_pindexes_actual == nullptr || !num_pindexes_actual->is_number()) {
2856
2869
  return false;
2857
2870
  }
2858
- const auto* num_pindexes_target = stats.find(fmt::format("{}:{}:num_pindexes_target", integration.ctx.bucket, index_name));
2859
2871
  if (num_pindexes_target == nullptr || !num_pindexes_target->is_number()) {
2860
2872
  return false;
2861
2873
  }
@@ -2889,7 +2901,7 @@ TEST_CASE("integration: search index management analyze document", "[integration
2889
2901
  REQUIRE_SUCCESS(resp.ctx.ec);
2890
2902
  }
2891
2903
 
2892
- REQUIRE(wait_for_search_pindexes_ready(integration, index_name));
2904
+ REQUIRE(test::utils::wait_for_search_pindexes_ready(integration.cluster, integration.ctx.bucket, index_name));
2893
2905
 
2894
2906
  couchbase::core::operations::management::search_index_analyze_document_response resp;
2895
2907
  bool operation_completed = test::utils::wait_until([&integration, &index_name, &resp]() {