couchbase 3.4.1 → 3.4.2
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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/couchbase/CMakeLists.txt +2 -0
- data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
- data/ext/couchbase/core/cluster_options.hxx +0 -1
- data/ext/couchbase/core/config_profile.cxx +23 -1
- data/ext/couchbase/core/config_profile.hxx +2 -12
- data/ext/couchbase/core/impl/analytics.cxx +236 -0
- data/ext/couchbase/core/impl/cluster.cxx +0 -1
- data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
- data/ext/couchbase/core/impl/query.cxx +5 -5
- data/ext/couchbase/core/io/dns_client.cxx +225 -0
- data/ext/couchbase/core/io/dns_client.hxx +19 -188
- data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
- data/ext/couchbase/core/transactions/attempt_context_impl.cxx +3 -0
- data/ext/couchbase/core/transactions/attempt_context_impl.hxx +1 -1
- data/ext/couchbase/core/transactions/internal/transaction_context.hxx +12 -12
- data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
- data/ext/couchbase/core/transactions/transaction_context.cxx +1 -0
- data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
- data/ext/couchbase/core/utils/connection_string.cxx +10 -3
- data/ext/couchbase/core/utils/connection_string.hxx +3 -3
- data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
- data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
- data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
- data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
- data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
- data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
- data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
- data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
- data/ext/couchbase/couchbase/cluster.hxx +33 -0
- data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
- data/ext/couchbase/couchbase/query_options.hxx +0 -1
- data/ext/couchbase/couchbase/scope.hxx +33 -0
- data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
- data/ext/couchbase/test/CMakeLists.txt +1 -2
- data/ext/couchbase/test/test_helper.hxx +1 -1
- data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
- data/ext/couchbase/test/test_integration_crud.cxx +8 -1
- data/ext/couchbase/test/test_integration_examples.cxx +41 -0
- data/ext/couchbase/test/test_integration_management.cxx +15 -3
- data/ext/couchbase/test/test_integration_search.cxx +601 -0
- data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
- data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
- data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
- data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
- data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
- data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
- data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
- data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
- data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
- data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
- data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
- data/ext/couchbase/third_party/snappy/snappy.h +19 -4
- data/ext/couchbase.cxx +27 -6
- data/ext/revisions.rb +3 -3
- data/lib/couchbase/cluster.rb +13 -9
- data/lib/couchbase/cluster_registry.rb +7 -2
- data/lib/couchbase/configuration.rb +3 -4
- data/lib/couchbase/options.rb +85 -2
- data/lib/couchbase/search_options.rb +158 -240
- data/lib/couchbase/version.rb +1 -1
- metadata +17 -6
- 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/ | 
| 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:: | 
| 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:: | 
| 134 | 
            -
                     | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 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 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
                       | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 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 | 
            -
                     | 
| 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 | 
            -
             | 
| 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]() {
         |