Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/operations/document_lookup_in.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ auto
lookup_in_request::encode_to(lookup_in_request::encoded_request_type& encoded,
mcbp_context&& context) -> std::error_code
{
if (specs.empty()) {
return errc::common::invalid_argument;
}

for (std::size_t i = 0; i < specs.size(); ++i) {
specs[i].original_index_ = i;

Expand Down
4 changes: 4 additions & 0 deletions core/operations/document_lookup_in_all_replicas.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ struct lookup_in_all_replicas_request {
ec = errc::key_value::document_irretrievable;
}

if (!ec && specs.empty()) {
ec = errc::common::invalid_argument;
}

if (ec) {
return h(response_type{ make_subdocument_error_context(
make_key_value_error_context(ec, id), ec, {}, {}, false) });
Expand Down
4 changes: 4 additions & 0 deletions core/operations/document_lookup_in_any_replica.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ struct lookup_in_any_replica_request {
ec = errc::key_value::document_irretrievable;
}

if (!ec && specs.empty()) {
ec = errc::common::invalid_argument;
}

if (ec) {
return h(response_type{ make_subdocument_error_context(
make_key_value_error_context(ec, id), ec, {}, {}, false) });
Expand Down
3 changes: 3 additions & 0 deletions core/operations/document_mutate_in.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ mutate_in_request::encode_to(mutate_in_request::encoded_request_type& encoded,
!context.supports_feature(protocol::hello_feature::subdoc_create_as_deleted)) {
return errc::common::unsupported_operation;
}
if (specs.empty()) {
return errc::common::invalid_argument;
}
for (std::size_t i = 0; i < specs.size(); ++i) {
auto& entry = specs[i];
entry.original_index_ = i;
Expand Down
60 changes: 60 additions & 0 deletions test/test_integration_subdoc.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,66 @@ TEST_CASE("integration: subdoc any replica reads", "[integration]")
}
}

TEST_CASE("integration: subdoc invalid_argument if empty specs", "[integration]")
{
test::utils::integration_test_guard integration;

SECTION("core API")
{
couchbase::core::document_id id{
integration.ctx.bucket, "_default", "_default", test::utils::uniq_id("empty_specs")
};

couchbase::core::operations::lookup_in_request lookupin_req{ id };
auto lookupin_resp = test::utils::execute(integration.cluster, lookupin_req);
REQUIRE(lookupin_resp.ctx.ec() == couchbase::errc::common::invalid_argument);

if (integration.has_bucket_capability("subdoc.ReplicaRead")) {
couchbase::core::operations::lookup_in_any_replica_request lookupin_any_replica_req{ id };
auto lookupin_any_replica_resp =
test::utils::execute(integration.cluster, lookupin_any_replica_req);
REQUIRE(lookupin_any_replica_resp.ctx.ec() == couchbase::errc::common::invalid_argument);

couchbase::core::operations::lookup_in_all_replicas_request lookup_in_all_replicas_req{ id };
auto lookup_in_all_replicas_resp =
test::utils::execute(integration.cluster, lookup_in_all_replicas_req);
REQUIRE(lookup_in_all_replicas_resp.ctx.ec() == couchbase::errc::common::invalid_argument);
}

couchbase::core::operations::mutate_in_request mutatein_req{ id };
auto mutatein_resp = test::utils::execute(integration.cluster, mutatein_req);
REQUIRE(mutatein_resp.ctx.ec() == couchbase::errc::common::invalid_argument);
}

SECTION("public API")
{
auto test_ctx = integration.ctx;
auto [e, cluster] =
couchbase::cluster::connect(test_ctx.connection_string, test_ctx.build_options()).get();
REQUIRE_SUCCESS(e.ec());

auto collection = cluster.bucket(test_ctx.bucket).scope("_default").collection("_default");

auto key = test::utils::uniq_id("empty_specs");
auto [lookupin_err, lookupin_resp] = collection.lookup_in(key, {}).get();
REQUIRE(lookupin_err.ec() == couchbase::errc::common::invalid_argument);

if (integration.has_bucket_capability("subdoc.ReplicaRead")) {
auto [lookup_in_any_replica_err, lookup_in_any_replica_resp] =
collection.lookup_in_any_replica(key, {}).get();
REQUIRE(lookup_in_any_replica_err.ec() == couchbase::errc::common::invalid_argument);

auto [lookup_in_all_replicas_err, lookup_in_all_replicas_resp] =
collection.lookup_in_all_replicas(key, {}).get();
REQUIRE(lookup_in_all_replicas_err.ec() == couchbase::errc::common::invalid_argument);
REQUIRE(lookup_in_all_replicas_resp.empty());
}

auto [mutate_in_err, mutate_in_resp] = collection.mutate_in(key, {}).get();
REQUIRE(mutate_in_err.ec() == couchbase::errc::common::invalid_argument);
}
}

TEST_CASE("integration: public API lookup in per-spec errors", "[integration]")
{
test::utils::integration_test_guard integration;
Expand Down
Loading