From 3087d97e8ac6b081bb6c6403b64e8b8cd8be6eac Mon Sep 17 00:00:00 2001 From: mpeddada1 Date: Wed, 24 Dec 2025 15:50:05 +0000 Subject: [PATCH 1/2] feat: remove DataClient and it's usages --- examples/gcs2cbt.cc | 5 +- google/cloud/bigtable/CMakeLists.txt | 8 - google/cloud/bigtable/benchmarks/benchmark.cc | 1 + .../benchmarks/embedded_server_test.cc | 1 + .../bigtable/bigtable_client_testing.bzl | 5 - .../bigtable/bigtable_client_unit_tests.bzl | 15 - google/cloud/bigtable/data_client.cc | 242 ---- google/cloud/bigtable/data_client.h | 235 ---- google/cloud/bigtable/data_client_test.cc | 85 -- .../bigtable_instance_admin_snippets.cc | 1 + .../cloud/bigtable/examples/data_snippets.cc | 1 + .../bigtable/google_cloud_cpp_bigtable.bzl | 12 - .../bigtable/internal/async_bulk_apply.cc | 1 + .../internal/async_bulk_apply_test.cc | 1 + .../cloud/bigtable/internal/bulk_mutator.cc | 17 +- google/cloud/bigtable/internal/bulk_mutator.h | 8 +- .../bigtable/internal/bulk_mutator_test.cc | 1 + .../bigtable/internal/default_row_reader.cc | 1 + .../internal/default_row_reader_test.cc | 1 + .../internal/legacy_async_bulk_apply.cc | 107 -- .../internal/legacy_async_bulk_apply.h | 81 -- .../internal/legacy_async_bulk_apply_test.cc | 522 -------- .../internal/legacy_async_row_reader.cc | 281 ---- .../internal/legacy_async_row_reader.h | 183 --- .../internal/legacy_async_row_reader_test.cc | 1159 ----------------- .../internal/legacy_async_row_sampler.cc | 121 -- .../internal/legacy_async_row_sampler.h | 84 -- .../internal/legacy_async_row_sampler_test.cc | 462 ------- .../internal/legacy_bulk_mutator_test.cc | 496 ------- .../bigtable/internal/legacy_row_reader.cc | 200 --- .../bigtable/internal/legacy_row_reader.h | 133 -- .../internal/legacy_row_reader_test.cc | 871 ------------- .../bigtable/internal/logging_data_client.cc | 240 ---- .../bigtable/internal/logging_data_client.h | 159 --- .../internal/logging_data_client_test.cc | 160 --- google/cloud/bigtable/legacy_table_test.cc | 409 ------ .../bigtable/metadata_update_policy_test.cc | 4 +- .../bigtable/mocks/mock_data_connection.h | 2 + google/cloud/bigtable/row_reader.cc | 1 - google/cloud/bigtable/row_reader.h | 1 - google/cloud/bigtable/table.cc | 520 +------- google/cloud/bigtable/table.h | 215 +-- google/cloud/bigtable/table_apply_test.cc | 113 -- .../cloud/bigtable/table_bulk_apply_test.cc | 391 ------ .../table_check_and_mutate_row_test.cc | 92 -- .../bigtable/table_readmodifywriterow_test.cc | 295 ----- google/cloud/bigtable/table_readrow_test.cc | 132 -- google/cloud/bigtable/table_readrows_test.cc | 157 --- .../bigtable/table_sample_row_keys_test.cc | 179 --- google/cloud/bigtable/table_test.cc | 49 + .../bigtable/test_proxy/cbt_test_proxy.h | 1 + .../testing/embedded_server_test_fixture.cc | 38 +- .../testing/embedded_server_test_fixture.h | 3 +- .../bigtable/testing/inprocess_data_client.cc | 151 --- .../bigtable/testing/inprocess_data_client.h | 155 --- .../cloud/bigtable/testing/mock_data_client.h | 157 --- .../testing/table_integration_test.cc | 22 +- .../bigtable/testing/table_integration_test.h | 11 +- .../bigtable/testing/table_test_fixture.cc | 65 - .../bigtable/testing/table_test_fixture.h | 57 - .../bigtable/tests/admin_integration_test.cc | 7 +- .../data_async_future_integration_test.cc | 36 +- .../bigtable/tests/data_integration_test.cc | 176 +-- .../tests/filters_integration_test.cc | 40 +- .../tests/mutations_integration_test.cc | 22 +- .../table_sample_rows_integration_test.cc | 22 - 66 files changed, 248 insertions(+), 9175 deletions(-) delete mode 100644 google/cloud/bigtable/data_client.cc delete mode 100644 google/cloud/bigtable/data_client.h delete mode 100644 google/cloud/bigtable/data_client_test.cc delete mode 100644 google/cloud/bigtable/internal/legacy_async_bulk_apply.cc delete mode 100644 google/cloud/bigtable/internal/legacy_async_bulk_apply.h delete mode 100644 google/cloud/bigtable/internal/legacy_async_bulk_apply_test.cc delete mode 100644 google/cloud/bigtable/internal/legacy_async_row_reader.cc delete mode 100644 google/cloud/bigtable/internal/legacy_async_row_reader.h delete mode 100644 google/cloud/bigtable/internal/legacy_async_row_reader_test.cc delete mode 100644 google/cloud/bigtable/internal/legacy_async_row_sampler.cc delete mode 100644 google/cloud/bigtable/internal/legacy_async_row_sampler.h delete mode 100644 google/cloud/bigtable/internal/legacy_async_row_sampler_test.cc delete mode 100644 google/cloud/bigtable/internal/legacy_bulk_mutator_test.cc delete mode 100644 google/cloud/bigtable/internal/legacy_row_reader.cc delete mode 100644 google/cloud/bigtable/internal/legacy_row_reader.h delete mode 100644 google/cloud/bigtable/internal/legacy_row_reader_test.cc delete mode 100644 google/cloud/bigtable/internal/logging_data_client.cc delete mode 100644 google/cloud/bigtable/internal/logging_data_client.h delete mode 100644 google/cloud/bigtable/internal/logging_data_client_test.cc delete mode 100644 google/cloud/bigtable/legacy_table_test.cc delete mode 100644 google/cloud/bigtable/table_apply_test.cc delete mode 100644 google/cloud/bigtable/table_bulk_apply_test.cc delete mode 100644 google/cloud/bigtable/table_check_and_mutate_row_test.cc delete mode 100644 google/cloud/bigtable/table_readmodifywriterow_test.cc delete mode 100644 google/cloud/bigtable/table_readrow_test.cc delete mode 100644 google/cloud/bigtable/table_readrows_test.cc delete mode 100644 google/cloud/bigtable/table_sample_row_keys_test.cc delete mode 100644 google/cloud/bigtable/testing/inprocess_data_client.cc delete mode 100644 google/cloud/bigtable/testing/inprocess_data_client.h delete mode 100644 google/cloud/bigtable/testing/mock_data_client.h delete mode 100644 google/cloud/bigtable/testing/table_test_fixture.cc delete mode 100644 google/cloud/bigtable/testing/table_test_fixture.h diff --git a/examples/gcs2cbt.cc b/examples/gcs2cbt.cc index 0b1d5ab889556..4405a2cb8d28b 100644 --- a/examples/gcs2cbt.cc +++ b/examples/gcs2cbt.cc @@ -60,8 +60,9 @@ int main(int argc, char* argv[]) try { // Create a connection to Cloud Bigtable and an object to manipulate the // specific table used in this demo. - cbt::Table table(cbt::MakeDataClient(options.project_id, options.instance_id), - options.table_id); + cbt::Table table(cbt::MakeDataConnection(), + cbt::TableResource(options.project_id, options.instance_id, + options.table_id)); cbt::MutationBatcher batcher(table); // How often do we print a progress marker ('.') in the reader thread. diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index 7b751b0ba1bb5..2c3d3ca3c026f 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -123,8 +123,6 @@ add_library( cluster_list_responses.h column_family.h completion_queue.h - data_client.cc - data_client.h data_connection.cc data_connection.h expr.cc @@ -403,8 +401,6 @@ if (BUILD_TESTING) testing/cleanup_stale_resources.h testing/embedded_server_test_fixture.cc testing/embedded_server_test_fixture.h - testing/inprocess_data_client.cc - testing/inprocess_data_client.h testing/mock_async_failing_rpc_factory.h testing/mock_bigtable_stub.h testing/mock_data_client.h @@ -456,7 +452,6 @@ if (BUILD_TESTING) client_test.cc cluster_config_test.cc column_family_test.cc - data_client_test.cc data_connection_test.cc expr_test.cc filters_test.cc @@ -524,13 +519,10 @@ if (BUILD_TESTING) table_admin_test.cc table_apply_test.cc table_bulk_apply_test.cc - table_check_and_mutate_row_test.cc table_config_test.cc - table_readmodifywriterow_test.cc table_readrow_test.cc table_readrows_test.cc table_resource_test.cc - table_sample_row_keys_test.cc table_test.cc testing/cleanup_stale_resources_test.cc testing/random_names_test.cc diff --git a/google/cloud/bigtable/benchmarks/benchmark.cc b/google/cloud/bigtable/benchmarks/benchmark.cc index 87e9baac9b657..d758bb6b09714 100644 --- a/google/cloud/bigtable/benchmarks/benchmark.cc +++ b/google/cloud/bigtable/benchmarks/benchmark.cc @@ -16,6 +16,7 @@ #include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" #include "google/cloud/bigtable/benchmarks/random_mutation.h" #include "google/cloud/bigtable/resource_names.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/internal/background_threads_impl.h" #include "google/cloud/internal/getenv.h" #include "google/cloud/internal/make_status.h" diff --git a/google/cloud/bigtable/benchmarks/embedded_server_test.cc b/google/cloud/bigtable/benchmarks/embedded_server_test.cc index 9f11bacf0f3a7..79c956d7f5a7f 100644 --- a/google/cloud/bigtable/benchmarks/embedded_server_test.cc +++ b/google/cloud/bigtable/benchmarks/embedded_server_test.cc @@ -16,6 +16,7 @@ #include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" #include "google/cloud/bigtable/resource_names.h" #include "google/cloud/bigtable/table.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/testing_util/status_matchers.h" #include #include diff --git a/google/cloud/bigtable/bigtable_client_testing.bzl b/google/cloud/bigtable/bigtable_client_testing.bzl index 865460e3aead3..2146dbf028f1a 100644 --- a/google/cloud/bigtable/bigtable_client_testing.bzl +++ b/google/cloud/bigtable/bigtable_client_testing.bzl @@ -19,10 +19,8 @@ bigtable_client_testing_hdrs = [ "testing/cleanup_stale_resources.h", "testing/embedded_server_test_fixture.h", - "testing/inprocess_data_client.h", "testing/mock_async_failing_rpc_factory.h", "testing/mock_bigtable_stub.h", - "testing/mock_data_client.h", "testing/mock_mutate_rows_limiter.h", "testing/mock_mutate_rows_reader.h", "testing/mock_partial_result_set_reader.h", @@ -32,14 +30,11 @@ bigtable_client_testing_hdrs = [ "testing/mock_sample_row_keys_reader.h", "testing/random_names.h", "testing/table_integration_test.h", - "testing/table_test_fixture.h", ] bigtable_client_testing_srcs = [ "testing/cleanup_stale_resources.cc", "testing/embedded_server_test_fixture.cc", - "testing/inprocess_data_client.cc", "testing/random_names.cc", "testing/table_integration_test.cc", - "testing/table_test_fixture.cc", ] diff --git a/google/cloud/bigtable/bigtable_client_unit_tests.bzl b/google/cloud/bigtable/bigtable_client_unit_tests.bzl index c5dda043da0a4..10d64955cc798 100644 --- a/google/cloud/bigtable/bigtable_client_unit_tests.bzl +++ b/google/cloud/bigtable/bigtable_client_unit_tests.bzl @@ -28,7 +28,6 @@ bigtable_client_unit_tests = [ "client_test.cc", "cluster_config_test.cc", "column_family_test.cc", - "data_client_test.cc", "data_connection_test.cc", "expr_test.cc", "filters_test.cc", @@ -57,12 +56,6 @@ bigtable_client_unit_tests = [ "internal/default_row_reader_test.cc", "internal/defaults_test.cc", "internal/google_bytes_traits_test.cc", - "internal/legacy_async_bulk_apply_test.cc", - "internal/legacy_async_row_reader_test.cc", - "internal/legacy_async_row_sampler_test.cc", - "internal/legacy_bulk_mutator_test.cc", - "internal/legacy_row_reader_test.cc", - "internal/logging_data_client_test.cc", "internal/logging_result_set_reader_test.cc", "internal/metrics_test.cc", "internal/mutate_rows_limiter_test.cc", @@ -76,7 +69,6 @@ bigtable_client_unit_tests = [ "internal/retry_traits_test.cc", "internal/traced_row_reader_test.cc", "internal/tuple_utils_test.cc", - "legacy_table_test.cc", "metadata_update_policy_test.cc", "mocks/mock_row_reader_test.cc", "mutation_batcher_test.cc", @@ -94,15 +86,8 @@ bigtable_client_unit_tests = [ "rpc_retry_policy_test.cc", "sql_statement_test.cc", "table_admin_test.cc", - "table_apply_test.cc", - "table_bulk_apply_test.cc", - "table_check_and_mutate_row_test.cc", "table_config_test.cc", - "table_readmodifywriterow_test.cc", - "table_readrow_test.cc", - "table_readrows_test.cc", "table_resource_test.cc", - "table_sample_row_keys_test.cc", "table_test.cc", "testing/cleanup_stale_resources_test.cc", "testing/random_names_test.cc", diff --git a/google/cloud/bigtable/data_client.cc b/google/cloud/bigtable/data_client.cc deleted file mode 100644 index 9932d24c541e7..0000000000000 --- a/google/cloud/bigtable/data_client.cc +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/data_client.h" -#include "google/cloud/bigtable/internal/common_client.h" -#include "google/cloud/bigtable/internal/logging_data_client.h" -#include "google/cloud/internal/log_wrapper.h" -#include "google/cloud/log.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -namespace btproto = ::google::bigtable::v2; - -std::unique_ptr< - ::grpc::ClientAsyncReaderInterface> -// NOLINTNEXTLINE(performance-unnecessary-value-param) -DataClient::PrepareAsyncSampleRowKeys(grpc::ClientContext*, - btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - return nullptr; -} - -namespace { - -// TODO(#8800) - remove after `DataClient` deprecation is complete -#include "google/cloud/internal/disable_deprecation_warnings.inc" - -/** - * Implement a simple DataClient. - * - * This implementation does not support multiple threads, or refresh - * authorization tokens. In other words, it is extremely bare bones. - */ -class DefaultDataClient : public DataClient { - public: - DefaultDataClient(std::string project, std::string instance, - Options options = {}) - : project_(std::move(project)), - instance_(std::move(instance)), - authority_(options.get()), - user_project_( - options.has() - ? absl::make_optional(options.get()) - : absl::nullopt), - impl_(std::move(options)) {} - - std::string const& project_id() const override { return project_; }; - std::string const& instance_id() const override { return instance_; }; - - std::shared_ptr Channel() override { return impl_.Channel(); } - void reset() override { impl_.reset(); } - - grpc::Status MutateRow(grpc::ClientContext* context, - btproto::MutateRowRequest const& request, - btproto::MutateRowResponse* response) override { - ApplyOptions(context); - return impl_.Stub()->MutateRow(context, request, response); - } - - std::unique_ptr< - grpc::ClientAsyncResponseReaderInterface> - AsyncMutateRow(grpc::ClientContext* context, - btproto::MutateRowRequest const& request, - grpc::CompletionQueue* cq) override { - ApplyOptions(context); - return impl_.Stub()->AsyncMutateRow(context, request, cq); - } - - grpc::Status CheckAndMutateRow( - grpc::ClientContext* context, - btproto::CheckAndMutateRowRequest const& request, - btproto::CheckAndMutateRowResponse* response) override { - ApplyOptions(context); - return impl_.Stub()->CheckAndMutateRow(context, request, response); - } - - std::unique_ptr> - AsyncCheckAndMutateRow(grpc::ClientContext* context, - btproto::CheckAndMutateRowRequest const& request, - grpc::CompletionQueue* cq) override { - ApplyOptions(context); - return impl_.Stub()->AsyncCheckAndMutateRow(context, request, cq); - } - - grpc::Status ReadModifyWriteRow( - grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - btproto::ReadModifyWriteRowResponse* response) override { - ApplyOptions(context); - return impl_.Stub()->ReadModifyWriteRow(context, request, response); - } - - std::unique_ptr> - AsyncReadModifyWriteRow(grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - grpc::CompletionQueue* cq) override { - ApplyOptions(context); - return impl_.Stub()->AsyncReadModifyWriteRow(context, request, cq); - } - - std::unique_ptr> - ReadRows(grpc::ClientContext* context, - btproto::ReadRowsRequest const& request) override { - ApplyOptions(context); - return impl_.Stub()->ReadRows(context, request); - } - - std::unique_ptr> - AsyncReadRows(grpc::ClientContext* context, - btproto::ReadRowsRequest const& request, - grpc::CompletionQueue* cq, void* tag) override { - ApplyOptions(context); - return impl_.Stub()->AsyncReadRows(context, request, cq, tag); - } - - std::unique_ptr<::grpc::ClientAsyncReaderInterface> - PrepareAsyncReadRows(grpc::ClientContext* context, - btproto::ReadRowsRequest const& request, - grpc::CompletionQueue* cq) override { - ApplyOptions(context); - return impl_.Stub()->PrepareAsyncReadRows(context, request, cq); - } - - std::unique_ptr> - SampleRowKeys(grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request) override { - ApplyOptions(context); - return impl_.Stub()->SampleRowKeys(context, request); - } - - std::unique_ptr< - ::grpc::ClientAsyncReaderInterface> - AsyncSampleRowKeys(grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request, - grpc::CompletionQueue* cq, void* tag) override { - ApplyOptions(context); - return impl_.Stub()->AsyncSampleRowKeys(context, request, cq, tag); - } - - std::unique_ptr< - ::grpc::ClientAsyncReaderInterface> - PrepareAsyncSampleRowKeys(grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request, - grpc::CompletionQueue* cq) override { - ApplyOptions(context); - return impl_.Stub()->PrepareAsyncSampleRowKeys(context, request, cq); - } - - std::unique_ptr> - MutateRows(grpc::ClientContext* context, - btproto::MutateRowsRequest const& request) override { - ApplyOptions(context); - return impl_.Stub()->MutateRows(context, request); - } - - std::unique_ptr< - ::grpc::ClientAsyncReaderInterface> - AsyncMutateRows(grpc::ClientContext* context, - btproto::MutateRowsRequest const& request, - grpc::CompletionQueue* cq, void* tag) override { - ApplyOptions(context); - return impl_.Stub()->AsyncMutateRows(context, request, cq, tag); - } - - std::unique_ptr< - ::grpc::ClientAsyncReaderInterface> - PrepareAsyncMutateRows(grpc::ClientContext* context, - btproto::MutateRowsRequest const& request, - grpc::CompletionQueue* cq) override { - ApplyOptions(context); - return impl_.Stub()->PrepareAsyncMutateRows(context, request, cq); - } - - private: - google::cloud::BackgroundThreadsFactory BackgroundThreadsFactory() override { - return impl_.BackgroundThreadsFactory(); - } - - void ApplyOptions(grpc::ClientContext* context) { - if (!authority_.empty()) context->set_authority(authority_); - if (user_project_) { - context->AddMetadata("x-goog-user-project", *user_project_); - } - } - - std::string project_; - std::string instance_; - std::string authority_; - absl::optional user_project_; - internal::CommonClient impl_; -}; - -// TODO(#8800) - remove after `DataClient` deprecation is complete -#include "google/cloud/internal/diagnostics_pop.inc" - -} // namespace - -std::shared_ptr MakeDataClient(std::string project_id, - std::string instance_id, - Options options) { - options = internal::DefaultDataOptions(std::move(options)); - bool tracing_enabled = google::cloud::internal::Contains( - options.get(), "rpc"); - auto tracing_options = options.get(); - - std::shared_ptr client = std::make_shared( - std::move(project_id), std::move(instance_id), std::move(options)); - if (tracing_enabled) { - GCP_LOG(INFO) << "Enabled logging for gRPC calls"; - client = std::make_shared( - std::move(client), std::move(tracing_options)); - } - return client; -} - -std::shared_ptr CreateDefaultDataClient(std::string project_id, - std::string instance_id, - ClientOptions options) { - return MakeDataClient(std::move(project_id), std::move(instance_id), - internal::MakeOptions(std::move(options))); -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/data_client.h b/google/cloud/bigtable/data_client.h deleted file mode 100644 index eb7f376cc4483..0000000000000 --- a/google/cloud/bigtable/data_client.h +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_DATA_CLIENT_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_DATA_CLIENT_H - -#include "google/cloud/bigtable/client_options.h" -#include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/row.h" -#include "google/cloud/bigtable/version.h" -#include "google/bigtable/v2/bigtable.grpc.pb.h" -#include - -namespace google { -namespace cloud { -// Forward declare some classes so we can be friends. -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -class BulkMutator; -class LegacyAsyncRowReader; -class LegacyRowReader; -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -class Table; -namespace internal { -class AsyncRetryBulkApply; -class LegacyAsyncRowSampler; -class LoggingDataClient; -} // namespace internal - -/** - * Connects to Cloud Bigtable's data manipulation APIs. - * - * This class is used by the Cloud Bigtable wrappers to access Cloud Bigtable. - * Multiple `bigtable::Table` objects may share a connection via a single - * `DataClient` object. The `DataClient` object is configured at construction - * time, this configuration includes the credentials, access endpoints, default - * timeouts, and other gRPC configuration options. This is an interface class - * because it is also used as a dependency injection point in some of the tests. - * - * @par Cost - * Applications should avoid unnecessarily creating new objects of type - * `DataClient`. Creating a new object of this type typically requires - * connecting to the Cloud Bigtable servers, and performing the authentication - * workflows with Google Cloud Platform. These operations can take many - * milliseconds, therefore applications should try to reuse the same - * `DataClient` instances when possible. - * - * @deprecated #google::cloud::bigtable::DataConnection is the preferred way to - * communicate with the Bigtable Data API. To migrate existing code, see - * @ref migrating-from-dataclient "Migrating from DataClient". - */ -class DataClient { - public: - virtual ~DataClient() = default; - - virtual std::string const& project_id() const = 0; - virtual std::string const& instance_id() const = 0; - - /** - * Return a new channel to handle admin operations. - * - * Intended to access rarely used services in the same endpoints as the - * Bigtable admin interfaces, for example, the google.longrunning.Operations. - * - * @deprecated This member function is scheduled for deletion and `DataClient` - * will be marked as `final`. Do not extend this class. Application - * developers who need to configure the gRPC Channel can pass any of the - * following options into `MakeDataClient(...)`: - * * `google::cloud::GrpcChannelArgumentsOption` - * * `google::cloud::GrpcChannelArgumentsNativeOption` - */ - GOOGLE_CLOUD_CPP_BIGTABLE_DATA_CLIENT_DEPRECATED("Channel()") - virtual std::shared_ptr Channel() = 0; - - /** - * Reset and create new Channels. - * - * @deprecated This member function is scheduled for deletion and `DataClient` - * will be marked as `final`. Do not extend this class. The client library - * will handle all interactions with the gRPC channels. - */ - GOOGLE_CLOUD_CPP_BIGTABLE_DATA_CLIENT_DEPRECATED("reset()") - virtual void reset() = 0; - - /** - * The thread factory this client was created with. - * - * @deprecated This member function is scheduled for deletion and `DataClient` - * will be marked as `final`. Do not extend this class. Application - * developers who need to configure the background threads can pass any - * of the following options into `MakeDataClient(...)`: - * * `google::cloud::GrpcBackgroundThreadPoolSizeOption` - * * `google::cloud::GrpcCompletionQueueOption` - * * `google::cloud::GrpcBackgroundThreadFactoryOption` - */ - virtual google::cloud::BackgroundThreadsFactory - BackgroundThreadsFactory() = 0; - - // The member functions of this class are not intended for general use by - // application developers (they are simply a dependency injection point). Make - // them protected, so the mock classes can override them, and then make the - // classes that do use them friends. - protected: - friend class Table; - friend class internal::AsyncRetryBulkApply; - friend class internal::LegacyAsyncRowSampler; - friend class bigtable_internal::BulkMutator; - friend class bigtable_internal::LegacyRowReader; - friend class bigtable_internal::LegacyAsyncRowReader; - friend class internal::LoggingDataClient; - - ///@{ - /// @name the `google.bigtable.v2.Bigtable` wrappers. - virtual grpc::Status MutateRow( - grpc::ClientContext* context, - google::bigtable::v2::MutateRowRequest const& request, - google::bigtable::v2::MutateRowResponse* response) = 0; - virtual std::unique_ptr> - AsyncMutateRow(grpc::ClientContext* context, - google::bigtable::v2::MutateRowRequest const& request, - grpc::CompletionQueue* cq) = 0; - virtual grpc::Status CheckAndMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - google::bigtable::v2::CheckAndMutateRowResponse* response) = 0; - virtual std::unique_ptr> - AsyncCheckAndMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - grpc::CompletionQueue* cq) = 0; - virtual grpc::Status ReadModifyWriteRow( - grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - google::bigtable::v2::ReadModifyWriteRowResponse* response) = 0; - virtual std::unique_ptr> - AsyncReadModifyWriteRow( - grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - grpc::CompletionQueue* cq) = 0; - virtual std::unique_ptr< - grpc::ClientReaderInterface> - ReadRows(grpc::ClientContext* context, - google::bigtable::v2::ReadRowsRequest const& request) = 0; - virtual std::unique_ptr< - grpc::ClientAsyncReaderInterface> - AsyncReadRows(grpc::ClientContext* context, - google::bigtable::v2::ReadRowsRequest const& request, - grpc::CompletionQueue* cq, void* tag) = 0; - virtual std::unique_ptr<::grpc::ClientAsyncReaderInterface< - google::bigtable::v2::ReadRowsResponse>> - PrepareAsyncReadRows(::grpc::ClientContext* context, - google::bigtable::v2::ReadRowsRequest const& request, - grpc::CompletionQueue* cq) = 0; - virtual std::unique_ptr< - grpc::ClientReaderInterface> - SampleRowKeys(grpc::ClientContext* context, - google::bigtable::v2::SampleRowKeysRequest const& request) = 0; - virtual std::unique_ptr<::grpc::ClientAsyncReaderInterface< - google::bigtable::v2::SampleRowKeysResponse>> - AsyncSampleRowKeys(grpc::ClientContext* context, - google::bigtable::v2::SampleRowKeysRequest const& request, - grpc::CompletionQueue* cq, void* tag) = 0; - virtual std::unique_ptr<::grpc::ClientAsyncReaderInterface< - google::bigtable::v2::SampleRowKeysResponse>> - PrepareAsyncSampleRowKeys( - grpc::ClientContext* context, - google::bigtable::v2::SampleRowKeysRequest const& request, - grpc::CompletionQueue* cq); - virtual std::unique_ptr< - grpc::ClientReaderInterface> - MutateRows(grpc::ClientContext* context, - google::bigtable::v2::MutateRowsRequest const& request) = 0; - virtual std::unique_ptr<::grpc::ClientAsyncReaderInterface< - google::bigtable::v2::MutateRowsResponse>> - AsyncMutateRows(::grpc::ClientContext* context, - google::bigtable::v2::MutateRowsRequest const& request, - grpc::CompletionQueue* cq, void* tag) = 0; - virtual std::unique_ptr<::grpc::ClientAsyncReaderInterface< - google::bigtable::v2::MutateRowsResponse>> - PrepareAsyncMutateRows(grpc::ClientContext* context, - google::bigtable::v2::MutateRowsRequest const& request, - grpc::CompletionQueue* cq) = 0; - ///@} -}; - -/// Create a new data client configured via @p options. -std::shared_ptr MakeDataClient(std::string project_id, - std::string instance_id, - Options options = {}); - -/** - * Create a new data client configured via @p options. - * - * @deprecated use the `MakeDataClient` method which accepts - * `google::cloud::Options` instead. - */ -GOOGLE_CLOUD_CPP_DEPRECATED("use `MakeDataClient` instead") -std::shared_ptr CreateDefaultDataClient(std::string project_id, - std::string instance_id, - ClientOptions options); - -/** - * Return the fully qualified instance name for the @p client. - * - * Compute the full path of the instance associated with the client, i.e., - * `projects/instances/project_id()>/instances/instance_id()>` - */ -inline std::string InstanceName(std::shared_ptr const& client) { - return "projects/" + client->project_id() + "/instances/" + - client->instance_id(); -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_DATA_CLIENT_H diff --git a/google/cloud/bigtable/data_client_test.cc b/google/cloud/bigtable/data_client_test.cc deleted file mode 100644 index 2fcc28caad549..0000000000000 --- a/google/cloud/bigtable/data_client_test.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/data_client.h" -#include "google/cloud/bigtable/internal/logging_data_client.h" -#include "google/cloud/testing_util/scoped_environment.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -// TODO(#8800) - remove after `DataClient` deprecation is complete -#include "google/cloud/internal/disable_deprecation_warnings.inc" - -TEST(DataClientTest, Default) { - auto data_client = - CreateDefaultDataClient("test-project", "test-instance", - ClientOptions().set_connection_pool_size(1)); - ASSERT_TRUE(data_client); - EXPECT_EQ("test-project", data_client->project_id()); - EXPECT_EQ("test-instance", data_client->instance_id()); - - auto channel0 = data_client->Channel(); - EXPECT_TRUE(channel0); - - auto channel1 = data_client->Channel(); - EXPECT_EQ(channel0.get(), channel1.get()); - - data_client->reset(); - channel1 = data_client->Channel(); - EXPECT_TRUE(channel1); - EXPECT_NE(channel0.get(), channel1.get()); -} - -TEST(DataClientTest, MakeClient) { - auto data_client = MakeDataClient("test-project", "test-instance", - Options{}.set(1)); - ASSERT_TRUE(data_client); - EXPECT_EQ("test-project", data_client->project_id()); - EXPECT_EQ("test-instance", data_client->instance_id()); - - auto channel0 = data_client->Channel(); - EXPECT_TRUE(channel0); - - auto channel1 = data_client->Channel(); - EXPECT_EQ(channel0.get(), channel1.get()); - - data_client->reset(); - channel1 = data_client->Channel(); - EXPECT_TRUE(channel1); - EXPECT_NE(channel0.get(), channel1.get()); -} - -// TODO(#8800) - remove after `DataClient` deprecation is complete -#include "google/cloud/internal/diagnostics_pop.inc" - -TEST(DataClientTest, Logging) { - testing_util::ScopedEnvironment env("GOOGLE_CLOUD_CPP_ENABLE_TRACING", "rpc"); - - auto data_client = MakeDataClient("test-project", "test-instance"); - ASSERT_TRUE(data_client); - ASSERT_TRUE( - dynamic_cast(data_client.get())) - << "Should create LoggingDataClient"; -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/examples/bigtable_instance_admin_snippets.cc b/google/cloud/bigtable/examples/bigtable_instance_admin_snippets.cc index 0f7984a08ad8b..3ae4f9e1c1c2c 100644 --- a/google/cloud/bigtable/examples/bigtable_instance_admin_snippets.cc +++ b/google/cloud/bigtable/examples/bigtable_instance_admin_snippets.cc @@ -23,6 +23,7 @@ #include "google/cloud/location.h" #include "google/cloud/log.h" #include "google/cloud/project.h" +#include "absl/strings/match.h" #include namespace { diff --git a/google/cloud/bigtable/examples/data_snippets.cc b/google/cloud/bigtable/examples/data_snippets.cc index 1b849dbd47a87..f261a2acdc796 100644 --- a/google/cloud/bigtable/examples/data_snippets.cc +++ b/google/cloud/bigtable/examples/data_snippets.cc @@ -17,6 +17,7 @@ #include "google/cloud/bigtable/resource_names.h" #include "google/cloud/bigtable/testing/cleanup_stale_resources.h" #include "google/cloud/bigtable/testing/random_names.h" +#include "google/cloud/grpc_options.h" //! [bigtable includes] #include "google/cloud/bigtable/client.h" #include "google/cloud/bigtable/table.h" diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index c5d4f47beff0b..c9adc3f84ee1d 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -57,7 +57,6 @@ google_cloud_cpp_bigtable_hdrs = [ "cluster_list_responses.h", "column_family.h", "completion_queue.h", - "data_client.h", "data_connection.h", "expr.h", "filters.h", @@ -96,11 +95,6 @@ google_cloud_cpp_bigtable_hdrs = [ "internal/default_row_reader.h", "internal/defaults.h", "internal/google_bytes_traits.h", - "internal/legacy_async_bulk_apply.h", - "internal/legacy_async_row_reader.h", - "internal/legacy_async_row_sampler.h", - "internal/legacy_row_reader.h", - "internal/logging_data_client.h", "internal/logging_result_set_reader.h", "internal/metrics.h", "internal/mutate_rows_limiter.h", @@ -185,7 +179,6 @@ google_cloud_cpp_bigtable_srcs = [ "client.cc", "client_options.cc", "cluster_config.cc", - "data_client.cc", "data_connection.cc", "expr.cc", "iam_binding.cc", @@ -218,11 +211,6 @@ google_cloud_cpp_bigtable_srcs = [ "internal/default_row_reader.cc", "internal/defaults.cc", "internal/google_bytes_traits.cc", - "internal/legacy_async_bulk_apply.cc", - "internal/legacy_async_row_reader.cc", - "internal/legacy_async_row_sampler.cc", - "internal/legacy_row_reader.cc", - "internal/logging_data_client.cc", "internal/logging_result_set_reader.cc", "internal/metrics.cc", "internal/mutate_rows_limiter.cc", diff --git a/google/cloud/bigtable/internal/async_bulk_apply.cc b/google/cloud/bigtable/internal/async_bulk_apply.cc index e19c3a0ffddfb..1039aa862b30b 100644 --- a/google/cloud/bigtable/internal/async_bulk_apply.cc +++ b/google/cloud/bigtable/internal/async_bulk_apply.cc @@ -14,6 +14,7 @@ #include "google/cloud/bigtable/internal/async_bulk_apply.h" #include "google/cloud/bigtable/internal/async_streaming_read.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/internal/grpc_opentelemetry.h" #include "google/cloud/internal/retry_loop_helpers.h" diff --git a/google/cloud/bigtable/internal/async_bulk_apply_test.cc b/google/cloud/bigtable/internal/async_bulk_apply_test.cc index 930eed5281915..f860d202df592 100644 --- a/google/cloud/bigtable/internal/async_bulk_apply_test.cc +++ b/google/cloud/bigtable/internal/async_bulk_apply_test.cc @@ -16,6 +16,7 @@ #include "google/cloud/bigtable/internal/operation_context.h" #include "google/cloud/bigtable/testing/mock_bigtable_stub.h" #include "google/cloud/bigtable/testing/mock_mutate_rows_limiter.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/internal/async_streaming_read_rpc_impl.h" #include "google/cloud/internal/background_threads_impl.h" #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS diff --git a/google/cloud/bigtable/internal/bulk_mutator.cc b/google/cloud/bigtable/internal/bulk_mutator.cc index 7203d23fbd14d..fad9d4342563a 100644 --- a/google/cloud/bigtable/internal/bulk_mutator.cc +++ b/google/cloud/bigtable/internal/bulk_mutator.cc @@ -15,6 +15,7 @@ #include "google/cloud/bigtable/internal/bulk_mutator.h" #include "google/cloud/bigtable/rpc_retry_policy.h" #include "google/cloud/bigtable/table.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/internal/make_status.h" #include "google/cloud/log.h" #include @@ -195,22 +196,6 @@ BulkMutator::BulkMutator(std::string const& app_profile_id, : state_(app_profile_id, table_name, idempotent_policy, std::move(mut)), operation_context_(std::move(operation_context)) {} -grpc::Status BulkMutator::MakeOneRequest(bigtable::DataClient& client, - grpc::ClientContext& client_context) { - // Send the request to the server. - auto const& mutations = state_.BeforeStart(); - auto stream = client.MutateRows(&client_context, mutations); - // Read the stream of responses. - btproto::MutateRowsResponse response; - while (stream->Read(&response)) { - state_.OnRead(std::move(response)); - } - // Handle any errors in the stream. - auto grpc_status = stream->Finish(); - state_.OnFinish(MakeStatusFromRpcError(grpc_status)); - return grpc_status; -} - Status BulkMutator::MakeOneRequest(BigtableStub& stub, MutateRowsLimiter& limiter, Options const& options) { diff --git a/google/cloud/bigtable/internal/bulk_mutator.h b/google/cloud/bigtable/internal/bulk_mutator.h index bd543dc6f0ccc..922c9caeab426 100644 --- a/google/cloud/bigtable/internal/bulk_mutator.h +++ b/google/cloud/bigtable/internal/bulk_mutator.h @@ -16,12 +16,12 @@ #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_BULK_MUTATOR_H #include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/data_client.h" #include "google/cloud/bigtable/idempotent_mutation_policy.h" #include "google/cloud/bigtable/internal/bigtable_stub.h" #include "google/cloud/bigtable/internal/mutate_rows_limiter.h" #include "google/cloud/bigtable/internal/operation_context.h" #include "google/cloud/bigtable/version.h" +#include "google/cloud/idempotency.h" #include "google/cloud/internal/invoke_result.h" #include "google/cloud/status.h" #include @@ -89,7 +89,7 @@ class BulkMutatorState { * request provided by the application. */ int original_index; - Idempotency idempotency; + google::cloud::Idempotency idempotency; /// Set to `false` if the result is unknown. bool has_mutation_result; /** @@ -123,10 +123,6 @@ class BulkMutator { /// Return true if there are pending mutations in the mutator bool HasPendingMutations() const { return state_.HasPendingMutations(); } - /// Synchronously send one batch request to the given stub. - grpc::Status MakeOneRequest(bigtable::DataClient& client, - grpc::ClientContext& client_context); - /// Synchronously send one batch request to the given stub. Status MakeOneRequest(BigtableStub& stub, MutateRowsLimiter& limiter, Options const& options); diff --git a/google/cloud/bigtable/internal/bulk_mutator_test.cc b/google/cloud/bigtable/internal/bulk_mutator_test.cc index 7724da5f21501..e7bf9f7433e9d 100644 --- a/google/cloud/bigtable/internal/bulk_mutator_test.cc +++ b/google/cloud/bigtable/internal/bulk_mutator_test.cc @@ -14,6 +14,7 @@ #include "google/cloud/bigtable/internal/bulk_mutator.h" #include "google/cloud/bigtable/internal/operation_context.h" +#include "google/cloud/grpc_options.h" #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS #include "google/cloud/bigtable/internal/metrics.h" #include "google/cloud/testing_util/fake_clock.h" diff --git a/google/cloud/bigtable/internal/default_row_reader.cc b/google/cloud/bigtable/internal/default_row_reader.cc index 844bdace38dd2..7cb45dad72e67 100644 --- a/google/cloud/bigtable/internal/default_row_reader.cc +++ b/google/cloud/bigtable/internal/default_row_reader.cc @@ -15,6 +15,7 @@ #include "google/cloud/bigtable/internal/default_row_reader.h" #include "google/cloud/bigtable/table.h" #include "google/cloud/grpc_error_delegate.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/internal/make_status.h" #include "google/cloud/internal/retry_loop_helpers.h" diff --git a/google/cloud/bigtable/internal/default_row_reader_test.cc b/google/cloud/bigtable/internal/default_row_reader_test.cc index bcbd97dfc077e..9c282ad0660cf 100644 --- a/google/cloud/bigtable/internal/default_row_reader_test.cc +++ b/google/cloud/bigtable/internal/default_row_reader_test.cc @@ -16,6 +16,7 @@ #include "google/cloud/bigtable/row_reader.h" #include "google/cloud/bigtable/testing/mock_bigtable_stub.h" #include "google/cloud/bigtable/testing/mock_policies.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/internal/make_status.h" #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS #include "google/cloud/bigtable/internal/metrics.h" diff --git a/google/cloud/bigtable/internal/legacy_async_bulk_apply.cc b/google/cloud/bigtable/internal/legacy_async_bulk_apply.cc deleted file mode 100644 index b4d2efa5da9a9..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_bulk_apply.cc +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/legacy_async_bulk_apply.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace internal { - -future> AsyncRetryBulkApply::Create( - CompletionQueue cq, std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - IdempotentMutationPolicy& idempotent_policy, - MetadataUpdatePolicy metadata_update_policy, - std::shared_ptr client, - std::string const& app_profile_id, std::string const& table_name, - BulkMutation mut) { - if (mut.empty()) return make_ready_future(std::vector{}); - - std::shared_ptr bulk_apply(new AsyncRetryBulkApply( - std::move(rpc_retry_policy), std::move(rpc_backoff_policy), - idempotent_policy, std::move(metadata_update_policy), std::move(client), - app_profile_id, table_name, std::move(mut))); - bulk_apply->StartIteration(std::move(cq)); - return bulk_apply->promise_.get_future(); -} - -AsyncRetryBulkApply::AsyncRetryBulkApply( - std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - IdempotentMutationPolicy& idempotent_policy, - MetadataUpdatePolicy metadata_update_policy, - std::shared_ptr client, - std::string const& app_profile_id, std::string const& table_name, - BulkMutation mut) - : rpc_retry_policy_(std::move(rpc_retry_policy)), - rpc_backoff_policy_(std::move(rpc_backoff_policy)), - metadata_update_policy_(std::move(metadata_update_policy)), - client_(std::move(client)), - state_(app_profile_id, table_name, idempotent_policy, std::move(mut)) {} - -void AsyncRetryBulkApply::StartIteration(CompletionQueue cq) { - auto context = std::make_unique(); - rpc_retry_policy_->Setup(*context); - rpc_backoff_policy_->Setup(*context); - metadata_update_policy_.Setup(*context); - auto& client = client_; - auto self = shared_from_this(); - cq.MakeStreamingReadRpc( - [client](grpc::ClientContext* context, - google::bigtable::v2::MutateRowsRequest const& request, - grpc::CompletionQueue* cq) { - return client->PrepareAsyncMutateRows(context, request, cq); - }, - state_.BeforeStart(), std::move(context), - [self, cq](google::bigtable::v2::MutateRowsResponse r) { - self->OnRead(std::move(r)); - return make_ready_future(true); - }, - [self, cq](Status const& s) { self->OnFinish(cq, s); }); -} - -void AsyncRetryBulkApply::OnRead( - google::bigtable::v2::MutateRowsResponse response) { - state_.OnRead(std::move(response)); -} - -void AsyncRetryBulkApply::OnFinish(CompletionQueue cq, Status const& status) { - state_.OnFinish(status); - if (!state_.HasPendingMutations() || !rpc_retry_policy_->OnFailure(status)) { - SetPromise(); - return; - } - - auto self = this->shared_from_this(); - cq.MakeRelativeTimer(rpc_backoff_policy_->OnCompletion(status)) - .then([self, cq](auto result) { - if (result.get()) { - self->StartIteration(std::move(cq)); - } else { - self->SetPromise(); - } - }); -} - -void AsyncRetryBulkApply::SetPromise() { - promise_.set_value(std::move(state_).OnRetryDone()); -} - -} // namespace internal -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_async_bulk_apply.h b/google/cloud/bigtable/internal/legacy_async_bulk_apply.h deleted file mode 100644 index f53802f5c50f1..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_bulk_apply.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_BULK_APPLY_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_BULK_APPLY_H - -#include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/data_client.h" -#include "google/cloud/bigtable/idempotent_mutation_policy.h" -#include "google/cloud/bigtable/internal/async_retry_op.h" -#include "google/cloud/bigtable/internal/bulk_mutator.h" -#include "google/cloud/bigtable/version.h" -#include "google/cloud/internal/invoke_result.h" -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace internal { -/** - * Implement the retry loop for AsyncBulkApply. - * - * The retry loop for AsyncBulkApply() is fairly different from all the other - * retry loops: only those mutations that are idempotent and had a transient - * failure can be retried, and the result for each mutation arrives in a stream. - * This class implements that retry loop. - */ -class AsyncRetryBulkApply - : public std::enable_shared_from_this { - public: - static future> Create( - CompletionQueue cq, std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - IdempotentMutationPolicy& idempotent_policy, - MetadataUpdatePolicy metadata_update_policy, - std::shared_ptr client, - std::string const& app_profile_id, std::string const& table_name, - BulkMutation mut); - - private: - AsyncRetryBulkApply(std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - IdempotentMutationPolicy& idempotent_policy, - MetadataUpdatePolicy metadata_update_policy, - std::shared_ptr client, - std::string const& app_profile_id, - std::string const& table_name, BulkMutation mut); - - void StartIteration(CompletionQueue cq); - void OnRead(google::bigtable::v2::MutateRowsResponse response); - void OnFinish(CompletionQueue cq, google::cloud::Status const& status); - void SetPromise(); - - std::unique_ptr rpc_retry_policy_; - std::unique_ptr rpc_backoff_policy_; - MetadataUpdatePolicy metadata_update_policy_; - std::shared_ptr client_; - bigtable_internal::BulkMutatorState state_; - promise> promise_; -}; - -} // namespace internal -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_BULK_APPLY_H diff --git a/google/cloud/bigtable/internal/legacy_async_bulk_apply_test.cc b/google/cloud/bigtable/internal/legacy_async_bulk_apply_test.cc deleted file mode 100644 index 9c2e21f730758..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_bulk_apply_test.cc +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/legacy_async_bulk_apply.h" -#include "google/cloud/bigtable/testing/mock_mutate_rows_reader.h" -#include "google/cloud/bigtable/testing/mock_policies.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/future.h" -#include "google/cloud/internal/api_client_header.h" -#include "google/cloud/testing_util/chrono_literals.h" -#include "google/cloud/testing_util/fake_completion_queue_impl.h" -#include "google/cloud/testing_util/status_matchers.h" -#include "google/cloud/testing_util/validate_metadata.h" -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; - -using ::google::cloud::bigtable::testing::MockBackoffPolicy; -using ::google::cloud::bigtable::testing::MockClientAsyncReaderInterface; -using ::google::cloud::testing_util::chrono_literals::operator""_ms; -using ::google::cloud::testing_util::FakeCompletionQueueImpl; -using ::google::cloud::testing_util::StatusIs; - -class AsyncBulkApplyTest : public bigtable::testing::TableTestFixture { - protected: - AsyncBulkApplyTest() - : TableTestFixture( - CompletionQueue(std::make_shared())), - rpc_retry_policy_( - bigtable::DefaultRPCRetryPolicy(internal::kBigtableLimits)), - rpc_backoff_policy_(bigtable::DefaultRPCBackoffPolicy( - internal::kBigtableTableAdminLimits)), - idempotent_mutation_policy_( - bigtable::DefaultIdempotentMutationPolicy()), - metadata_update_policy_("my_table", MetadataParamTypes::NAME) {} - - void SimulateIteration() { - cq_impl_->SimulateCompletion(true); - // state == PROCESSING - cq_impl_->SimulateCompletion(true); - // state == PROCESSING, 1 read - cq_impl_->SimulateCompletion(false); - // state == FINISHING - cq_impl_->SimulateCompletion(true); - } - - std::shared_ptr rpc_retry_policy_; - std::shared_ptr rpc_backoff_policy_; - std::shared_ptr idempotent_mutation_policy_; - MetadataUpdatePolicy metadata_update_policy_; -}; - -std::vector StatusOnly(std::vector const& failures) { - std::vector v; - std::transform(failures.begin(), failures.end(), std::back_inserter(v), - [](FailedMutation const& f) { return f.status(); }); - return v; -} - -TEST_F(AsyncBulkApplyTest, NoMutations) { - bigtable::BulkMutation mut; - - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, rpc_retry_policy_->clone(), rpc_backoff_policy_->clone(), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - ASSERT_EQ(0U, bulk_apply_future.get().size()); -} - -TEST_F(AsyncBulkApplyTest, Success) { - bigtable::BulkMutation mut{ - bigtable::SingleRowMutation("foo2", - {bigtable::SetCell("f", "c", 0_ms, "v2")}), - bigtable::SingleRowMutation("foo3", - {bigtable::SetCell("f", "c", 0_ms, "v3")}), - }; - - auto* reader = - new MockClientAsyncReaderInterface; - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::MutateRowsResponse* r, void*) { - auto& r1 = *r->add_entries(); - r1.set_index(0); - r1.mutable_status()->set_code(grpc::StatusCode::OK); - - auto& r2 = *r->add_entries(); - r2.set_index(1); - r2.mutable_status()->set_code(grpc::StatusCode::OK); - }) - .WillOnce([](btproto::MutateRowsResponse*, void*) {}); - - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - EXPECT_CALL(*reader, StartCall).Times(1); - - EXPECT_CALL(*client_, PrepareAsyncMutateRows) - .WillOnce([reader](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - return std::unique_ptr< - MockClientAsyncReaderInterface>( - reader); - }) - .RetiresOnSaturation(); - - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, rpc_retry_policy_->clone(), rpc_backoff_policy_->clone(), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - bulk_apply_future.then( - [](future> f) { f.get(); }); - - ASSERT_EQ(1U, cq_impl_->size()); - - SimulateIteration(); - - ASSERT_EQ(0U, cq_impl_->size()); -} - -TEST_F(AsyncBulkApplyTest, PartialSuccessRetry) { - bigtable::BulkMutation mut{ - bigtable::SingleRowMutation("foo2", - {bigtable::SetCell("f", "c", 0_ms, "v2")}), - bigtable::SingleRowMutation("foo3", - {bigtable::SetCell("f", "c", 0_ms, "v3")}), - }; - - auto* reader0 = - new MockClientAsyncReaderInterface; - auto* reader1 = - new MockClientAsyncReaderInterface; - - EXPECT_CALL(*reader0, Read) - .WillOnce([](btproto::MutateRowsResponse* r, void*) { - auto& r1 = *r->add_entries(); - r1.set_index(0); - r1.mutable_status()->set_code(grpc::StatusCode::OK); - }) - .WillOnce([](btproto::MutateRowsResponse*, void*) {}); - - EXPECT_CALL(*reader1, Read) - .WillOnce([](btproto::MutateRowsResponse* r, void*) { - auto& r1 = *r->add_entries(); - r1.set_index(0); - r1.mutable_status()->set_code(grpc::StatusCode::OK); - }) - .WillOnce([](btproto::MutateRowsResponse*, void*) {}); - - EXPECT_CALL(*reader0, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - EXPECT_CALL(*reader1, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - EXPECT_CALL(*reader0, StartCall).Times(1); - EXPECT_CALL(*reader1, StartCall).Times(1); - - EXPECT_CALL(*client_, PrepareAsyncMutateRows) - .WillOnce([reader0](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - return std::unique_ptr< - MockClientAsyncReaderInterface>( - reader0); - }) - .WillOnce([reader1](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - return std::unique_ptr< - MockClientAsyncReaderInterface>( - reader1); - }); - - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, rpc_retry_policy_->clone(), rpc_backoff_policy_->clone(), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - SimulateIteration(); - // simulate the backoff timer - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(1U, cq_impl_->size()); - - SimulateIteration(); - - bulk_apply_future.get(); - - ASSERT_EQ(0U, cq_impl_->size()); - EXPECT_TRUE(cq_impl_->empty()); -} - -TEST_F(AsyncBulkApplyTest, DefaultFailureRetry) { - bigtable::BulkMutation mut{ - bigtable::SingleRowMutation("foo2", - {bigtable::SetCell("f", "c", 0_ms, "v2")}), - bigtable::SingleRowMutation("foo3", - {bigtable::SetCell("f", "c", 0_ms, "v3")}), - }; - - auto* reader0 = - new MockClientAsyncReaderInterface; - auto* reader1 = - new MockClientAsyncReaderInterface; - - EXPECT_CALL(*reader0, Read) - .WillOnce([](btproto::MutateRowsResponse* r, void*) { - auto& r1 = *r->add_entries(); - r1.set_index(0); - r1.mutable_status()->set_code(grpc::StatusCode::OK); - }) - .WillOnce([](btproto::MutateRowsResponse*, void*) {}); - - EXPECT_CALL(*reader1, Read) - .WillOnce([](btproto::MutateRowsResponse* r, void*) { - auto& r1 = *r->add_entries(); - r1.set_index(0); - r1.mutable_status()->set_code(grpc::StatusCode::OK); - - auto& r2 = *r->add_entries(); - r2.set_index(1); - r2.mutable_status()->set_code(grpc::StatusCode::OK); - }) - .WillOnce([](btproto::MutateRowsResponse*, void*) {}); - - EXPECT_CALL(*reader0, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::UNAVAILABLE, ""); - }); - - EXPECT_CALL(*reader1, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - EXPECT_CALL(*reader0, StartCall).Times(1); - EXPECT_CALL(*reader1, StartCall).Times(1); - - EXPECT_CALL(*client_, PrepareAsyncMutateRows) - .WillOnce([reader0](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - return std::unique_ptr< - MockClientAsyncReaderInterface>( - reader0); - }) - .WillOnce([reader1](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - return std::unique_ptr< - MockClientAsyncReaderInterface>( - reader1); - }); - - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, rpc_retry_policy_->clone(), rpc_backoff_policy_->clone(), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - SimulateIteration(); - // simulate the backoff timer - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(1U, cq_impl_->size()); - - SimulateIteration(); - - bulk_apply_future.get(); - - ASSERT_EQ(0U, cq_impl_->size()); - - EXPECT_TRUE(cq_impl_->empty()); -} - -TEST_F(AsyncBulkApplyTest, TooManyFailures) { - bigtable::BulkMutation mut{ - bigtable::SingleRowMutation("foo2", - {bigtable::SetCell("f", "c", 0_ms, "v2")}), - bigtable::SingleRowMutation("foo3", - {bigtable::SetCell("f", "c", 0_ms, "v3")}), - }; - - // We give up on the 3rd error. - auto constexpr kErrorCount = 2; - - EXPECT_CALL(*client_, PrepareAsyncMutateRows) - .Times(kErrorCount + 1) - .WillRepeatedly([](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, Read).Times(2); - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::UNAVAILABLE, "try again"); - }); - EXPECT_CALL(*reader, StartCall); - return reader; - }); - - auto limited_retry_policy = LimitedErrorCountRetryPolicy(kErrorCount); - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, limited_retry_policy.clone(), rpc_backoff_policy_->clone(), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - for (int retry = 0; retry < kErrorCount; ++retry) { - SimulateIteration(); - // simulate the backoff timer - cq_impl_->SimulateCompletion(true); - ASSERT_EQ(1U, cq_impl_->size()); - } - - SimulateIteration(); - - auto failures = StatusOnly(bulk_apply_future.get()); - EXPECT_THAT(failures, ElementsAre(StatusIs(StatusCode::kUnavailable), - StatusIs(StatusCode::kUnavailable))); - - ASSERT_EQ(0U, cq_impl_->size()); - EXPECT_TRUE(cq_impl_->empty()); -} - -TEST_F(AsyncBulkApplyTest, RetryPolicyUsedForOkStreamsWithFailedMutations) { - bigtable::BulkMutation mut{bigtable::SingleRowMutation( - "row", {bigtable::SetCell("f", "c", 0_ms, "v2")})}; - - // We give up on the 3rd error. - auto constexpr kErrorCount = 2; - - EXPECT_CALL(*client_, PrepareAsyncMutateRows) - .Times(kErrorCount + 1) - .WillRepeatedly([](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::MutateRowsResponse* r, void*) { - auto& r1 = *r->add_entries(); - r1.set_index(0); - r1.mutable_status()->set_code(grpc::StatusCode::UNAVAILABLE); - }) - .WillOnce([](btproto::MutateRowsResponse*, void*) {}); - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - EXPECT_CALL(*reader, StartCall); - return reader; - }); - - auto limited_retry_policy = LimitedErrorCountRetryPolicy(kErrorCount); - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, limited_retry_policy.clone(), rpc_backoff_policy_->clone(), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - for (int retry = 0; retry != kErrorCount; ++retry) { - SimulateIteration(); - // simulate the backoff timer - cq_impl_->SimulateCompletion(true); - ASSERT_EQ(1U, cq_impl_->size()); - } - - SimulateIteration(); - - auto failures = StatusOnly(bulk_apply_future.get()); - EXPECT_THAT(failures, ElementsAre(StatusIs(StatusCode::kUnavailable))); - - ASSERT_EQ(0U, cq_impl_->size()); - EXPECT_TRUE(cq_impl_->empty()); -} - -TEST_F(AsyncBulkApplyTest, UsesBackoffPolicy) { - bigtable::BulkMutation mut{ - bigtable::SingleRowMutation("foo2", - {bigtable::SetCell("f", "c", 0_ms, "v2")}), - bigtable::SingleRowMutation("foo3", - {bigtable::SetCell("f", "c", 0_ms, "v3")}), - }; - - auto grpc_error = grpc::Status(grpc::StatusCode::UNAVAILABLE, "try again"); - auto error = MakeStatusFromRpcError(grpc_error); - - std::unique_ptr mock(new MockBackoffPolicy); - EXPECT_CALL(*mock, Setup).Times(2); - EXPECT_CALL(*mock, OnCompletion(error)).WillOnce([](Status const&) { - return 10_ms; - }); - - EXPECT_CALL(*client_, PrepareAsyncMutateRows) - .WillOnce([grpc_error](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, Read).Times(2); - EXPECT_CALL(*reader, Finish) - .WillOnce([grpc_error](grpc::Status* status, void*) { - *status = grpc_error; - }); - EXPECT_CALL(*reader, StartCall); - return reader; - }) - .WillOnce([](grpc::ClientContext*, btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::MutateRowsResponse* r, void*) { - auto& r1 = *r->add_entries(); - r1.set_index(0); - r1.mutable_status()->set_code(grpc::StatusCode::OK); - - auto& r2 = *r->add_entries(); - r2.set_index(1); - r2.mutable_status()->set_code(grpc::StatusCode::OK); - }) - .WillOnce([](btproto::MutateRowsResponse*, void*) {}); - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - EXPECT_CALL(*reader, StartCall); - return reader; - }); - - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, rpc_retry_policy_->clone(), std::move(mock), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - SimulateIteration(); - // simulate the backoff timer - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(1U, cq_impl_->size()); - - SimulateIteration(); - - ASSERT_EQ(0U, cq_impl_->size()); -} - -TEST_F(AsyncBulkApplyTest, CancelDuringBackoff) { - bigtable::BulkMutation mut{ - bigtable::SingleRowMutation("foo2", - {bigtable::SetCell("f", "c", 0_ms, "v2")}), - bigtable::SingleRowMutation("foo3", - {bigtable::SetCell("f", "c", 0_ms, "v3")}), - }; - - auto grpc_error = grpc::Status(grpc::StatusCode::UNAVAILABLE, "try again"); - auto error = MakeStatusFromRpcError(grpc_error); - - std::unique_ptr mock(new MockBackoffPolicy); - EXPECT_CALL(*mock, Setup); - EXPECT_CALL(*mock, OnCompletion(error)).WillOnce([](Status const&) { - return 10_ms; - }); - - EXPECT_CALL(*client_, PrepareAsyncMutateRows) - .WillOnce([grpc_error](grpc::ClientContext*, - btproto::MutateRowsRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, Read).Times(2); - EXPECT_CALL(*reader, Finish) - .WillOnce([grpc_error](grpc::Status* status, void*) { - *status = grpc_error; - }); - EXPECT_CALL(*reader, StartCall); - return reader; - }); - - auto bulk_apply_future = internal::AsyncRetryBulkApply::Create( - cq_, rpc_retry_policy_->clone(), std::move(mock), - *idempotent_mutation_policy_, metadata_update_policy_, client_, - "my-app-profile", "my-table", std::move(mut)); - - SimulateIteration(); - ASSERT_EQ(1U, cq_impl_->size()); - - // cancel the pending operation. - bulk_apply_future.cancel(); - // simulate the backoff timer expiring. - cq_impl_->SimulateCompletion(false); - - ASSERT_EQ(0U, cq_impl_->size()); - - auto failures = StatusOnly(bulk_apply_future.get()); - EXPECT_THAT(failures, ElementsAre(StatusIs(StatusCode::kUnavailable), - StatusIs(StatusCode::kUnavailable))); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_async_row_reader.cc b/google/cloud/bigtable/internal/legacy_async_row_reader.cc deleted file mode 100644 index 80ce9973850d0..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_row_reader.cc +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/legacy_async_row_reader.h" -#include "google/cloud/bigtable/version.h" -#include "google/cloud/log.h" - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -void LegacyAsyncRowReader::MakeRequest() { - status_ = Status(); - google::bigtable::v2::ReadRowsRequest request; - - request.set_app_profile_id(app_profile_id_); - request.set_table_name(table_name_); - auto row_set_proto = row_set_.as_proto(); - request.mutable_rows()->Swap(&row_set_proto); - - auto filter_proto = filter_.as_proto(); - request.mutable_filter()->Swap(&filter_proto); - - if (rows_limit_ != NO_ROWS_LIMIT) { - request.set_rows_limit(rows_limit_ - rows_count_); - } - parser_ = parser_factory_->Create(false); - - auto context = std::make_unique(); - rpc_retry_policy_->Setup(*context); - rpc_backoff_policy_->Setup(*context); - metadata_update_policy_.Setup(*context); - - auto& client = client_; - auto self = this->shared_from_this(); - cq_.MakeStreamingReadRpc( - [client](grpc::ClientContext* context, - google::bigtable::v2::ReadRowsRequest const& request, - grpc::CompletionQueue* cq) { - return client->PrepareAsyncReadRows(context, request, cq); - }, - request, std::move(context), - [self](google::bigtable::v2::ReadRowsResponse r) { - return self->OnDataReceived(std::move(r)); - }, - [self](Status s) { self->OnStreamFinished(std::move(s)); }); -} - -void LegacyAsyncRowReader::TryGiveRowToUser() { - // The user is likely to ask for more rows immediately after receiving a - // row, which means that this function will be called recursively. The depth - // of the recursion can be as deep as the size of ready_rows_, which might - // be significant and potentially lead to stack overflow. The way to - // overcome this is to always switch thread to a CompletionQueue thread. - // Switching thread for every row has a non-trivial cost, though. To find a - // good balance, we allow for recursion no deeper than 100 and achieve it by - // tracking the level in `recursion_level_`. - // - // The magic value 100 is arbitrary, but back-of-the-envelope calculation - // indicates it should cap this stack usage to below 100K. Default stack - // size is usually 1MB. - struct CountFrames { - explicit CountFrames(int& cntr) : cntr(++cntr) {} - ~CountFrames() { --cntr; } - int& cntr; - } counter(recursion_level_); - - if (ready_rows_.empty()) { - if (whole_op_finished_) { - // The scan is finished for good, there will be no more rows. - on_finish_(status_); - return; - } - if (!continue_reading_) { - GCP_LOG(FATAL) - << "No rows are ready and we can't continue reading. This is a bug, " - "please report it at " - "https://github.com/googleapis/google-cloud-cpp/issues/new"; - } - // No rows, but we can fetch some. - auto continue_reading = std::move(continue_reading_); - continue_reading_.reset(); - continue_reading->set_value(true); - return; - } - - // Yay! We have something to give to the user and they want it. - auto row = std::move(ready_rows_.front()); - ready_rows_.pop(); - - auto self = this->shared_from_this(); - bool const break_recursion = recursion_level_ >= 100; - on_row_(std::move(row)).then([self, break_recursion](future fut) { - bool should_cancel; -#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - try { - should_cancel = !fut.get(); - } catch (std::exception& ex) { - self->Cancel( - std::string("future<> returned from the user callback threw an " - "exception: ") + - ex.what()); - return; - } catch (...) { - self->Cancel( - "future<> returned from the user callback threw an unknown " - "exception"); - return; - } -#else // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - should_cancel = !fut.get(); -#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - if (should_cancel) { - self->Cancel("User cancelled"); - return; - } - if (break_recursion) { - self->cq_.RunAsync([self] { self->UserWantsRows(); }); - return; - } - self->UserWantsRows(); - }); -} - -future LegacyAsyncRowReader::OnDataReceived( - google::bigtable::v2::ReadRowsResponse response) { - // assert(!whole_op_finished_); - // assert(!continue_reading_); - // assert(status_.ok()); - status_ = ConsumeResponse(std::move(response)); - // We've processed the response. - // - // If there were errors (e.g. malformed response from the server), we should - // interrupt this stream. Interrupting it will yield lower layers calling - // `OnStreamFinished` with a status unrelated to the real reason, so we - // store the actual reason in status_ and proceed exactly the - // same way as if the stream was broken for other reasons. - // - // Even if status_ is not OK, we might have consumed some rows, - // but, don't give them to the user yet. We want to keep the invariant that - // either the user doesn't hold a `future<>` when we're fetching more rows. - // Retries (successful or not) will do it. Improving this behavior makes - // little sense because parser errors are very unexpected and probably not - // retryable anyway. - - if (status_.ok()) { - continue_reading_.emplace(promise()); - auto res = continue_reading_->get_future(); - TryGiveRowToUser(); - return res; - } - return make_ready_future(false); -} - -void LegacyAsyncRowReader::OnStreamFinished(Status status) { - // assert(!continue_reading_); - if (status_.ok()) { - status_ = std::move(status); - } - grpc::Status parser_status; - parser_->HandleEndOfStream(parser_status); - if (!parser_status.ok() && status_.ok()) { - // If there stream finished with an error ignore what the parser says. - status_ = MakeStatusFromRpcError(parser_status); - } - - // In the unlikely case when we have already reached the requested - // number of rows and still receive an error (the parser can throw - // an error at end of stream for example), there is no need to - // retry and we have no good value for rows_limit anyway. - if (rows_limit_ != NO_ROWS_LIMIT && rows_limit_ <= rows_count_) { - status_ = Status(); - } - - if (!last_read_row_key_.empty()) { - // We've returned some rows and need to make sure we don't - // request them again. - row_set_ = - row_set_.Intersect(bigtable::RowRange::Open(last_read_row_key_, "")); - } - - // If we receive an error, but the retryable set is empty, consider it a - // success. - if (row_set_.IsEmpty()) { - status_ = Status(); - } - - if (status_.ok()) { - // We've successfully finished the scan. - whole_op_finished_ = true; - TryGiveRowToUser(); - return; - } - - if (!rpc_retry_policy_->OnFailure(status_)) { - // Can't retry. - whole_op_finished_ = true; - TryGiveRowToUser(); - return; - } - auto self = this->shared_from_this(); - cq_.MakeRelativeTimer(rpc_backoff_policy_->OnCompletion(status_)) - .then( - [self]( - future> result) { - if (auto tp = result.get()) { - self->MakeRequest(); - } else { - self->whole_op_finished_ = true; - self->TryGiveRowToUser(); - } - }); -} - -void LegacyAsyncRowReader::Cancel(std::string const& reason) { - ready_rows_ = std::queue(); - auto continue_reading = std::move(continue_reading_); - continue_reading_.reset(); - Status status(StatusCode::kCancelled, reason); - if (!continue_reading) { - // If we're not in the middle of the stream fire some user callbacks, but - // also override the overall status. - // assert(whole_op_finished_); - status_ = std::move(status); - TryGiveRowToUser(); - return; - } - // If we are in the middle of the stream, cancel the stream. - status_ = std::move(status); - continue_reading->set_value(false); -} - -Status LegacyAsyncRowReader::DrainParser() { - grpc::Status status; - while (parser_->HasNext()) { - bigtable::Row parsed_row = parser_->Next(status); - if (!status.ok()) { - return MakeStatusFromRpcError(status); - } - ++rows_count_; - last_read_row_key_ = parsed_row.row_key(); - ready_rows_.emplace(std::move(parsed_row)); - } - return Status(); -} - -Status LegacyAsyncRowReader::ConsumeResponse( - google::bigtable::v2::ReadRowsResponse response) { - for (auto& chunk : *response.mutable_chunks()) { - grpc::Status status; - parser_->HandleChunk(std::move(chunk), status); - if (!status.ok()) { - return MakeStatusFromRpcError(status); - } - Status parser_status = DrainParser(); - if (!parser_status.ok()) { - return parser_status; - } - } - if (!response.last_scanned_row_key().empty()) { - last_read_row_key_ = std::move(*response.mutable_last_scanned_row_key()); - } - return Status(); -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_async_row_reader.h b/google/cloud/bigtable/internal/legacy_async_row_reader.h deleted file mode 100644 index 0202f2ea1348d..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_row_reader.h +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_ROW_READER_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_ROW_READER_H - -#include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/data_client.h" -#include "google/cloud/bigtable/filters.h" -#include "google/cloud/bigtable/internal/readrowsparser.h" -#include "google/cloud/bigtable/metadata_update_policy.h" -#include "google/cloud/bigtable/row.h" -#include "google/cloud/bigtable/row_set.h" -#include "google/cloud/bigtable/rpc_backoff_policy.h" -#include "google/cloud/bigtable/rpc_retry_policy.h" -#include "google/cloud/bigtable/version.h" -#include "google/cloud/future.h" -#include "google/cloud/grpc_error_delegate.h" -#include "google/cloud/optional.h" -#include "google/cloud/status_or.h" -#include "absl/types/optional.h" -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -/** - * Objects of this class represent the state of reading rows via AsyncReadRows. - */ -class LegacyAsyncRowReader - : public std::enable_shared_from_this { - using RowFunctor = std::function(bigtable::Row)>; - using FinishFunctor = std::function; - - public: - /// Special value to be used as rows_limit indicating no limit. - // NOLINTNEXTLINE(readability-identifier-naming) - static std::int64_t constexpr NO_ROWS_LIMIT = 0; - // Callbacks keep pointers to these objects. - LegacyAsyncRowReader(LegacyAsyncRowReader&&) = delete; - LegacyAsyncRowReader(LegacyAsyncRowReader const&) = delete; - - static std::shared_ptr Create( - CompletionQueue cq, std::shared_ptr client, - std::string app_profile_id, std::string table_name, RowFunctor on_row, - FinishFunctor on_finish, bigtable::RowSet row_set, - std::int64_t rows_limit, bigtable::Filter filter, - std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - bigtable::MetadataUpdatePolicy metadata_update_policy, - std::unique_ptr - parser_factory) { - std::shared_ptr res(new LegacyAsyncRowReader( - std::move(cq), std::move(client), std::move(app_profile_id), - std::move(table_name), std::move(on_row), std::move(on_finish), - std::move(row_set), rows_limit, std::move(filter), - std::move(rpc_retry_policy), std::move(rpc_backoff_policy), - std::move(metadata_update_policy), std::move(parser_factory))); - res->MakeRequest(); - return res; - } - - private: - LegacyAsyncRowReader( - CompletionQueue cq, std::shared_ptr client, - std::string app_profile_id, std::string table_name, RowFunctor on_row, - FinishFunctor on_finish, bigtable::RowSet row_set, - std::int64_t rows_limit, bigtable::Filter filter, - std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - bigtable::MetadataUpdatePolicy metadata_update_policy, - std::unique_ptr parser_factory) - : cq_(std::move(cq)), - client_(std::move(client)), - app_profile_id_(std::move(app_profile_id)), - table_name_(std::move(table_name)), - on_row_(std::move(on_row)), - on_finish_(std::move(on_finish)), - row_set_(std::move(row_set)), - rows_limit_(rows_limit), - filter_(std::move(filter)), - rpc_retry_policy_(std::move(rpc_retry_policy)), - rpc_backoff_policy_(std::move(rpc_backoff_policy)), - metadata_update_policy_(std::move(metadata_update_policy)), - parser_factory_(std::move(parser_factory)) {} - - void MakeRequest(); - - /** - * Called when the user asks for more rows via satisfying the future returned - * from the row callback. - */ - void UserWantsRows() { TryGiveRowToUser(); } - - /** - * Attempt to call a user callback. - * - * If no rows are ready, this will not call the callback immediately and - * instead ask lower layers for more data. - */ - void TryGiveRowToUser(); - - /// Called when lower layers provide us with a response chunk. - future OnDataReceived(google::bigtable::v2::ReadRowsResponse response); - - /// Called when the whole stream finishes. - void OnStreamFinished(Status status); - - /// User satisfied the future returned from the row callback with false. - void Cancel(std::string const& reason); - - /// Process everything that is accumulated in the parser. - Status DrainParser(); - - /// Parse the data from the response. - Status ConsumeResponse(google::bigtable::v2::ReadRowsResponse response); - - std::mutex mu_; - CompletionQueue cq_; - std::shared_ptr client_; - std::string app_profile_id_; - std::string table_name_; - RowFunctor on_row_; - FinishFunctor on_finish_; - bigtable::RowSet row_set_; - std::int64_t rows_limit_; - bigtable::Filter filter_; - std::unique_ptr rpc_retry_policy_; - std::unique_ptr rpc_backoff_policy_; - bigtable::MetadataUpdatePolicy metadata_update_policy_; - std::unique_ptr parser_factory_; - std::unique_ptr parser_; - /// Number of rows read so far, used to set row_limit in retries. - std::int64_t rows_count_ = 0; - /// Holds the last read row key, for retries. - bigtable::RowKeyType last_read_row_key_; - /// The queue of rows which we already received but no one has asked for them. - std::queue ready_rows_; - /** - * The promise to the underlying stream to either continue reading or cancel. - * - * If the `absl::optional` is empty, it means that either the whole scan is - * finished or the underlying layers are already trying to fetch more data. - * - * If the `absl::optional` is not empty, the lower layers are waiting for this - * to be satisfied before they start fetching more data. - */ - absl::optional> continue_reading_; - /// The final status of the operation. - bool whole_op_finished_ = false; - /** - * The status of the last retry attempt_. - * - * It is reset to OK at the beginning of every retry. If an error is - * encountered (be it while parsing the response or on stream finish), it is - * stored here (unless a different error had already been stored). - */ - Status status_; - /// Tracks the level of recursion of TryGiveRowToUser - int recursion_level_ = 0; -}; - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_ROW_READER_H diff --git a/google/cloud/bigtable/internal/legacy_async_row_reader_test.cc b/google/cloud/bigtable/internal/legacy_async_row_reader_test.cc deleted file mode 100644 index 83eef314300b0..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_row_reader_test.cc +++ /dev/null @@ -1,1159 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/mock_data_client.h" -#include "google/cloud/bigtable/testing/mock_read_rows_reader.h" -#include "google/cloud/bigtable/testing/mock_response_reader.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/internal/api_client_header.h" -#include "google/cloud/testing_util/chrono_literals.h" -#include "google/cloud/testing_util/fake_completion_queue_impl.h" -#include "google/cloud/testing_util/status_matchers.h" -#include "google/cloud/testing_util/validate_metadata.h" -#include -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; - -using ::google::cloud::bigtable::testing::MockClientAsyncReaderInterface; -using ::google::cloud::testing_util::ValidateMetadataFixture; -using ::google::cloud::testing_util::chrono_literals::operator""_ms; -using ::google::cloud::testing_util::FakeCompletionQueueImpl; -using ::testing::HasSubstr; -using ::testing::Values; -using ::testing::WithParamInterface; - -template -bool Unsatisfied(future const& fut) { - return std::future_status::timeout == fut.wait_for(1_ms); -} - -class TableAsyncReadRowsTest : public bigtable::testing::TableTestFixture { - protected: - TableAsyncReadRowsTest() - : TableTestFixture( - CompletionQueue(std::make_shared())), - stream_status_future_(stream_status_promise_.get_future()) {} - - MockClientAsyncReaderInterface& AddReader( - std::function request_expectations, - bool expect_a_read = true) { - readers_.emplace_back( - new MockClientAsyncReaderInterface); - reader_started_.push_back(false); - size_t idx = reader_started_.size() - 1; - auto& reader = LastReader(); - // We can't move request_expectations into the lambda because of lack of - // generalized lambda capture in C++11, so let's pass it by pointer. - auto request_expectations_ptr = - std::make_shared( - std::move(request_expectations)); - - EXPECT_CALL(*client_, PrepareAsyncReadRows) - .WillOnce([this, &reader, request_expectations_ptr]( - grpc::ClientContext* context, - btproto::ReadRowsRequest const& r, - grpc::CompletionQueue*) { - validate_metadata_fixture_.IsContextMDValid( - *context, "google.bigtable.v2.Bigtable.ReadRows", r, - google::cloud::internal::HandCraftedLibClientHeader()); - (*request_expectations_ptr)(r); - return std::unique_ptr< - MockClientAsyncReaderInterface>( - &reader); - }) - .RetiresOnSaturation(); - - EXPECT_CALL(reader, StartCall).WillOnce([idx, this](void*) { - reader_started_[idx] = true; - }); - if (expect_a_read) { - // The last call, to which we'll return ok==false. - EXPECT_CALL(reader, Read).WillOnce([](btproto::ReadRowsResponse*, void*) { - }); - } - return reader; - } - - MockClientAsyncReaderInterface& LastReader() { - return *readers_.back(); - } - - // Start Table::AsyncReadRows. - void ReadRows(int row_limit = RowReader::NO_ROWS_LIMIT) { - table_.AsyncReadRows( - [this](Row const& row) { - EXPECT_EQ(expected_rows_.front(), row.row_key()); - expected_rows_.pop(); - row_promises_.front().set_value(row.row_key()); - row_promises_.pop(); - auto ret = std::move(futures_from_user_cb_.front()); - futures_from_user_cb_.pop(); - return ret; - }, - [this](Status const& stream_status) { - stream_status_promise_.set_value(stream_status); - }, - RowSet(), row_limit, Filter::PassAllFilter()); - } - - /// Expect a row whose row key is equal to this function's argument. - template - void ExpectRow(T const& row) { - row_promises_.emplace(); - row_futures_.emplace_back(row_promises_.back().get_future()); - promises_from_user_cb_.emplace_back(); - futures_from_user_cb_.emplace(promises_from_user_cb_.back().get_future()); - expected_rows_.push(RowKeyType(row)); - } - - /// A wrapper around ExpectRow to expect many rows. - template - void ExpectRows(std::initializer_list const& rows) { - for (auto const& row : rows) { - ExpectRow(row); - } - } - - std::vector*> - readers_; - // Whether `Start()` was called on i-th retry attempt. - std::vector reader_started_; - std::queue> row_promises_; - /** - * Future at idx i corresponse to i-th expected row. It will be satisfied - * when the relevant `on_row` callback of AsyncReadRows is called. - */ - std::vector> row_futures_; - std::queue expected_rows_; - promise stream_status_promise_; - /// Future which will be satisfied with the status passed in on_finished. - future stream_status_future_; - /// I-th promise corresponds to the future returned from the ith on_row cb. - std::vector> promises_from_user_cb_; - std::queue> futures_from_user_cb_; - ValidateMetadataFixture validate_metadata_fixture_; -}; - -/// @test Verify that successfully reading a single row works. -TEST_F(TableAsyncReadRowsTest, SingleRow) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - auto row = row_futures_[0].get(); - - // Check that we're not asking for data unless someone is waiting for it. - ASSERT_EQ(0U, cq_impl_->size()); - promises_from_user_cb_[0].set_value(true); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Like SingleRow, but the future returned from the cb is satisfied. -TEST_F(TableAsyncReadRowsTest, SingleRowInstantFinish) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - promises_from_user_cb_[0].set_value(true); - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - auto row = row_futures_[0].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Verify that reading 2 rows delivered in 2 responses works. -TEST_F(TableAsyncReadRowsTest, MultipleChunks) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - ExpectRow("r2"); - promises_from_user_cb_[1].set_value(true); - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - row_futures_[0].get(); - - // Check that we're not asking for data unless someone is waiting for it. - ASSERT_EQ(0U, cq_impl_->size()); - promises_from_user_cb_[0].set_value(true); - - EXPECT_TRUE(Unsatisfied(row_futures_[1])); - cq_impl_->SimulateCompletion(true); // Return data - row_futures_[1].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Like MultipleChunks but the future returned from on_row is satisfied. -TEST_F(TableAsyncReadRowsTest, MultipleChunksImmediatelySatisfied) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - ExpectRow("r2"); - promises_from_user_cb_[0].set_value(true); - promises_from_user_cb_[1].set_value(true); - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - row_futures_[0].get(); - - EXPECT_TRUE(Unsatisfied(row_futures_[1])); - cq_impl_->SimulateCompletion(true); // Return data - row_futures_[1].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Verify that a single row can span multiple responses. -TEST_F(TableAsyncReadRowsTest, ResponseInMultipleChunks) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: false - })"); - }) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col2" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - promises_from_user_cb_[0].set_value(true); - ReadRows(); - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - - row_futures_[0].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Verify that parser fails if the stream finishes prematurely. -TEST_F(TableAsyncReadRowsTest, ParserEofFailsOnUnfinishedRow) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - // missing final commit - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: false - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - ASSERT_FALSE(stream_status_future_.get().ok()); -} - -/// @test Check that we ignore HandleEndOfStream errors if enough rows were read -TEST_F(TableAsyncReadRowsTest, ParserEofDoesntFailsOnUnfinishedRowIfRowLimit) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - // missing final commit - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: false - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - promises_from_user_cb_[0].set_value(true); - ReadRows(1); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - cq_impl_->SimulateCompletion(true); // Return data - - row_futures_[0].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Verify that permanent errors are not retried and properly passed. -TEST_F(TableAsyncReadRowsTest, PermanentFailure) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::PERMISSION_DENIED, "noooo"); - }); - - ReadRows(); - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_EQ(StatusCode::kPermissionDenied, stream_status.code()); -} - -/// @test Verify that transient errors are retried. -TEST_F(TableAsyncReadRowsTest, TransientErrorIsRetried) { - auto& stream2 = AddReader([](btproto::ReadRowsRequest const& req) { - // Verify that we're not asking for the same rows again. - EXPECT_TRUE(req.has_rows()); - auto const& rows = req.rows(); - EXPECT_EQ(1, rows.row_ranges_size()); - auto const& range = rows.row_ranges(0); - EXPECT_EQ("r1", range.start_key_open()); - }); - auto& stream1 = AddReader([](btproto::ReadRowsRequest const&) {}); - - // Make it a bit trickier by delivering the error while parsing second row. - EXPECT_CALL(stream1, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: false - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream1, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::UNAVAILABLE, "oh no"); - }); - - EXPECT_CALL(stream2, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream2, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRows({"r1", "r2"}); - promises_from_user_cb_[0].set_value(true); - promises_from_user_cb_[1].set_value(true); - ReadRows(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - - row_futures_[0].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream with failure - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish timer - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(row_futures_[1])); - cq_impl_->SimulateCompletion(true); // Return data - - row_futures_[1].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Verify that the last scanned row is respected. -TEST_F(TableAsyncReadRowsTest, LastScannedRowKeyIsRespected) { - auto& stream2 = AddReader([](btproto::ReadRowsRequest const& req) { - // The server has told that "r2" has been scanned. Our second request - // should use the range ("r2", ""]. This is what is under test. - EXPECT_TRUE(req.has_rows()); - auto const& rows = req.rows(); - EXPECT_EQ(1, rows.row_ranges_size()); - auto const& range = rows.row_ranges(0); - EXPECT_EQ("r2", range.start_key_open()); - }); - auto& stream1 = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream1, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - std::cout << "Second Read for stream1 " << std::endl; - btproto::ReadRowsResponse resp; - resp.set_last_scanned_row_key("r2"); - *r = resp; - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream1, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::UNAVAILABLE, "retry"); - }); - - EXPECT_CALL(stream2, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRows({"r1", "r2", "r3"}); - promises_from_user_cb_[0].set_value(true); - ReadRows(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return "r1" - - row_futures_[0].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return last_scanned_row_key = "r2" - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream1 with failure - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish timer - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -/// @test Verify proper handling of bogus responses from the service. -TEST_F(TableAsyncReadRowsTest, ParserFailure) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - // Row not in increasing order. - R"( - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r2"); - promises_from_user_cb_[0].set_value(true); - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish placeholder Read() - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - row_futures_[0].get(); - - auto stream_status = stream_status_future_.get(); - ASSERT_EQ(StatusCode::kInternal, stream_status.code()); - ASSERT_EQ(0U, cq_impl_->size()); -} - -enum class CancelMode { - kFalseValue, -#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - kStdExcept, - kOtherExcept, -#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS -}; - -/// @test Verify canceling the stream by satisfying the futures with false -class TableAsyncReadRowsCancelMidStreamTest - : public TableAsyncReadRowsTest, - public WithParamInterface {}; - -TEST_P(TableAsyncReadRowsCancelMidStreamTest, CancelMidStream) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - row_futures_[0].get(); - - // Check that we're not asking for data unless someone is waiting for it. - ASSERT_EQ(0U, cq_impl_->size()); - - switch (GetParam()) { - case CancelMode::kFalseValue: - promises_from_user_cb_[0].set_value(false); - break; -#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - case CancelMode::kStdExcept: - try { - throw std::runtime_error("user threw std::exception"); - } catch (...) { - promises_from_user_cb_[0].set_exception(std::current_exception()); - } - break; - case CancelMode::kOtherExcept: - try { - throw 5; - } catch (...) { - promises_from_user_cb_[0].set_exception(std::current_exception()); - } - break; -#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - } - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_EQ(StatusCode::kCancelled, stream_status.code()); - switch (GetParam()) { - case CancelMode::kFalseValue: - ASSERT_THAT(stream_status.message(), HasSubstr("User cancelled")); - break; -#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - case CancelMode::kStdExcept: - ASSERT_THAT(stream_status.message(), - HasSubstr("user threw std::exception")); - break; - case CancelMode::kOtherExcept: - ASSERT_THAT(stream_status.message(), HasSubstr("unknown exception")); - break; -#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - } - - ASSERT_EQ(0U, cq_impl_->size()); -} - -#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS -INSTANTIATE_TEST_SUITE_P(CancelMidStream, TableAsyncReadRowsCancelMidStreamTest, - Values(CancelMode::kFalseValue, CancelMode::kStdExcept, - CancelMode::kOtherExcept)); -#else // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS -INSTANTIATE_TEST_SUITE_P(CancelMidStream, TableAsyncReadRowsCancelMidStreamTest, - Values(CancelMode::kFalseValue)); -#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - -/// @test Like CancelMidStream but after the underlying stream has finished. -TEST_F(TableAsyncReadRowsTest, CancelAfterStreamFinish) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - // First two rows are going to be processed, but third will cause the parser - // to fail (row order violation). This will result in finishing the stream - // while still keeping the two processed rows for the user. - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - chunks { - row_key: "r0" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - ExpectRow("r1"); - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - ASSERT_EQ(0U, cq_impl_->size()); - - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - auto row = row_futures_[0].get(); - - // Check that we're not asking for data unless someone is waiting for it. - ASSERT_EQ(0U, cq_impl_->size()); - promises_from_user_cb_[0].set_value(false); - - auto stream_status = stream_status_future_.get(); - ASSERT_FALSE(stream_status.ok()); - ASSERT_EQ(StatusCode::kCancelled, stream_status.code()); -} - -/// @test Verify that the recursion described in TryGiveRowToUser is bounded. -TEST_F(TableAsyncReadRowsTest, DeepStack) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - auto large_response = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "000" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - ExpectRow("000"); - for (int i = 1; i < 101; ++i) { - auto chunk = large_response.chunks(0); - std::stringstream s_idx; - s_idx << std::setfill('0') << std::setw(3) << i; - chunk.set_row_key(s_idx.str()); - ExpectRow(chunk.row_key()); - *large_response.add_chunks() = std::move(chunk); - } - - EXPECT_CALL(stream, Read) - .WillOnce([large_response](btproto::ReadRowsResponse* r, void*) { - *r = large_response; - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - for (int i = 0; i < 101; ++i) { - promises_from_user_cb_[i].set_value(true); - } - ReadRows(); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_futures_[0])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - - for (int i = 0; i < 100; ++i) { - row_futures_[i].get(); - } - ASSERT_TRUE(Unsatisfied(row_futures_[100])); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // RunAsync - row_futures_[100].get(); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(stream_status_future_)); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto stream_status = stream_status_future_.get(); - ASSERT_STATUS_OK(stream_status); - ASSERT_EQ(0U, cq_impl_->size()); -} - -TEST_F(TableAsyncReadRowsTest, ReadRowSuccess) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Read) - .WillOnce([](btproto::ReadRowsResponse* r, void*) { - *r = bigtable::testing::ReadRowsResponseFromString( - R"( - chunks { - row_key: "000" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - })"); - }) - .RetiresOnSaturation(); - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - auto row_future = table_.AsyncReadRow("000", Filter::PassAllFilter()); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - EXPECT_TRUE(Unsatisfied(row_future)); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Return data - - // We return data only after the whole stream is finished. - ASSERT_TRUE(Unsatisfied(row_future)); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto row = row_future.get(); - ASSERT_STATUS_OK(row); - ASSERT_TRUE(row->first); - ASSERT_EQ("000", row->second.row_key()); - - ASSERT_EQ(0U, cq_impl_->size()); -} - -TEST_F(TableAsyncReadRowsTest, ReadRowNotFound) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - - auto row_future = table_.AsyncReadRow("000", Filter::PassAllFilter()); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(row_future)); - - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto row = row_future.get(); - ASSERT_STATUS_OK(row); - ASSERT_FALSE(row->first); -} - -TEST_F(TableAsyncReadRowsTest, ReadRowError) { - auto& stream = AddReader([](btproto::ReadRowsRequest const&) {}); - - EXPECT_CALL(stream, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::PERMISSION_DENIED, ""); - }); - - auto row_future = table_.AsyncReadRow("000", Filter::PassAllFilter()); - - EXPECT_TRUE(reader_started_[0]); - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); // Finish Start() - - ASSERT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(false); // Finish stream - ASSERT_EQ(1U, cq_impl_->size()); - EXPECT_TRUE(Unsatisfied(row_future)); - - cq_impl_->SimulateCompletion(true); // Finish Finish() - - auto row = row_future.get(); - ASSERT_FALSE(row); - ASSERT_EQ(StatusCode::kPermissionDenied, row.status().code()); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_async_row_sampler.cc b/google/cloud/bigtable/internal/legacy_async_row_sampler.cc deleted file mode 100644 index 9ed3f3065b620..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_row_sampler.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/legacy_async_row_sampler.h" -#include "google/cloud/grpc_error_delegate.h" -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace internal { - -namespace btproto = ::google::bigtable::v2; - -future>> LegacyAsyncRowSampler::Create( - CompletionQueue cq, std::shared_ptr client, - std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - MetadataUpdatePolicy metadata_update_policy, std::string app_profile_id, - std::string table_name) { - std::shared_ptr sampler(new LegacyAsyncRowSampler( - std::move(cq), std::move(client), std::move(rpc_retry_policy), - std::move(rpc_backoff_policy), std::move(metadata_update_policy), - std::move(app_profile_id), std::move(table_name))); - sampler->StartIteration(); - return sampler->promise_.get_future(); -} - -LegacyAsyncRowSampler::LegacyAsyncRowSampler( - CompletionQueue cq, std::shared_ptr client, - std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - MetadataUpdatePolicy metadata_update_policy, std::string app_profile_id, - std::string table_name) - : cq_(std::move(cq)), - client_(std::move(client)), - rpc_retry_policy_(std::move(rpc_retry_policy)), - rpc_backoff_policy_(std::move(rpc_backoff_policy)), - metadata_update_policy_(std::move(metadata_update_policy)), - app_profile_id_(std::move(app_profile_id)), - table_name_(std::move(table_name)), - promise_([this] { keep_reading_ = false; }) {} - -void LegacyAsyncRowSampler::StartIteration() { - btproto::SampleRowKeysRequest request; - request.set_app_profile_id(app_profile_id_); - request.set_table_name(table_name_); - - auto context = std::make_unique(); - rpc_retry_policy_->Setup(*context); - rpc_backoff_policy_->Setup(*context); - metadata_update_policy_.Setup(*context); - - auto& client = client_; - auto self = this->shared_from_this(); - cq_.MakeStreamingReadRpc( - [client](grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request, - grpc::CompletionQueue* cq) { - return client->PrepareAsyncSampleRowKeys(context, request, cq); - }, - request, std::move(context), - [self](btproto::SampleRowKeysResponse response) { - return self->OnRead(std::move(response)); - }, - [self](Status const& status) { self->OnFinish(status); }); -} - -future LegacyAsyncRowSampler::OnRead( - btproto::SampleRowKeysResponse response) { - RowKeySample row_sample; - row_sample.offset_bytes = response.offset_bytes(); - row_sample.row_key = std::move(*response.mutable_row_key()); - samples_.emplace_back(std::move(row_sample)); - return make_ready_future(keep_reading_.load()); -} - -void LegacyAsyncRowSampler::OnFinish(Status const& status) { - if (status.ok()) { - promise_.set_value(std::move(samples_)); - return; - } - if (!rpc_retry_policy_->OnFailure(status)) { - promise_.set_value(status); - return; - } - - using TimerFuture = future>; - - samples_.clear(); - auto self = this->shared_from_this(); - auto delay = rpc_backoff_policy_->OnCompletion(std::move(status)); - cq_.MakeRelativeTimer(delay).then([self](TimerFuture result) { - if (result.get()) { - self->StartIteration(); - } else { - self->promise_.set_value( - Status(StatusCode::kCancelled, "call cancelled")); - } - }); -} - -} // namespace internal -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_async_row_sampler.h b/google/cloud/bigtable/internal/legacy_async_row_sampler.h deleted file mode 100644 index 54c4440ddb24e..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_row_sampler.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_ROW_SAMPLER_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_ROW_SAMPLER_H - -#include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/data_client.h" -#include "google/cloud/bigtable/metadata_update_policy.h" -#include "google/cloud/bigtable/row_key_sample.h" -#include "google/cloud/bigtable/rpc_backoff_policy.h" -#include "google/cloud/bigtable/rpc_retry_policy.h" -#include "google/cloud/bigtable/version.h" -#include "google/cloud/future_generic.h" -#include "google/cloud/status.h" -#include "google/cloud/status_or.h" -#include "google/bigtable/v2/bigtable.pb.h" -#include -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace internal { - -/** - * Objects of this class represent the state of receiving row keys via - * AsyncSampleRows. - */ -class LegacyAsyncRowSampler - : public std::enable_shared_from_this { - public: - static future>> Create( - CompletionQueue cq, std::shared_ptr client, - std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - MetadataUpdatePolicy metadata_update_policy, std::string app_profile_id, - std::string table_name); - - private: - LegacyAsyncRowSampler(CompletionQueue cq, std::shared_ptr client, - std::unique_ptr rpc_retry_policy, - std::unique_ptr rpc_backoff_policy, - MetadataUpdatePolicy metadata_update_policy, - std::string app_profile_id, std::string table_name); - - void StartIteration(); - future OnRead(google::bigtable::v2::SampleRowKeysResponse response); - void OnFinish(Status const& status); - - CompletionQueue cq_; - std::shared_ptr client_; - std::unique_ptr rpc_retry_policy_; - std::unique_ptr rpc_backoff_policy_; - MetadataUpdatePolicy metadata_update_policy_; - std::string app_profile_id_; - std::string table_name_; - - std::atomic keep_reading_{true}; - std::vector samples_; - promise>> promise_; -}; - -} // namespace internal -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ASYNC_ROW_SAMPLER_H diff --git a/google/cloud/bigtable/internal/legacy_async_row_sampler_test.cc b/google/cloud/bigtable/internal/legacy_async_row_sampler_test.cc deleted file mode 100644 index f5eaab86ad4c0..0000000000000 --- a/google/cloud/bigtable/internal/legacy_async_row_sampler_test.cc +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/legacy_async_row_sampler.h" -#include "google/cloud/bigtable/testing/mock_policies.h" -#include "google/cloud/bigtable/testing/mock_response_reader.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/testing_util/fake_completion_queue_impl.h" -#include "google/cloud/testing_util/status_matchers.h" -#include "google/bigtable/v2/bigtable.pb.h" -#include -#include -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; - -using ::google::cloud::bigtable::testing::MockBackoffPolicy; -using ::google::cloud::bigtable::testing::MockClientAsyncReaderInterface; -using ::google::cloud::testing_util::FakeCompletionQueueImpl; -using ::google::cloud::testing_util::StatusIs; -using ::testing::ElementsAre; -using ::testing::HasSubstr; - -class AsyncSampleRowKeysTest : public bigtable::testing::TableTestFixture { - protected: - AsyncSampleRowKeysTest() - : TableTestFixture( - CompletionQueue(std::make_shared())), - rpc_retry_policy_( - bigtable::DefaultRPCRetryPolicy(internal::kBigtableLimits)), - metadata_update_policy_("my_table", MetadataParamTypes::NAME) {} - - std::shared_ptr rpc_retry_policy_; - MetadataUpdatePolicy metadata_update_policy_; -}; - -struct RowKeySampleVectors { - explicit RowKeySampleVectors(std::vector samples) { - row_keys.reserve(samples.size()); - offset_bytes.reserve(samples.size()); - for (auto& sample : samples) { - row_keys.emplace_back(std::move(sample.row_key)); - offset_bytes.emplace_back(std::move(sample.offset_bytes)); - } - } - - std::vector row_keys; - std::vector offset_bytes; -}; - -TEST_F(AsyncSampleRowKeysTest, Simple) { - EXPECT_CALL(*client_, PrepareAsyncSampleRowKeys) - .WillOnce([](grpc::ClientContext*, btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test1"); - r->set_offset_bytes(11); - } - }) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test2"); - r->set_offset_bytes(22); - } - }) - .WillOnce([](btproto::SampleRowKeysResponse*, void*) {}); - - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - return reader; - }); - - auto samples_future = table_.AsyncSampleRows(); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response 1 - cq_impl_->SimulateCompletion(true); - // Return response 2 - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - - auto status = samples_future.get(); - ASSERT_STATUS_OK(status); - - auto samples = RowKeySampleVectors(status.value()); - EXPECT_THAT(samples.row_keys, ElementsAre("test1", "test2")); - EXPECT_THAT(samples.offset_bytes, ElementsAre(11, 22)); -} - -TEST_F(AsyncSampleRowKeysTest, Retry) { - EXPECT_CALL(*client_, PrepareAsyncSampleRowKeys) - .WillOnce([](grpc::ClientContext*, btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test1"); - r->set_offset_bytes(11); - } - }) - .WillOnce([](btproto::SampleRowKeysResponse*, void*) {}); - - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::UNAVAILABLE, "try again"); - }); - return reader; - }) - .WillOnce([](grpc::ClientContext*, btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test2"); - r->set_offset_bytes(22); - } - }) - .WillOnce([](btproto::SampleRowKeysResponse*, void*) {}); - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - return reader; - }); - - auto samples_future = table_.AsyncSampleRows(); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - // Simulate the backoff timer - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(1U, cq_impl_->size()); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(0U, cq_impl_->size()); - - auto status = samples_future.get(); - ASSERT_STATUS_OK(status); - - auto samples = RowKeySampleVectors(status.value()); - EXPECT_THAT(samples.row_keys, ElementsAre("test2")); - EXPECT_THAT(samples.offset_bytes, ElementsAre(22)); -} - -TEST_F(AsyncSampleRowKeysTest, TooManyFailures) { - // We give up on the 3rd error. - auto constexpr kErrorCount = 2; - Table custom_table(client_, "foo_table", - LimitedErrorCountRetryPolicy(kErrorCount)); - - EXPECT_CALL(*client_, PrepareAsyncSampleRowKeys) - .Times(kErrorCount + 1) - .WillRepeatedly([](grpc::ClientContext*, - btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read).Times(2); - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::UNAVAILABLE, "try again"); - }); - return reader; - }); - - auto samples_future = custom_table.AsyncSampleRows(); - - for (int retry = 0; retry < kErrorCount; ++retry) { - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - // Simulate the backoff timer - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(1U, cq_impl_->size()); - } - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - - auto status = samples_future.get(); - ASSERT_THAT(status, - StatusIs(StatusCode::kUnavailable, HasSubstr("try again"))); - - ASSERT_EQ(0U, cq_impl_->size()); -} - -TEST_F(AsyncSampleRowKeysTest, UsesBackoff) { - auto grpc_error = grpc::Status(grpc::StatusCode::UNAVAILABLE, "try again"); - auto error = MakeStatusFromRpcError(grpc_error); - - std::unique_ptr mock(new MockBackoffPolicy); - EXPECT_CALL(*mock, Setup).Times(2); - EXPECT_CALL(*mock, OnCompletion(error)); - - EXPECT_CALL(*client_, PrepareAsyncSampleRowKeys) - .WillOnce([grpc_error](grpc::ClientContext*, - btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read).Times(2); - EXPECT_CALL(*reader, Finish) - .WillOnce([grpc_error](grpc::Status* status, void*) { - *status = grpc_error; - }); - return reader; - }) - .WillOnce([](grpc::ClientContext*, btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read).Times(2); - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - return reader; - }); - - auto samples_future = internal::LegacyAsyncRowSampler::Create( - cq_, client_, rpc_retry_policy_->clone(), std::move(mock), - metadata_update_policy_, "my-app-profile", "my-table"); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - // Simulate the backoff timer - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(1U, cq_impl_->size()); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(0U, cq_impl_->size()); -} - -TEST_F(AsyncSampleRowKeysTest, CancelDuringBackoff) { - auto grpc_error = grpc::Status(grpc::StatusCode::UNAVAILABLE, "try again"); - auto error = MakeStatusFromRpcError(grpc_error); - - std::unique_ptr mock(new MockBackoffPolicy); - EXPECT_CALL(*mock, Setup); - EXPECT_CALL(*mock, OnCompletion(error)); - - EXPECT_CALL(*client_, PrepareAsyncSampleRowKeys) - .WillOnce([grpc_error](grpc::ClientContext*, - btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read).Times(2); - EXPECT_CALL(*reader, Finish) - .WillOnce([grpc_error](grpc::Status* status, void*) { - *status = grpc_error; - }); - return reader; - }); - - auto samples_future = internal::LegacyAsyncRowSampler::Create( - cq_, client_, rpc_retry_policy_->clone(), std::move(mock), - metadata_update_policy_, "my-app-profile", "my-table"); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - - ASSERT_EQ(1U, cq_impl_->size()); - - // Cancel the pending operation. - samples_future.cancel(); - // Simulate the backoff timer - cq_impl_->SimulateCompletion(false); - - ASSERT_EQ(0U, cq_impl_->size()); - - auto status = samples_future.get(); - ASSERT_THAT(status, - StatusIs(StatusCode::kCancelled, HasSubstr("call cancelled"))); -} - -TEST_F(AsyncSampleRowKeysTest, CancelAfterSuccess) { - EXPECT_CALL(*client_, PrepareAsyncSampleRowKeys) - .WillOnce([](grpc::ClientContext*, btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test1"); - r->set_offset_bytes(11); - } - }) - .WillOnce([](btproto::SampleRowKeysResponse*, void*) {}); - - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status::OK; - }); - return reader; - }); - - auto samples_future = table_.AsyncSampleRows(); - // samples_future.cancel(); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response - cq_impl_->SimulateCompletion(true); - - // Cancel the pending operation - samples_future.cancel(); - - // End stream - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - - auto status = samples_future.get(); - ASSERT_STATUS_OK(status); - - auto samples = RowKeySampleVectors(status.value()); - EXPECT_THAT(samples.row_keys, ElementsAre("test1")); - EXPECT_THAT(samples.offset_bytes, ElementsAre(11)); -} - -TEST_F(AsyncSampleRowKeysTest, CancelMidStream) { - EXPECT_CALL(*client_, PrepareAsyncSampleRowKeys) - .WillOnce([](grpc::ClientContext*, btproto::SampleRowKeysRequest const&, - grpc::CompletionQueue*) { - auto reader = std::make_unique< - MockClientAsyncReaderInterface>(); - EXPECT_CALL(*reader, StartCall); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test1"); - r->set_offset_bytes(11); - } - }) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test2"); - r->set_offset_bytes(22); - } - }) - .WillOnce([](btproto::SampleRowKeysResponse* r, void*) { - { - r->set_row_key("test3"); - r->set_offset_bytes(33); - } - }); - EXPECT_CALL(*reader, Finish).WillOnce([](grpc::Status* status, void*) { - *status = grpc::Status(grpc::StatusCode::CANCELLED, "User cancelled"); - }); - return reader; - }); - - auto samples_future = table_.AsyncSampleRows(); - - // Start() - cq_impl_->SimulateCompletion(true); - // Return response 1 - cq_impl_->SimulateCompletion(true); - // Cancel the pending operation - samples_future.cancel(); - // Return response 2 - cq_impl_->SimulateCompletion(true); - // Return response 3 - cq_impl_->SimulateCompletion(false); - // Finish() - cq_impl_->SimulateCompletion(true); - - auto status = samples_future.get(); - EXPECT_THAT(status, - StatusIs(StatusCode::kCancelled, HasSubstr("User cancelled"))); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_bulk_mutator_test.cc b/google/cloud/bigtable/internal/legacy_bulk_mutator_test.cc deleted file mode 100644 index 5674b8aff7390..0000000000000 --- a/google/cloud/bigtable/internal/legacy_bulk_mutator_test.cc +++ /dev/null @@ -1,496 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/bulk_mutator.h" -#include "google/cloud/bigtable/testing/mock_data_client.h" -#include "google/cloud/bigtable/testing/mock_mutate_rows_reader.h" -#include "google/cloud/bigtable/testing/mock_response_reader.h" -#include "google/cloud/testing_util/chrono_literals.h" -#include "google/cloud/testing_util/fake_completion_queue_impl.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; -using ::testing::Return; -using ::google::cloud::testing_util::chrono_literals::operator""_ms; -using ::google::cloud::bigtable::testing::MockMutateRowsReader; - -auto constexpr kTableName = "projects/blah/instances/blah2/tables/table"; - -std::unique_ptr TestContext( - std::string const& app_profile_id = "") { - auto context = std::make_unique(); - bigtable_internal::MakeMetadataUpdatePolicy(kTableName, app_profile_id) - .Setup(*context); - return context; -} - -/// @test Verify that MultipleRowsMutator handles easy cases. -TEST(MultipleRowsMutatorTest, Simple) { - // In this test we create a Mutation for two rows, which succeeds in the - // first RPC request. First create the mutation. - BulkMutation mut( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")})); - - // Prepare the mocks. The mutator should issue a RPC which must return a - // stream of responses, we prepare the stream first because it is easier than - // to create one of the fly. - auto reader = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - { - auto& e = *r->add_entries(); - e.set_index(1); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*reader, Finish()).WillOnce(Return(grpc::Status::OK)); - - // Now prepare the client for the one request. - bigtable::testing::MockDataClient client; - EXPECT_CALL(client, MutateRows) - .WillOnce(reader.release()->MakeMockReturner()); - - auto policy = DefaultIdempotentMutationPolicy(); - bigtable_internal::BulkMutator mutator( - "", kTableName, *policy, std::move(mut), - std::make_shared()); - - EXPECT_TRUE(mutator.HasPendingMutations()); - auto context = TestContext(); - auto status = mutator.MakeOneRequest(client, *context); - EXPECT_TRUE(status.ok()); - auto failures = std::move(mutator).OnRetryDone(); - EXPECT_TRUE(failures.empty()); -} - -/// @test Verify that MultipleRowsMutator uses app_profile_id when set. -TEST(MultipleRowsMutatorTest, BulkApplyAppProfileId) { - namespace btproto = ::google::bigtable::v2; - - // In this test we create a Mutation for two rows, which succeeds in the - // first RPC request. First create the mutation. - BulkMutation mut( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")})); - - // Prepare the mocks. The mutator should issue a RPC which must return a - // stream of responses, we prepare the stream first because it is easier than - // to create one of the fly. - - // Now prepare the client for the one request. - std::string expected_id = "test-id"; - bigtable::testing::MockDataClient client; - EXPECT_CALL(client, MutateRows) - .WillOnce([expected_id](grpc::ClientContext*, - btproto::MutateRowsRequest const& req) { - auto reader = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - { - auto& e = *r->add_entries(); - e.set_index(1); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*reader, Finish()).WillOnce(Return(grpc::Status::OK)); - EXPECT_EQ(expected_id, req.app_profile_id()); - return reader; - }); - - auto policy = DefaultIdempotentMutationPolicy(); - bigtable_internal::BulkMutator mutator( - "test-id", kTableName, *policy, std::move(mut), - std::make_shared()); - - EXPECT_TRUE(mutator.HasPendingMutations()); - auto context = TestContext("test-id"); - auto status = mutator.MakeOneRequest(client, *context); - EXPECT_TRUE(status.ok()); - auto failures = std::move(mutator).OnRetryDone(); - EXPECT_TRUE(failures.empty()); -} - -/// @test Verify that MultipleRowsMutator retries partial failures. -TEST(MultipleRowsMutatorTest, RetryPartialFailure) { - // In this test we create a Mutation for two rows, one of which will fail. - // First create the mutation. - BulkMutation mut( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")})); - - // Prepare the mocks for the request. First create a stream response which - // indicates a partial failure. - - // Setup the client to response with r1 first, and r2 next. - bigtable::testing::MockDataClient client; - EXPECT_CALL(client, MutateRows) - .WillOnce( - [](grpc::ClientContext*, btproto::MutateRowsRequest const& req) { - EXPECT_EQ(kTableName, req.table_name()); - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - // Simulate a partial (and recoverable) failure. - auto& e0 = *r->add_entries(); - e0.set_index(0); - e0.mutable_status()->set_code(grpc::StatusCode::UNAVAILABLE); - auto& e1 = *r->add_entries(); - e1.set_index(1); - e1.mutable_status()->set_code(grpc::StatusCode::OK); - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish).WillOnce(Return(grpc::Status::OK)); - return r1; - }) - .WillOnce( - [](grpc::ClientContext*, btproto::MutateRowsRequest const& req) { - EXPECT_EQ(kTableName, req.table_name()); - // Prepare a second stream response, because the client should retry - // after the partial failure. - auto r2 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r2, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r2, Finish).WillOnce(Return(grpc::Status::OK)); - return r2; - }); - - auto policy = DefaultIdempotentMutationPolicy(); - bigtable_internal::BulkMutator mutator( - "", kTableName, *policy, std::move(mut), - std::make_shared()); - - // This work will be in BulkApply(), but this is the test for BulkMutator in - // isolation, so call MakeOneRequest() twice, for the r1, and the r2 cases. - for (int i = 0; i != 2; ++i) { - EXPECT_TRUE(mutator.HasPendingMutations()); - auto context = TestContext(); - auto status = mutator.MakeOneRequest(client, *context); - EXPECT_TRUE(status.ok()); - } - auto failures = std::move(mutator).OnRetryDone(); - EXPECT_TRUE(failures.empty()); -} - -/// @test Verify that MultipleRowsMutator handles permanent failures. -TEST(MultipleRowsMutatorTest, PermanentFailure) { - // In this test we handle a recoverable and one unrecoverable failures. - // Create a bulk mutation with two SetCell() mutations. - BulkMutation mut( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")})); - - // Make the first RPC return one recoverable and one unrecoverable failures. - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - // Simulate a partial failure, which is recoverable for this first - // element. - auto& e0 = *r->add_entries(); - e0.set_index(0); - e0.mutable_status()->set_code(grpc::StatusCode::UNAVAILABLE); - // Simulate an unrecoverable failure for the second element. - auto& e1 = *r->add_entries(); - e1.set_index(1); - e1.mutable_status()->set_code(grpc::StatusCode::OUT_OF_RANGE); - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish()).WillOnce(Return(grpc::Status::OK)); - - // The BulkMutator should issue a second request, which will return success - // for the remaining mutation. - auto r2 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r2, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r2, Finish()).WillOnce(Return(grpc::Status::OK)); - - bigtable::testing::MockDataClient client; - EXPECT_CALL(client, MutateRows) - .WillOnce(r1.release()->MakeMockReturner()) - .WillOnce(r2.release()->MakeMockReturner()); - - auto policy = DefaultIdempotentMutationPolicy(); - bigtable_internal::BulkMutator mutator( - "", kTableName, *policy, std::move(mut), - std::make_shared()); - - // This work will be in BulkApply(), but this is the test for BulkMutator in - // isolation, so call MakeOneRequest() twice, for the r1, and the r2 cases. - for (int i = 0; i != 2; ++i) { - EXPECT_TRUE(mutator.HasPendingMutations()); - auto context = TestContext(); - auto status = mutator.MakeOneRequest(client, *context); - EXPECT_TRUE(status.ok()); - } - auto failures = std::move(mutator).OnRetryDone(); - ASSERT_EQ(1UL, failures.size()); - EXPECT_EQ(1, failures[0].original_index()); - // EXPECT_EQ("bar", failures[0].mutation().row_key()); - EXPECT_EQ(google::cloud::StatusCode::kOutOfRange, - failures[0].status().code()); -} - -/// @test Verify that MultipleRowsMutator handles a stream with partial results -TEST(MultipleRowsMutatorTest, PartialStream) { - // We are going to test the case where the stream does not contain a response - // for all requests. Create a BulkMutation with two entries. - BulkMutation mut( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")})); - - // This will be the stream returned by the first request. It is missing - // information about one of the mutations. - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - auto& e0 = *r->add_entries(); - e0.set_index(0); - e0.mutable_status()->set_code(grpc::StatusCode::OK); - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish()).WillOnce(Return(grpc::Status::OK)); - - // The BulkMutation should issue a second request, this is the stream returned - // by the second request, which indicates success for the missed mutation - // on r1. - auto r2 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r2, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r2, Finish()).WillOnce(Return(grpc::Status::OK)); - - bigtable::testing::MockDataClient client; - EXPECT_CALL(client, MutateRows) - .WillOnce(r1.release()->MakeMockReturner()) - .WillOnce(r2.release()->MakeMockReturner()); - - auto policy = DefaultIdempotentMutationPolicy(); - bigtable_internal::BulkMutator mutator( - "", kTableName, *policy, std::move(mut), - std::make_shared()); - - // This work will be in BulkApply(), but this is the test for BulkMutator in - // isolation, so call MakeOneRequest() twice: for the r1 and r2 cases. - for (int i = 0; i != 2; ++i) { - EXPECT_TRUE(mutator.HasPendingMutations()); - auto context = TestContext(); - auto status = mutator.MakeOneRequest(client, *context); - EXPECT_TRUE(status.ok()); - } - auto failures = std::move(mutator).OnRetryDone(); - EXPECT_TRUE(failures.empty()); -} - -/// @test Verify that MultipleRowsMutator only retries idempotent mutations -TEST(MultipleRowsMutatorTest, RetryOnlyIdempotent) { - // Create a BulkMutation with a non-idempotent mutation. - BulkMutation mut( - SingleRowMutation("foo", {SetCell("fam", "col", "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}), - SingleRowMutation("baz", {SetCell("fam", "col", "v")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")})); - - // We will setup the mock to return recoverable failures for idempotent - // mutations. - - // Verify that the second response has the right contents. It is easier (and - // more readable) to write these in a separate small lambda expression because - // ASSERT_EQ() has an embedded "return;" in it, which does not play well with - // the rest of the stuff here. - auto expect_r2 = [](btproto::MutateRowsRequest const& r) { - ASSERT_EQ(2, r.entries_size()); - EXPECT_EQ("bar", r.entries(0).row_key()); - }; - bigtable::testing::MockDataClient client; - EXPECT_CALL(client, MutateRows) - .WillOnce([](grpc::ClientContext*, btproto::MutateRowsRequest const& r) { - EXPECT_EQ(4, r.entries_size()); - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - // Simulate recoverable failures for both elements. - auto& e0 = *r->add_entries(); - e0.set_index(0); - e0.mutable_status()->set_code(grpc::StatusCode::UNAVAILABLE); - auto& e1 = *r->add_entries(); - e1.set_index(1); - e1.mutable_status()->set_code(grpc::StatusCode::UNAVAILABLE); - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish).WillOnce(Return(grpc::Status::OK)); - return r1; - }) - .WillOnce([expect_r2](grpc::ClientContext*, - btproto::MutateRowsRequest const& r) { - expect_r2(r); - // The BulkMutator should issue a second request, with only the - // idempotent mutations, make the mocks return success for them. - auto r2 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r2, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r2, Finish).WillOnce(Return(grpc::Status::OK)); - - return r2; - }); - - auto policy = DefaultIdempotentMutationPolicy(); - bigtable_internal::BulkMutator mutator( - "", kTableName, *policy, std::move(mut), - std::make_shared()); - - // This work will be in BulkApply(), but this is the test for BulkMutator in - // isolation, so call MakeOneRequest() twice, for the r1, and the r2 cases. - for (int i = 0; i != 2; ++i) { - EXPECT_TRUE(mutator.HasPendingMutations()); - auto context = TestContext(); - auto status = mutator.MakeOneRequest(client, *context); - EXPECT_TRUE(status.ok()); - } - auto failures = std::move(mutator).OnRetryDone(); - ASSERT_EQ(3UL, failures.size()); - EXPECT_EQ(0, failures[0].original_index()); - // EXPECT_EQ("foo", failures[0].mutation().row_key()); - EXPECT_EQ(google::cloud::StatusCode::kUnavailable, - failures[0].status().code()); - - EXPECT_EQ(2, failures[1].original_index()); - // EXPECT_EQ("baz", failures[1].mutation().row_key()); - EXPECT_EQ(google::cloud::StatusCode::kInternal, failures[1].status().code()); - EXPECT_EQ(google::cloud::StatusCode::kInternal, failures[2].status().code()); -} - -TEST(MultipleRowsMutatorTest, UnconfirmedAreFailed) { - // Make sure that mutations which are not confirmed are reported as UNKNOWN - // with the proper index. - BulkMutation mut(SingleRowMutation("foo", {SetCell("fam", "col", "baz")}), - // this one will be unconfirmed - SingleRowMutation("bar", {SetCell("fam", "col", "qux")}), - SingleRowMutation("baz", {SetCell("fam", "col", "v")})); - - // We will setup the mock to return recoverable failures for idempotent - // mutations. - - // The BulkMutator should not issue a second request because the error is - // PERMISSION_DENIED (not retryable). - - bigtable::testing::MockDataClient client; - EXPECT_CALL(client, MutateRows) - .WillOnce([](grpc::ClientContext*, btproto::MutateRowsRequest const& r) { - EXPECT_EQ(3, r.entries_size()); - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - auto& e0 = *r->add_entries(); - e0.set_index(0); - e0.mutable_status()->set_code(grpc::StatusCode::OK); - auto& e1 = *r->add_entries(); - e1.set_index(2); - e1.mutable_status()->set_code(grpc::StatusCode::OK); - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish) - .WillOnce( - Return(grpc::Status(grpc::StatusCode::PERMISSION_DENIED, ""))); - return r1; - }); - - auto policy = DefaultIdempotentMutationPolicy(); - bigtable_internal::BulkMutator mutator( - "", kTableName, *policy, std::move(mut), - std::make_shared()); - - EXPECT_TRUE(mutator.HasPendingMutations()); - auto context = TestContext(); - auto status = mutator.MakeOneRequest(client, *context); - EXPECT_FALSE(status.ok()); - - auto failures = std::move(mutator).OnRetryDone(); - ASSERT_EQ(1UL, failures.size()); - EXPECT_EQ(1, failures[0].original_index()); - // EXPECT_EQ("bar", failures[0].mutation().row_key()); - EXPECT_EQ(google::cloud::StatusCode::kPermissionDenied, - failures.front().status().code()); -} - -} // anonymous namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_row_reader.cc b/google/cloud/bigtable/internal/legacy_row_reader.cc deleted file mode 100644 index 62eeafff9ca3e..0000000000000 --- a/google/cloud/bigtable/internal/legacy_row_reader.cc +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/legacy_row_reader.h" -#include "google/cloud/bigtable/table.h" -#include "google/cloud/grpc_error_delegate.h" -#include "google/cloud/internal/throw_delegate.h" -#include "google/cloud/log.h" -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -LegacyRowReader::LegacyRowReader( - std::shared_ptr client, std::string table_name, - bigtable::RowSet row_set, std::int64_t rows_limit, bigtable::Filter filter, - std::unique_ptr retry_policy, - std::unique_ptr backoff_policy, - bigtable::MetadataUpdatePolicy metadata_update_policy, - std::unique_ptr parser_factory) - : LegacyRowReader(std::move(client), std::string(""), std::move(table_name), - std::move(row_set), rows_limit, std::move(filter), - std::move(retry_policy), std::move(backoff_policy), - std::move(metadata_update_policy), - std::move(parser_factory)) {} - -LegacyRowReader::LegacyRowReader( - std::shared_ptr client, std::string app_profile_id, - std::string table_name, bigtable::RowSet row_set, std::int64_t rows_limit, - bigtable::Filter filter, - std::unique_ptr retry_policy, - std::unique_ptr backoff_policy, - bigtable::MetadataUpdatePolicy metadata_update_policy, - std::unique_ptr parser_factory) - : client_(std::move(client)), - app_profile_id_(std::move(app_profile_id)), - table_name_(std::move(table_name)), - row_set_(std::move(row_set)), - rows_limit_(rows_limit), - filter_(std::move(filter)), - retry_policy_(std::move(retry_policy)), - backoff_policy_(std::move(backoff_policy)), - metadata_update_policy_(std::move(metadata_update_policy)), - parser_factory_(std::move(parser_factory)) {} - -void LegacyRowReader::MakeRequest() { - response_ = {}; - processed_chunks_count_ = 0; - - google::bigtable::v2::ReadRowsRequest request; - request.set_table_name(table_name_); - request.set_app_profile_id(app_profile_id_); - - auto row_set_proto = row_set_.as_proto(); - request.mutable_rows()->Swap(&row_set_proto); - - auto filter_proto = filter_.as_proto(); - request.mutable_filter()->Swap(&filter_proto); - - if (rows_limit_ != bigtable::RowReader::NO_ROWS_LIMIT) { - request.set_rows_limit(rows_limit_ - rows_count_); - } - - context_ = std::make_unique(); - retry_policy_->Setup(*context_); - backoff_policy_->Setup(*context_); - metadata_update_policy_.Setup(*context_); - stream_ = client_->ReadRows(context_.get(), request); - stream_is_open_ = true; - - parser_ = parser_factory_->Create(false); -} - -bool LegacyRowReader::NextChunk() { - ++processed_chunks_count_; - while (processed_chunks_count_ >= response_.chunks_size()) { - processed_chunks_count_ = 0; - bool response_is_valid = stream_->Read(&response_); - if (!response_is_valid) { - response_ = {}; - return false; - } - if (!response_.last_scanned_row_key().empty()) { - last_read_row_key_ = std::move(*response_.mutable_last_scanned_row_key()); - } - } - return true; -} - -absl::variant LegacyRowReader::Advance() { - if (operation_cancelled_) { - return Status(StatusCode::kCancelled, "Operation cancelled."); - } - while (true) { - auto variant = AdvanceOrFail(); - if (absl::holds_alternative(variant)) { - return absl::get(std::move(variant)); - } - - auto status = absl::get(std::move(variant)); - if (status.ok()) return Status{}; - - // In the unlikely case when we have already reached the requested - // number of rows and still receive an error (the parser can throw - // an error at end of stream for example), there is no need to - // retry and we have no good value for rows_limit anyway. - if (rows_limit_ != bigtable::RowReader::NO_ROWS_LIMIT && - rows_limit_ <= rows_count_) { - return Status{}; - } - - if (!last_read_row_key_.empty()) { - // We've returned some rows and need to make sure we don't - // request them again. - row_set_ = - row_set_.Intersect(bigtable::RowRange::Open(last_read_row_key_, "")); - } - - // If we receive an error, but the retryable set is empty, stop. - if (row_set_.IsEmpty()) return Status{}; - - if (!retry_policy_->OnFailure(status)) return status; - - auto delay = backoff_policy_->OnCompletion(status); - std::this_thread::sleep_for(delay); - - // If we reach this place, we failed and need to restart the call. - MakeRequest(); - } -} - -absl::variant LegacyRowReader::AdvanceOrFail() { - grpc::Status status; - if (!stream_) { - MakeRequest(); - } - while (!parser_->HasNext()) { - if (NextChunk()) { - parser_->HandleChunk( - std::move(*(response_.mutable_chunks(processed_chunks_count_))), - status); - if (!status.ok()) return MakeStatusFromRpcError(status); - continue; - } - - // Here, there are no more chunks to look at. Close the stream, - // finalize the parser and return OK with no rows unless something - // fails during cleanup. - stream_is_open_ = false; - status = stream_->Finish(); - if (!status.ok()) return MakeStatusFromRpcError(status); - parser_->HandleEndOfStream(status); - return MakeStatusFromRpcError(status); - } - - // We have a complete row in the parser. - bigtable::Row parsed_row = parser_->Next(status); - if (!status.ok()) return MakeStatusFromRpcError(status); - - ++rows_count_; - last_read_row_key_ = parsed_row.row_key(); - return parsed_row; -} - -void LegacyRowReader::Cancel() { - operation_cancelled_ = true; - if (!stream_is_open_) return; - context_->TryCancel(); - - // Also drain any data left unread - google::bigtable::v2::ReadRowsResponse response; - while (stream_->Read(&response)) { - } - - stream_is_open_ = false; - (void)stream_->Finish(); // ignore errors -} - -LegacyRowReader::~LegacyRowReader() { - // Make sure we don't leave open streams. - Cancel(); -} - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/legacy_row_reader.h b/google/cloud/bigtable/internal/legacy_row_reader.h deleted file mode 100644 index 3d9acc7fae36f..0000000000000 --- a/google/cloud/bigtable/internal/legacy_row_reader.h +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ROW_READER_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ROW_READER_H - -#include "google/cloud/bigtable/data_client.h" -#include "google/cloud/bigtable/filters.h" -#include "google/cloud/bigtable/internal/readrowsparser.h" -#include "google/cloud/bigtable/internal/row_reader_impl.h" -#include "google/cloud/bigtable/metadata_update_policy.h" -#include "google/cloud/bigtable/row.h" -#include "google/cloud/bigtable/row_set.h" -#include "google/cloud/bigtable/rpc_backoff_policy.h" -#include "google/cloud/bigtable/rpc_retry_policy.h" -#include "google/cloud/bigtable/version.h" -#include "absl/types/variant.h" -#include "google/bigtable/v2/bigtable.grpc.pb.h" -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN - -/** - * `RowReaderImpl` that interacts with the Bigtable service via `DataClient`. - */ -class LegacyRowReader : public RowReaderImpl { - public: - LegacyRowReader(std::shared_ptr client, - std::string table_name, bigtable::RowSet row_set, - std::int64_t rows_limit, bigtable::Filter filter, - std::unique_ptr retry_policy, - std::unique_ptr backoff_policy, - bigtable::MetadataUpdatePolicy metadata_update_policy, - std::unique_ptr - parser_factory); - - LegacyRowReader(std::shared_ptr client, - std::string app_profile_id, std::string table_name, - bigtable::RowSet row_set, std::int64_t rows_limit, - bigtable::Filter filter, - std::unique_ptr retry_policy, - std::unique_ptr backoff_policy, - bigtable::MetadataUpdatePolicy metadata_update_policy, - std::unique_ptr - parser_factory); - - ~LegacyRowReader() override; - - void Cancel() override; - - /** - * Read and parse the next row in the response. - * - * @param row receives the next row on success, and is reset on failure or if - * there are no more rows. - * - * This call possibly blocks waiting for data until a full row is available. - */ - absl::variant Advance() override; - - private: - /// Called by Advance(), does not handle retries. - absl::variant AdvanceOrFail(); - - /** - * Move the `processed_chunks_count_` index to the next chunk, - * reading data if needed. - * - * Returns false if no more chunks are available. - * - * This call is used internally by AdvanceOrFail to prepare data for - * parsing. When it returns true, the value of - * `response_.chunks(processed_chunks_count_)` is valid and holds - * the next chunk to parse. - */ - bool NextChunk(); - - /// Sends the ReadRows request to the stub. - void MakeRequest(); - - std::shared_ptr client_; - std::string app_profile_id_; - std::string table_name_; - bigtable::RowSet row_set_; - std::int64_t rows_limit_; - bigtable::Filter filter_; - std::unique_ptr retry_policy_; - std::unique_ptr backoff_policy_; - bigtable::MetadataUpdatePolicy metadata_update_policy_; - - std::unique_ptr context_; - - std::unique_ptr parser_factory_; - std::unique_ptr parser_; - std::unique_ptr< - grpc::ClientReaderInterface> - stream_; - bool stream_is_open_ = false; - bool operation_cancelled_ = false; - - /// The last received response, chunks are being parsed one by one from it. - google::bigtable::v2::ReadRowsResponse response_; - /// Number of chunks already parsed in response_. - int processed_chunks_count_ = 0; - - /// Number of rows read so far, used to set row_limit in retries. - std::int64_t rows_count_ = 0; - /// Holds the last read row key, for retries. - bigtable::RowKeyType last_read_row_key_; -}; - -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LEGACY_ROW_READER_H diff --git a/google/cloud/bigtable/internal/legacy_row_reader_test.cc b/google/cloud/bigtable/internal/legacy_row_reader_test.cc deleted file mode 100644 index a3dea04f8d84b..0000000000000 --- a/google/cloud/bigtable/internal/legacy_row_reader_test.cc +++ /dev/null @@ -1,871 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/legacy_row_reader.h" -#include "google/cloud/bigtable/row_reader.h" -#include "google/cloud/bigtable/testing/mock_policies.h" -#include "google/cloud/bigtable/testing/mock_read_rows_reader.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/internal/api_client_header.h" -#include "google/cloud/internal/throw_delegate.h" -#include "google/cloud/testing_util/scoped_log.h" -#include "google/cloud/testing_util/status_matchers.h" -#include "google/cloud/testing_util/validate_metadata.h" -#include -#include -#include - -namespace google { -namespace cloud { -namespace bigtable_internal { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -using ::google::bigtable::v2::ReadRowsRequest; -using ::google::bigtable::v2::ReadRowsResponse_CellChunk; -using ::google::cloud::bigtable::Row; -using ::google::cloud::bigtable::testing::MockBackoffPolicy; -using ::google::cloud::bigtable::testing::MockReadRowsReader; -using ::google::cloud::bigtable::testing::MockRetryPolicy; -using ::google::cloud::testing_util::StatusIs; -using ::google::cloud::testing_util::ValidateMetadataFixture; -using ::testing::_; -using ::testing::An; -using ::testing::DoAll; -using ::testing::Eq; -using ::testing::Matcher; -using ::testing::NiceMock; -using ::testing::Property; -using ::testing::Return; -using ::testing::SetArgPointee; -using ::testing::SetArgReferee; - -class ReadRowsParserMock : public bigtable::internal::ReadRowsParser { - public: - explicit ReadRowsParserMock() : ReadRowsParser(false) {} - - MOCK_METHOD(void, HandleChunkHook, - (ReadRowsResponse_CellChunk chunk, grpc::Status& status)); - void HandleChunk(ReadRowsResponse_CellChunk chunk, - grpc::Status& status) override { - HandleChunkHook(chunk, status); - } - - MOCK_METHOD(void, HandleEndOfStreamHook, (grpc::Status & status)); - void HandleEndOfStream(grpc::Status& status) override { - HandleEndOfStreamHook(status); - } - - bool HasNext() const override { return !rows_.empty(); } - - Row Next(grpc::Status&) override { - Row row = rows_.front(); - rows_.pop_front(); - return row; - } - - void SetRows(std::initializer_list l) { - std::transform(l.begin(), l.end(), std::back_inserter(rows_), - [](std::string const& s) -> Row { - return Row(s, std::vector()); - }); - } - - private: - std::deque rows_; -}; - -// Returns a preconfigured set of parsers, so expectations can be set on each. -class ReadRowsParserMockFactory - : public bigtable::internal::ReadRowsParserFactory { - using ParserPtr = std::unique_ptr; - - public: - void AddParser(ParserPtr parser) { parsers_.emplace_back(std::move(parser)); } - - MOCK_METHOD(void, CreateHook, ()); - ParserPtr Create(bool reverse) override { - CreateHook(); - if (parsers_.empty()) { - return std::make_unique(reverse); - } - ParserPtr parser = std::move(parsers_.front()); - parsers_.pop_front(); - return parser; - } - - private: - std::deque parsers_; -}; - -// Match the number of expected row keys in a request in EXPECT_CALL -Matcher RequestWithRowKeysCount(int n) { - return Property( - &ReadRowsRequest::rows, - Property(&google::bigtable::v2::RowSet::row_keys_size, Eq(n))); -} - -// Match the row limit in a request -Matcher RequestWithRowsLimit(std::int64_t n) { - return Property(&ReadRowsRequest::rows_limit, Eq(n)); -} - -class LegacyRowReaderTest : public bigtable::testing::TableTestFixture { - public: - LegacyRowReaderTest() - : TableTestFixture(CompletionQueue{}), - retry_policy_(std::make_unique>()), - backoff_policy_(std::make_unique>()), - metadata_update_policy_(MakeMetadataUpdatePolicy(kTableName, "")), - parser_factory_( - std::make_unique>()) {} - - std::unique_ptr retry_policy_; - std::unique_ptr backoff_policy_; - bigtable::MetadataUpdatePolicy metadata_update_policy_; - std::unique_ptr> parser_factory_; -}; - -TEST_F(LegacyRowReaderTest, EmptyReaderHasNoRows) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish).WillOnce(Return(grpc::Status::OK)); - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - EXPECT_EQ(reader.begin(), reader.end()); -} - -TEST_F(LegacyRowReaderTest, ReadOneRow) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - EXPECT_CALL(*parser, HandleEndOfStreamHook).Times(1); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, ReadOneRowAppProfileId) { - // wrapped in unique_ptr by ReadRows - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - EXPECT_CALL(*parser, HandleEndOfStreamHook).Times(1); - EXPECT_CALL(*client_, ReadRows) - .WillOnce([](grpc::ClientContext* context, ReadRowsRequest const& req) { - ValidateMetadataFixture fixture; - fixture.IsContextMDValid( - *context, "google.bigtable.v2.Bigtable.ReadRows", req, - google::cloud::internal::HandCraftedLibClientHeader()); - EXPECT_EQ("test-app-profile-id", req.app_profile_id()); - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.ReadRows"); - ::testing::InSequence s; - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish).WillOnce(Return(grpc::Status::OK)); - return stream; - }); - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, "test-app-profile-id", kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - MakeMetadataUpdatePolicy(kTableName, "test-app-profile-id"), - std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, StreamIsDrained) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_NE(it, reader.end()); - // Do not finish the iteration. We still expect the stream to be finalized, - // and the previously setup expectations on the mock `stream` check that. -} - -TEST_F(LegacyRowReaderTest, RetryThenSuccess) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, "retry"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - // the stub will free it - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*client_, ReadRows).WillOnce(stream_retry->MakeMockReturner()); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, NoRetryOnPermanentError) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, "retry"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(false)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())).Times(0); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - EXPECT_THAT(*it, StatusIs(StatusCode::kInternal)); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, RetrySkipsAlreadyReadRows) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - { - ::testing::InSequence s; - // As a baseline, check we have two rows in the initial request - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(2))) - .WillOnce(stream->MakeMockReturner()); - - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, "retry"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - // the stub will free it - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - // First row should be removed from the retried request, leaving one row - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(1))) - .WillOnce(stream_retry->MakeMockReturner()); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet("r1", "r2"), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, RetrySkipsAlreadyScannedRows) { - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - google::bigtable::v2::ReadRowsResponse response; - response.set_last_scanned_row_key("r2"); - { - ::testing::InSequence s; - // We start our call with 3 rows in the set: "r1", "r2", "r3". - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(3))) - .WillOnce(stream->MakeMockReturner()); - - // The mock `parser` will return "r1". Next, simulate the server returning - // an empty chunk with `last_scanned_row_key` set to "r2". - EXPECT_CALL(*stream, Read) - .WillOnce(DoAll(SetArgPointee<0>(response), Return(true))); - - // The stream fails with a retry-able error - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, "retry"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - - // We retry the remaining rows. We have "r1" returned, but the service has - // also told us that "r2" was scanned. This means there is only one row - // remaining to read: "r3". - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(1))) - .WillOnce(stream_retry->MakeMockReturner()); - - // End the stream to clean up the test - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet("r1", "r2", "r3"), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, FailedParseIsRetried) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - auto response = bigtable::testing::ReadRowsResponseFromString("chunks {}"); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read) - .WillOnce(DoAll(SetArgPointee<0>(response), Return(true))); - EXPECT_CALL(*parser, HandleChunkHook) - .WillOnce(SetArgReferee<1>( - grpc::Status(grpc::StatusCode::INTERNAL, "parser exception"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - // the stub will free it - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*client_, ReadRows).WillOnce(stream_retry->MakeMockReturner()); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, FailedParseSkipsAlreadyReadRows) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - { - ::testing::InSequence s; - // As a baseline, check we have two rows in the initial request - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(2))) - .WillOnce(stream->MakeMockReturner()); - - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - EXPECT_CALL(*parser, HandleEndOfStreamHook) - .WillOnce(SetArgReferee<0>( - grpc::Status(grpc::StatusCode::INTERNAL, "InternalError"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - // the stub will free it - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - // First row should be removed from the retried request, leaving one row - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(1))) - .WillOnce(stream_retry->MakeMockReturner()); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet("r1", "r2"), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, FailedParseSkipsAlreadyScannedRows) { - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - google::bigtable::v2::ReadRowsResponse response; - response.set_last_scanned_row_key("r2"); - { - ::testing::InSequence s; - // We start our call with 3 rows in the set: "r1", "r2", "r3". - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(3))) - .WillOnce(stream->MakeMockReturner()); - - // The mock `parser` will return "r1". Next, simulate the server returning - // an empty chunk with `last_scanned_row_key` set to "r2". - EXPECT_CALL(*stream, Read) - .WillOnce(DoAll(SetArgPointee<0>(response), Return(true))); - - // The stream fails with a retry-able error - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - EXPECT_CALL(*parser, HandleEndOfStreamHook) - .WillOnce(SetArgReferee<0>( - grpc::Status(grpc::StatusCode::INTERNAL, "InternalError"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - - // We retry the remaining rows. We have "r1" returned, but the service has - // also told us that "r2" was scanned. This means there is only one row - // remaining to read: "r3". - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowKeysCount(1))) - .WillOnce(stream_retry->MakeMockReturner()); - - // End the stream to clean up the test - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet("r1", "r2", "r3"), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, FailedParseWithPermanentError) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - { - ::testing::InSequence s; - - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - EXPECT_CALL(*parser, HandleEndOfStreamHook) - .WillOnce(SetArgReferee<0>( - grpc::Status(grpc::StatusCode::INTERNAL, "InternalError"))); - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(false)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())).Times(0); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - EXPECT_THAT(*it, StatusIs(StatusCode::kInternal)); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, NoRetryOnEmptyRowSet) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r2"}); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, - "this exception must be ignored"))); - - // Note there is no expectation of a new connection, because the - // set of rows to read should become empty after reading "r2" and - // intersecting the requested ["r1", "r2"] with ("r2", "") for the - // retry. - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, - bigtable::RowSet(bigtable::RowRange::Closed("r1", "r2")), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r2"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, RowLimitIsSent) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowsLimit(442))) - .WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), 442, - bigtable::Filter::PassAllFilter(), std::move(retry_policy_), - std::move(backoff_policy_), metadata_update_policy_, - std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_EQ(it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, RowLimitIsDecreasedOnRetry) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowsLimit(42))) - .WillOnce(stream->MakeMockReturner()); - - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, "retry"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - // the stub will free it - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - // 41 instead of 42 - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowsLimit(41))) - .WillOnce(stream_retry->MakeMockReturner()); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), 42, - bigtable::Filter::PassAllFilter(), std::move(retry_policy_), - std::move(backoff_policy_), metadata_update_policy_, - std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, NoRetryIfRowLimitIsReached) { - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows(_, RequestWithRowsLimit(1))) - .WillOnce(stream->MakeMockReturner()); - - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, - "this exception must be ignored"))); - - // Note there is no expectation of a new connection, because the - // row limit reaches zero. - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), 1, - bigtable::Filter::PassAllFilter(), std::move(retry_policy_), - std::move(backoff_policy_), metadata_update_policy_, - std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, CancelDrainsStream) { - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_NE(it, reader.end()); - // Manually cancel the call. - reader.Cancel(); - it = reader.begin(); - EXPECT_NE(it, reader.end()); - EXPECT_THAT(*it, StatusIs(StatusCode::kCancelled)); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, CancelBeforeBegin) { - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - // Manually cancel the call before a stream was created. - reader.Cancel(); - reader.begin(); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - EXPECT_THAT(*it, StatusIs(StatusCode::kCancelled)); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(LegacyRowReaderTest, ConstructorDoesNotCallRpc) { - // The RowReader constructor/destructor by themselves should not - // invoke the RPC or create parsers (the latter restriction because - // parsers are per-connection and non-reusable). - EXPECT_CALL(*client_, ReadRows).Times(0); - EXPECT_CALL(*parser_factory_, CreateHook()).Times(0); - - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); -} - -TEST_F(LegacyRowReaderTest, RetryUsesNewContext) { - // Every retry should use a new ClientContext object. - // wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto parser = std::make_unique(); - parser->SetRows({"r1"}); - - void* previous_context = nullptr; - EXPECT_CALL(*retry_policy_, Setup) - .Times(2) - .WillRepeatedly([&previous_context](grpc::ClientContext& context) { - // This is a big hack, we want to make sure the context is new, - // but there is no easy way to check that, so we compare addresses. - EXPECT_NE(previous_context, &context); - previous_context = &context; - }); - - { - ::testing::InSequence s; - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::INTERNAL, "retry"))); - - EXPECT_CALL(*retry_policy_, OnFailure(An())) - .WillOnce(Return(true)); - EXPECT_CALL(*backoff_policy_, OnCompletion(An())) - .WillOnce(Return(std::chrono::milliseconds(0))); - - // the stub will free it - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*client_, ReadRows).WillOnce(stream_retry->MakeMockReturner()); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(true)); - EXPECT_CALL(*stream_retry, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - } - - parser_factory_->AddParser(std::move(parser)); - auto impl = std::make_shared( - client_, kTableName, bigtable::RowSet(), - bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter(), - std::move(retry_policy_), std::move(backoff_policy_), - metadata_update_policy_, std::move(parser_factory_)); - auto reader = MakeRowReader(std::move(impl)); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -} // anonymous namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable_internal -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/logging_data_client.cc b/google/cloud/bigtable/internal/logging_data_client.cc deleted file mode 100644 index cd94b131cd010..0000000000000 --- a/google/cloud/bigtable/internal/logging_data_client.cc +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/logging_data_client.h" -#include "google/cloud/bigtable/internal/common_client.h" -#include "google/cloud/internal/debug_string_protobuf.h" -#include "google/cloud/internal/log_wrapper.h" -#include "google/cloud/log.h" -#include "google/cloud/tracing_options.h" -#include "google/longrunning/operations.grpc.pb.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace internal { -namespace { - -using ::google::cloud::internal::DebugString; -using ::google::cloud::internal::IsUniquePtr; - -template , - std::enable_if_t::value, int> = 0> -Result LogWrapper(Functor&& functor, grpc::ClientContext* context, - Request const& request, Response* response, char const* where, - TracingOptions const& options) { - GCP_LOG(DEBUG) << where << "() << " << DebugString(request, options); - auto status = functor(context, request, response); - if (!status.ok()) { - GCP_LOG(DEBUG) << where << "() >> status=" - << DebugString(MakeStatusFromRpcError(status), options); - } else { - GCP_LOG(DEBUG) << where - << "() >> response=" << DebugString(*response, options); - } - return status; -} - -template , - std::enable_if_t::value, int> = 0> -Result LogWrapper(Functor&& functor, grpc::ClientContext* context, - Request const& request, char const* where, - TracingOptions const& options) { - GCP_LOG(DEBUG) << where << "() << " << DebugString(request, options); - auto response = functor(context, request); - GCP_LOG(DEBUG) << where << "() >> " << (response ? "not null" : "null") - << " stream"; - return response; -} - -template < - typename Functor, typename Request, - typename Result = google::cloud::internal::invoke_result_t< - Functor, grpc::ClientContext*, Request const&, grpc::CompletionQueue*>, - std::enable_if_t::value, int> = 0> -Result LogWrapper(Functor&& functor, grpc::ClientContext* context, - Request const& request, grpc::CompletionQueue* cq, - char const* where, TracingOptions const& options) { - GCP_LOG(DEBUG) << where << "() << " << DebugString(request, options); - auto response = functor(context, request, cq); - GCP_LOG(DEBUG) << where << "() >> " << (response ? "not null" : "null") - << " async response reader"; - return response; -} - -} // namespace - -namespace btproto = ::google::bigtable::v2; - -grpc::Status LoggingDataClient::MutateRow( - grpc::ClientContext* context, btproto::MutateRowRequest const& request, - btproto::MutateRowResponse* response) { - return LogWrapper( - [this](grpc::ClientContext* context, - btproto::MutateRowRequest const& request, - btproto::MutateRowResponse* response) { - return child_->MutateRow(context, request, response); - }, - context, request, response, __func__, tracing_options_); -} - -std::unique_ptr< - grpc::ClientAsyncResponseReaderInterface> -LoggingDataClient::AsyncMutateRow(grpc::ClientContext* context, - btproto::MutateRowRequest const& request, - grpc::CompletionQueue* cq) { - return child_->AsyncMutateRow(context, request, cq); -} - -grpc::Status LoggingDataClient::CheckAndMutateRow( - grpc::ClientContext* context, - btproto::CheckAndMutateRowRequest const& request, - btproto::CheckAndMutateRowResponse* response) { - return LogWrapper( - [this](grpc::ClientContext* context, - btproto::CheckAndMutateRowRequest const& request, - btproto::CheckAndMutateRowResponse* response) { - return child_->CheckAndMutateRow(context, request, response); - }, - context, request, response, __func__, tracing_options_); -} - -std::unique_ptr> -LoggingDataClient::AsyncCheckAndMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - grpc::CompletionQueue* cq) { - return child_->AsyncCheckAndMutateRow(context, request, cq); -} - -grpc::Status LoggingDataClient::ReadModifyWriteRow( - grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - btproto::ReadModifyWriteRowResponse* response) { - return LogWrapper( - [this](grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - btproto::ReadModifyWriteRowResponse* response) { - return child_->ReadModifyWriteRow(context, request, response); - }, - context, request, response, __func__, tracing_options_); -} - -std::unique_ptr> -LoggingDataClient::AsyncReadModifyWriteRow( - grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - grpc::CompletionQueue* cq) { - return child_->AsyncReadModifyWriteRow(context, request, cq); -} - -std::unique_ptr> -LoggingDataClient::ReadRows(grpc::ClientContext* context, - btproto::ReadRowsRequest const& request) { - return LogWrapper( - [this](grpc::ClientContext* context, - btproto::ReadRowsRequest const& request) { - return child_->ReadRows(context, request); - }, - context, request, __func__, tracing_options_); -} - -std::unique_ptr> -LoggingDataClient::AsyncReadRows( - grpc::ClientContext* context, - google::bigtable::v2::ReadRowsRequest const& request, - grpc::CompletionQueue* cq, void* tag) { - return child_->AsyncReadRows(context, request, cq, tag); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::ReadRowsResponse>> -LoggingDataClient::PrepareAsyncReadRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::ReadRowsRequest const& request, - ::grpc::CompletionQueue* cq) { - return child_->PrepareAsyncReadRows(context, request, cq); -} - -std::unique_ptr> -LoggingDataClient::SampleRowKeys(grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request) { - return LogWrapper( - [this](grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request) { - return child_->SampleRowKeys(context, request); - }, - context, request, __func__, tracing_options_); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> -LoggingDataClient::AsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) { - return child_->AsyncSampleRowKeys(context, request, cq, tag); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> -LoggingDataClient::PrepareAsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq) { - return child_->PrepareAsyncSampleRowKeys(context, request, cq); -} - -std::unique_ptr> -LoggingDataClient::MutateRows(grpc::ClientContext* context, - btproto::MutateRowsRequest const& request) { - return LogWrapper( - [this](grpc::ClientContext* context, - btproto::MutateRowsRequest const& request) { - return child_->MutateRows(context, request); - }, - context, request, __func__, tracing_options_); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> -LoggingDataClient::AsyncMutateRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) { - return child_->AsyncMutateRows(context, request, cq, tag); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> -LoggingDataClient::PrepareAsyncMutateRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq) { - return child_->PrepareAsyncMutateRows(context, request, cq); -} - -} // namespace internal -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/internal/logging_data_client.h b/google/cloud/bigtable/internal/logging_data_client.h deleted file mode 100644 index a31961cdebf22..0000000000000 --- a/google/cloud/bigtable/internal/logging_data_client.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LOGGING_DATA_CLIENT_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LOGGING_DATA_CLIENT_H - -#include "google/cloud/bigtable/data_client.h" -#include -#include -// TODO(#8800) - delete this class when deprecation is complete -#include "google/cloud/internal/disable_deprecation_warnings.inc" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace internal { - -namespace btproto = ::google::bigtable::v2; - -/** - * Implement a logging DataClient. - * - * This implementation does not support multiple threads, or refresh - * authorization tokens. In other words, it is extremely bare bones. - */ -class LoggingDataClient : public DataClient { - public: - LoggingDataClient(std::shared_ptr child, - google::cloud::TracingOptions options) - : child_(std::move(child)), tracing_options_(std::move(options)) {} - - std::string const& project_id() const override { - return child_->project_id(); - } - - std::string const& instance_id() const override { - return child_->instance_id(); - } - - std::shared_ptr Channel() override { - return child_->Channel(); - } - - void reset() override { child_->reset(); } - - grpc::Status MutateRow(grpc::ClientContext* context, - btproto::MutateRowRequest const& request, - btproto::MutateRowResponse* response) override; - - std::unique_ptr< - grpc::ClientAsyncResponseReaderInterface> - AsyncMutateRow(grpc::ClientContext* context, - btproto::MutateRowRequest const& request, - grpc::CompletionQueue* cq) override; - - grpc::Status CheckAndMutateRow( - grpc::ClientContext* context, - btproto::CheckAndMutateRowRequest const& request, - btproto::CheckAndMutateRowResponse* response) override; - - std::unique_ptr> - AsyncCheckAndMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - grpc::CompletionQueue* cq) override; - - grpc::Status ReadModifyWriteRow( - grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - btproto::ReadModifyWriteRowResponse* response) override; - - std::unique_ptr> - AsyncReadModifyWriteRow( - grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - grpc::CompletionQueue* cq) override; - - std::unique_ptr> - ReadRows(grpc::ClientContext* context, - btproto::ReadRowsRequest const& request) override; - - std::unique_ptr> - AsyncReadRows(grpc::ClientContext* context, - google::bigtable::v2::ReadRowsRequest const& request, - grpc::CompletionQueue* cq, void* tag) override; - - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::ReadRowsResponse>> - PrepareAsyncReadRows(::grpc::ClientContext* context, - ::google::bigtable::v2::ReadRowsRequest const& request, - ::grpc::CompletionQueue* cq) override; - - std::unique_ptr> - SampleRowKeys(grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request) override; - - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> - AsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) override; - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> - PrepareAsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq) override; - - std::unique_ptr> - MutateRows(grpc::ClientContext* context, - btproto::MutateRowsRequest const& request) override; - - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> - AsyncMutateRows(::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) override; - - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> - PrepareAsyncMutateRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq) override; - - private: - google::cloud::BackgroundThreadsFactory BackgroundThreadsFactory() override { - return child_->BackgroundThreadsFactory(); - } - - std::shared_ptr child_; - google::cloud::TracingOptions tracing_options_; -}; - -} // namespace internal -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google - -// TODO(#8800) - delete this class when deprecation is complete -#include "google/cloud/internal/diagnostics_pop.inc" - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_LOGGING_DATA_CLIENT_H diff --git a/google/cloud/bigtable/internal/logging_data_client_test.cc b/google/cloud/bigtable/internal/logging_data_client_test.cc deleted file mode 100644 index 23177906ab7fb..0000000000000 --- a/google/cloud/bigtable/internal/logging_data_client_test.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/internal/logging_data_client.h" -#include "google/cloud/bigtable/data_client.h" -#include "google/cloud/bigtable/testing/mock_data_client.h" -#include "google/cloud/testing_util/scoped_log.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -using ::testing::Contains; -using ::testing::HasSubstr; -using ::testing::Return; - -namespace btproto = ::google::bigtable::v2; - -class LoggingDataClientTest : public ::testing::Test { - protected: - static Status TransientError() { - return Status(StatusCode::kUnavailable, "try-again"); - } - - testing_util::ScopedLog log_; -}; - -TEST_F(LoggingDataClientTest, MutateRow) { - auto mock = std::make_shared(); - - EXPECT_CALL(*mock, MutateRow).WillOnce(Return(grpc::Status())); - - internal::LoggingDataClient stub( - mock, TracingOptions{}.SetOptions("single_line_mode")); - - grpc::ClientContext context; - btproto::MutateRowRequest request; - btproto::MutateRowResponse response; - - auto status = stub.MutateRow(&context, request, &response); - - EXPECT_TRUE(status.ok()); - EXPECT_THAT(log_.ExtractLines(), Contains(HasSubstr("MutateRow"))); -} - -TEST_F(LoggingDataClientTest, CheckAndMutateRow) { - auto mock = std::make_shared(); - - EXPECT_CALL(*mock, CheckAndMutateRow).WillOnce(Return(grpc::Status())); - - internal::LoggingDataClient stub( - mock, TracingOptions{}.SetOptions("single_line_mode")); - - grpc::ClientContext context; - btproto::CheckAndMutateRowRequest request; - btproto::CheckAndMutateRowResponse response; - - auto status = stub.CheckAndMutateRow(&context, request, &response); - - EXPECT_TRUE(status.ok()); - EXPECT_THAT(log_.ExtractLines(), Contains(HasSubstr("CheckAndMutateRow"))); -} - -TEST_F(LoggingDataClientTest, ReadModifyWriteRow) { - auto mock = std::make_shared(); - - EXPECT_CALL(*mock, ReadModifyWriteRow).WillOnce(Return(grpc::Status())); - - internal::LoggingDataClient stub( - mock, TracingOptions{}.SetOptions("single_line_mode")); - - grpc::ClientContext context; - btproto::ReadModifyWriteRowRequest request; - btproto::ReadModifyWriteRowResponse response; - - auto status = stub.ReadModifyWriteRow(&context, request, &response); - - EXPECT_TRUE(status.ok()); - EXPECT_THAT(log_.ExtractLines(), Contains(HasSubstr("ReadModifyWriteRow"))); -} - -TEST_F(LoggingDataClientTest, ReadRows) { - auto mock = std::make_shared(); - - EXPECT_CALL(*mock, ReadRows) - .WillOnce([](grpc::ClientContext*, btproto::ReadRowsRequest const&) { - return std::unique_ptr< - grpc::ClientReaderInterface>{}; - }); - - internal::LoggingDataClient stub( - mock, TracingOptions{}.SetOptions("single_line_mode")); - - grpc::ClientContext context; - btproto::ReadRowsRequest request; - - stub.ReadRows(&context, request); - - EXPECT_THAT(log_.ExtractLines(), Contains(HasSubstr("ReadRows"))); -} - -TEST_F(LoggingDataClientTest, SampleRowKeys) { - auto mock = std::make_shared(); - - EXPECT_CALL(*mock, SampleRowKeys) - .WillOnce([](grpc::ClientContext*, btproto::SampleRowKeysRequest const&) { - return std::unique_ptr< - grpc::ClientReaderInterface>{}; - }); - - internal::LoggingDataClient stub( - mock, TracingOptions{}.SetOptions("single_line_mode")); - - grpc::ClientContext context; - btproto::SampleRowKeysRequest request; - - stub.SampleRowKeys(&context, request); - - EXPECT_THAT(log_.ExtractLines(), Contains(HasSubstr("SampleRowKeys"))); -} - -TEST_F(LoggingDataClientTest, MutateRows) { - auto mock = std::make_shared(); - - EXPECT_CALL(*mock, MutateRows) - .WillOnce([](grpc::ClientContext*, btproto::MutateRowsRequest const&) { - return std::unique_ptr< - grpc::ClientReaderInterface>{}; - }); - - internal::LoggingDataClient stub( - mock, TracingOptions{}.SetOptions("single_line_mode")); - - grpc::ClientContext context; - btproto::MutateRowsRequest request; - - stub.MutateRows(&context, request); - - EXPECT_THAT(log_.ExtractLines(), Contains(HasSubstr("MutateRows"))); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/legacy_table_test.cc b/google/cloud/bigtable/legacy_table_test.cc deleted file mode 100644 index 7a5392d530945..0000000000000 --- a/google/cloud/bigtable/legacy_table_test.cc +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/mock_async_failing_rpc_factory.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/internal/background_threads_impl.h" -#include "google/cloud/testing_util/fake_completion_queue_impl.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; -using ::google::cloud::testing_util::FakeCompletionQueueImpl; -using ::google::cloud::testing_util::StatusIs; -using ::testing::HasSubstr; -using ::testing::MockFunction; - -Options NonEmptyOptions() { - struct TestOption { - using Type = bool; - }; - return Options{}.set(true); -} - -/// Define types and functions used in the tests. -class TableTest : public ::google::cloud::bigtable::testing::TableTestFixture { - public: - TableTest() : TableTestFixture(CompletionQueue{}) {} -}; - -TEST_F(TableTest, ClientProjectId) { - EXPECT_EQ(kProjectId, client_->project_id()); -} - -TEST_F(TableTest, ClientInstanceId) { - EXPECT_EQ(kInstanceId, client_->instance_id()); -} - -TEST_F(TableTest, StandaloneInstanceName) { - EXPECT_EQ(kInstanceName, InstanceName(client_)); -} - -TEST_F(TableTest, StandaloneTableName) { - EXPECT_EQ(kTableName, TableName(client_, kTableId)); -} - -TEST_F(TableTest, TableName) { EXPECT_EQ(kTableName, table_.table_name()); } - -TEST_F(TableTest, WithNewTarget) { - Table table(client_, "original-profile", kTableId); - EXPECT_EQ(table.project_id(), kProjectId); - EXPECT_EQ(table.instance_id(), kInstanceId); - EXPECT_EQ(table.table_id(), kTableId); - EXPECT_EQ(table.table_name(), TableName(kProjectId, kInstanceId, kTableId)); - EXPECT_EQ(table.app_profile_id(), "original-profile"); - - std::string const other_project_id = "other-project"; - std::string const other_instance_id = "other-instance"; - std::string const other_table_id = "other-table"; - auto other_table = - table.WithNewTarget(other_project_id, other_instance_id, other_table_id); - - EXPECT_EQ(other_table.project_id(), other_project_id); - EXPECT_EQ(other_table.instance_id(), other_instance_id); - EXPECT_EQ(other_table.table_id(), other_table_id); - EXPECT_EQ(other_table.table_name(), - TableName(other_project_id, other_instance_id, other_table_id)); - EXPECT_EQ(other_table.app_profile_id(), "original-profile"); -} - -TEST_F(TableTest, WithNewTargetProfile) { - Table table(client_, "original-profile", kTableId); - EXPECT_EQ(table.project_id(), kProjectId); - EXPECT_EQ(table.instance_id(), kInstanceId); - EXPECT_EQ(table.table_id(), kTableId); - EXPECT_EQ(table.table_name(), TableName(kProjectId, kInstanceId, kTableId)); - EXPECT_EQ(table.app_profile_id(), "original-profile"); - - std::string const other_project_id = "other-project"; - std::string const other_instance_id = "other-instance"; - std::string const other_table_id = "other-table"; - std::string const other_profile_id = "other-profile"; - auto other_table = table.WithNewTarget(other_project_id, other_instance_id, - other_profile_id, other_table_id); - - EXPECT_EQ(other_table.project_id(), other_project_id); - EXPECT_EQ(other_table.instance_id(), other_instance_id); - EXPECT_EQ(other_table.table_id(), other_table_id); - EXPECT_EQ(other_table.table_name(), - TableName(other_project_id, other_instance_id, other_table_id)); - EXPECT_EQ(other_table.app_profile_id(), other_profile_id); -} - -TEST_F(TableTest, TableConstructor) { - std::string const other_table_id = "my-table"; - std::string const other_table_name = TableName(client_, other_table_id); - Table table(client_, other_table_id); - EXPECT_EQ(other_table_name, table.table_name()); -} - -TEST_F(TableTest, CopyConstructor) { - Table source(client_, "my-table"); - std::string const& expected = source.table_name(); - // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) - Table copy(source); - EXPECT_EQ(expected, copy.table_name()); -} - -TEST_F(TableTest, MoveConstructor) { - Table source(client_, "my-table"); - std::string expected = source.table_name(); - Table copy(std::move(source)); - EXPECT_EQ(expected, copy.table_name()); -} - -TEST_F(TableTest, CopyAssignment) { - Table source(client_, "my-table"); - std::string const& expected = source.table_name(); - Table dest(client_, "another-table"); - dest = source; - EXPECT_EQ(expected, dest.table_name()); -} - -TEST_F(TableTest, MoveAssignment) { - Table source(client_, "my-table"); - std::string expected = source.table_name(); - Table dest(client_, "another-table"); - dest = std::move(source); - EXPECT_EQ(expected, dest.table_name()); -} - -TEST_F(TableTest, ChangeOnePolicy) { - Table table(client_, "some-table", AlwaysRetryMutationPolicy()); - EXPECT_EQ("", table.app_profile_id()); - EXPECT_THAT(table.table_name(), HasSubstr("some-table")); -} - -TEST_F(TableTest, ChangePolicies) { - Table table(client_, "some-table", AlwaysRetryMutationPolicy(), - LimitedErrorCountRetryPolicy(42)); - EXPECT_EQ("", table.app_profile_id()); - EXPECT_THAT(table.table_name(), HasSubstr("some-table")); -} - -TEST_F(TableTest, ConstructorWithAppProfileAndPolicies) { - Table table(client_, "test-profile-id", "some-table", - AlwaysRetryMutationPolicy(), LimitedErrorCountRetryPolicy(42)); - EXPECT_EQ("test-profile-id", table.app_profile_id()); - EXPECT_THAT(table.table_name(), HasSubstr("some-table")); -} - -std::string const kProjectId = "the-project"; -std::string const kInstanceId = "the-instance"; -std::string const kTableId = "the-table"; - -class ValidContextMdAsyncTest : public ::testing::Test { - public: - ValidContextMdAsyncTest() - : cq_impl_(new FakeCompletionQueueImpl), - cq_(cq_impl_), - client_(new ::google::cloud::bigtable::testing::MockDataClient( - Options{}.set(cq_))) { - EXPECT_CALL(*client_, project_id()) - .WillRepeatedly(::testing::ReturnRef(kProjectId)); - EXPECT_CALL(*client_, instance_id()) - .WillRepeatedly(::testing::ReturnRef(kInstanceId)); - table_ = std::make_unique(client_, kTableId); - } - - protected: - template - void FinishTest( - ::google::cloud::future> res_future) { - EXPECT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); - EXPECT_EQ(0U, cq_impl_->size()); - auto res = res_future.get(); - EXPECT_FALSE(res); - EXPECT_EQ(::google::cloud::StatusCode::kPermissionDenied, - res.status().code()); - } - - void FinishTest(::google::cloud::future res_future) { - EXPECT_EQ(1U, cq_impl_->size()); - cq_impl_->SimulateCompletion(true); - EXPECT_EQ(0U, cq_impl_->size()); - auto res = res_future.get(); - EXPECT_EQ(::google::cloud::StatusCode::kPermissionDenied, res.code()); - } - - std::shared_ptr cq_impl_; - CompletionQueue cq_; - std::shared_ptr client_; - std::unique_ptr
table_; -}; - -TEST_F(ValidContextMdAsyncTest, AsyncApply) { - testing::MockAsyncFailingRpcFactory - rpc_factory; - EXPECT_CALL(*client_, AsyncMutateRow) - .WillOnce(rpc_factory.Create( - R"""( - table_name: "projects/the-project/instances/the-instance/tables/the-table" - row_key: "row_key" - mutations: { delete_from_row { } } - )""", - "google.bigtable.v2.Bigtable.MutateRow")); - FinishTest(table_->AsyncApply(SingleRowMutation("row_key", DeleteFromRow()))); -} - -TEST_F(ValidContextMdAsyncTest, AsyncCheckAndMutateRow) { - testing::MockAsyncFailingRpcFactory - rpc_factory; - EXPECT_CALL(*client_, AsyncCheckAndMutateRow) - .WillOnce(rpc_factory.Create( - R"""( - table_name: "projects/the-project/instances/the-instance/tables/the-table" - row_key: "row_key" - true_mutations: { delete_from_row { } } - predicate_filter: { pass_all_filter: true } - )""", - "google.bigtable.v2.Bigtable.CheckAndMutateRow")); - FinishTest(table_->AsyncCheckAndMutateRow("row_key", Filter::PassAllFilter(), - {DeleteFromRow()}, {})); -} - -TEST_F(ValidContextMdAsyncTest, AsyncReadModifyWriteRow) { - testing::MockAsyncFailingRpcFactory - rpc_factory; - EXPECT_CALL(*client_, AsyncReadModifyWriteRow) - .WillOnce(rpc_factory.Create( - R"""( - table_name: "projects/the-project/instances/the-instance/tables/the-table" - row_key: "row_key" - rules: { - family_name: "fam" - column_qualifier: "counter" - increment_amount: 1 - } - rules: { - family_name: "fam" - column_qualifier: "list" - append_value: ";element" - } - )""", - "google.bigtable.v2.Bigtable.ReadModifyWriteRow")); - FinishTest(table_->AsyncReadModifyWriteRow( - "row_key", ReadModifyWriteRule::IncrementAmount("fam", "counter", 1), - ReadModifyWriteRule::AppendValue("fam", "list", ";element"))); -} - -TEST_F(TableTest, ApplyWithOptions) { - Table table(client_, kTableId); - auto status = table.Apply(SingleRowMutation("row"), NonEmptyOptions()); - EXPECT_THAT(status, StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, AsyncApplyWithOptions) { - Table table(client_, kTableId); - auto status = table.AsyncApply(SingleRowMutation("row"), NonEmptyOptions()); - EXPECT_THAT(status.get(), StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, BulkApplyWithOptions) { - Table table(client_, kTableId); - auto bulk = BulkMutation(SingleRowMutation("r1"), SingleRowMutation("r2")); - auto failed = table.BulkApply(bulk, NonEmptyOptions()); - ASSERT_EQ(2, failed.size()); - EXPECT_EQ(0, failed[0].original_index()); - EXPECT_THAT(failed[0].status(), StatusIs(StatusCode::kInvalidArgument)); - EXPECT_EQ(1, failed[1].original_index()); - EXPECT_THAT(failed[1].status(), StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, AsyncBulkApplyWithOptions) { - Table table(client_, kTableId); - auto bulk = BulkMutation(SingleRowMutation("r1"), SingleRowMutation("r2")); - auto failed = table.AsyncBulkApply(bulk, NonEmptyOptions()).get(); - ASSERT_EQ(2, failed.size()); - EXPECT_EQ(0, failed[0].original_index()); - EXPECT_THAT(failed[0].status(), StatusIs(StatusCode::kInvalidArgument)); - EXPECT_EQ(1, failed[1].original_index()); - EXPECT_THAT(failed[1].status(), StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, ReadRowsWithOptions) { - Table table(client_, kTableId); - auto reader = - table.ReadRows(RowSet(), Filter::PassAllFilter(), NonEmptyOptions()); - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - EXPECT_THAT(*it, StatusIs(StatusCode::kInvalidArgument)); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(TableTest, ReadRowsWithLimitWithOptions) { - Table table(client_, kTableId); - auto reader = - table.ReadRows(RowSet(), 1, Filter::PassAllFilter(), NonEmptyOptions()); - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - EXPECT_THAT(*it, StatusIs(StatusCode::kInvalidArgument)); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(TableTest, ReadRowWithOptions) { - Table table(client_, kTableId); - auto row = table.ReadRow("row", Filter::PassAllFilter(), NonEmptyOptions()); - EXPECT_THAT(row, StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, AsyncReadRowWithOptions) { - Table table(client_, kTableId); - auto row = - table.AsyncReadRow("row", Filter::PassAllFilter(), NonEmptyOptions()); - EXPECT_THAT(row.get(), StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, CheckAndMutateRowWithOptions) { - Table table(client_, kTableId); - auto branch = table.CheckAndMutateRow("row", Filter::PassAllFilter(), {}, {}, - NonEmptyOptions()); - EXPECT_THAT(branch, StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, AsyncCheckAndMutateRowWithOptions) { - Table table(client_, kTableId); - auto branch = table.AsyncCheckAndMutateRow("row", Filter::PassAllFilter(), {}, - {}, NonEmptyOptions()); - EXPECT_THAT(branch.get(), StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, SampleRowsWithOptions) { - Table table(client_, kTableId); - auto rows = table.SampleRows(NonEmptyOptions()); - EXPECT_THAT(rows, StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, AsyncSampleRowsWithOptions) { - Table table(client_, kTableId); - auto rows = table.AsyncSampleRows(NonEmptyOptions()); - EXPECT_THAT(rows.get(), StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, ReadModifyWriteRowWithOptions) { - Table table(client_, kTableId); - auto r = ReadModifyWriteRule::AppendValue("cf", "cq", "v"); - auto row = table.ReadModifyWriteRow("row", r, r, NonEmptyOptions(), r); - EXPECT_THAT(row, StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, AsyncReadModifyWriteRowWithOptions) { - Table table(client_, kTableId); - auto r = ReadModifyWriteRule::AppendValue("cf", "cq", "v"); - auto row = table.AsyncReadModifyWriteRow("row", r, r, NonEmptyOptions(), r); - EXPECT_THAT(row.get(), StatusIs(StatusCode::kInvalidArgument)); -} - -TEST_F(TableTest, AsyncReadRowsWithOptions) { - MockFunction(bigtable::Row const&)> on_row; - EXPECT_CALL(on_row, Call).Times(0); - - MockFunction on_finish; - EXPECT_CALL(on_finish, Call).WillOnce([](Status const& status) { - EXPECT_THAT(status, StatusIs(StatusCode::kInvalidArgument)); - }); - - Table table(client_, kTableId); - table.AsyncReadRows(on_row.AsStdFunction(), on_finish.AsStdFunction(), - RowSet(), Filter::PassAllFilter(), NonEmptyOptions()); -} - -TEST_F(TableTest, AsyncReadRowsWithLimitWithOptions) { - MockFunction(bigtable::Row const&)> on_row; - EXPECT_CALL(on_row, Call).Times(0); - - MockFunction on_finish; - EXPECT_CALL(on_finish, Call).WillOnce([](Status const& status) { - EXPECT_THAT(status, StatusIs(StatusCode::kInvalidArgument)); - }); - - Table table(client_, kTableId); - table.AsyncReadRows(on_row.AsStdFunction(), on_finish.AsStdFunction(), - RowSet(), 1, Filter::PassAllFilter(), NonEmptyOptions()); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/metadata_update_policy_test.cc b/google/cloud/bigtable/metadata_update_policy_test.cc index edc31787ff584..e71d154cd29a3 100644 --- a/google/cloud/bigtable/metadata_update_policy_test.cc +++ b/google/cloud/bigtable/metadata_update_policy_test.cc @@ -79,7 +79,9 @@ TEST_F(MetadataUpdatePolicyTest, SimpleDefault) { } TEST_F(MetadataUpdatePolicyTest, TableAppProfileMetadata) { - auto table = Table(data_client_, "profile", kTableId); + auto table = + Table(data_connection_, TableResource(kProjectId, kInstanceId, kTableId), + Options{}.set("profile")); grpc::string expected = "table_name=" + google::cloud::internal::UrlEncode(kTableName) + "&app_profile_id=profile"; diff --git a/google/cloud/bigtable/mocks/mock_data_connection.h b/google/cloud/bigtable/mocks/mock_data_connection.h index a283af2c9e787..61f3d824a2005 100644 --- a/google/cloud/bigtable/mocks/mock_data_connection.h +++ b/google/cloud/bigtable/mocks/mock_data_connection.h @@ -16,6 +16,8 @@ #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_MOCKS_MOCK_DATA_CONNECTION_H #include "google/cloud/bigtable/data_connection.h" +#include "google/cloud/bigtable/options.h" +#include "google/cloud/options.h" #include "google/cloud/version.h" #include diff --git a/google/cloud/bigtable/row_reader.cc b/google/cloud/bigtable/row_reader.cc index 66d7889201e30..aeb5960655140 100644 --- a/google/cloud/bigtable/row_reader.cc +++ b/google/cloud/bigtable/row_reader.cc @@ -13,7 +13,6 @@ // limitations under the License. #include "google/cloud/bigtable/row_reader.h" -#include "google/cloud/bigtable/internal/legacy_row_reader.h" #include "google/cloud/bigtable/table.h" #include "google/cloud/grpc_error_delegate.h" #include "google/cloud/internal/throw_delegate.h" diff --git a/google/cloud/bigtable/row_reader.h b/google/cloud/bigtable/row_reader.h index ea33b8ee8ff76..147cc2e1a4c40 100644 --- a/google/cloud/bigtable/row_reader.h +++ b/google/cloud/bigtable/row_reader.h @@ -15,7 +15,6 @@ #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ROW_READER_H #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ROW_READER_H -#include "google/cloud/bigtable/data_client.h" #include "google/cloud/bigtable/filters.h" #include "google/cloud/bigtable/internal/readrowsparser.h" #include "google/cloud/bigtable/internal/row_reader_impl.h" diff --git a/google/cloud/bigtable/table.cc b/google/cloud/bigtable/table.cc index 14b96ef6715d3..a04a62e45f6ef 100644 --- a/google/cloud/bigtable/table.cc +++ b/google/cloud/bigtable/table.cc @@ -13,14 +13,6 @@ // limitations under the License. #include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/internal/bulk_mutator.h" -#include "google/cloud/bigtable/internal/data_connection_impl.h" -#include "google/cloud/bigtable/internal/legacy_async_bulk_apply.h" -#include "google/cloud/bigtable/internal/legacy_async_row_sampler.h" -#include "google/cloud/bigtable/internal/legacy_row_reader.h" -#include "google/cloud/bigtable/internal/unary_client_utils.h" -#include "google/cloud/internal/async_retry_unary_rpc.h" -#include "google/cloud/internal/make_status.h" #include #include @@ -44,175 +36,28 @@ void SetCommonTableOperationRequest(Request& request, } } // namespace -using ClientUtils = bigtable::internal::UnaryClientUtils; - static_assert(std::is_copy_assignable::value, "bigtable::Table must be CopyAssignable"); Status Table::Apply(SingleRowMutation mut, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->Apply(table_name_, std::move(mut)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()); - } - - // Copy the policies in effect for this operation. Many policy classes change - // their state as the operation makes progress (or fails to make progress), so - // we need fresh instances. - auto rpc_policy = clone_rpc_retry_policy(); - auto backoff_policy = clone_rpc_backoff_policy(); - auto idempotent_policy = clone_idempotent_mutation_policy(); - - // Build the RPC request, try to minimize copying. - btproto::MutateRowRequest request; - SetCommonTableOperationRequest( - request, app_profile_id(), table_name_); - mut.MoveTo(request); - - bool const is_idempotent = - std::all_of(request.mutations().begin(), request.mutations().end(), - [&idempotent_policy](btproto::Mutation const& m) { - return idempotent_policy->is_idempotent(m); - }); - - btproto::MutateRowResponse response; - grpc::Status status; - while (true) { - grpc::ClientContext client_context; - rpc_policy->Setup(client_context); - backoff_policy->Setup(client_context); - metadata_update_policy_.Setup(client_context); - status = client_->MutateRow(&client_context, request, &response); - - if (status.ok()) { - return google::cloud::Status{}; - } - // It is up to the policy to terminate this loop, it could run - // forever, but that would be a bad policy (pun intended). - if (!rpc_policy->OnFailure(status) || !is_idempotent) { - return MakeStatusFromRpcError(status); - } - auto delay = backoff_policy->OnCompletion(status); - std::this_thread::sleep_for(delay); - } + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->Apply(table_name_, std::move(mut)); } future Table::AsyncApply(SingleRowMutation mut, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->AsyncApply(table_name_, std::move(mut)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return make_ready_future(google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO())); - } - - google::bigtable::v2::MutateRowRequest request; - SetCommonTableOperationRequest( - request, app_profile_id(), table_name_); - mut.MoveTo(request); - - // Determine if all the mutations are idempotent. The idempotency of the - // mutations won't change as the retry loop executes, so we can just compute - // it once and use a constant value for the loop. - auto idempotent_mutation_policy = clone_idempotent_mutation_policy(); - auto const is_idempotent = std::all_of( - request.mutations().begin(), request.mutations().end(), - [&idempotent_mutation_policy](google::bigtable::v2::Mutation const& m) { - return idempotent_mutation_policy->is_idempotent(m); - }); - - auto const idempotency = - is_idempotent ? Idempotency::kIdempotent : Idempotency::kNonIdempotent; - - auto cq = background_threads_->cq(); - auto& client = client_; - auto metadata_update_policy = clone_metadata_update_policy(); - return google::cloud::internal::StartRetryAsyncUnaryRpc( - cq, __func__, clone_rpc_retry_policy(), clone_rpc_backoff_policy(), - idempotency, - [client, metadata_update_policy]( - grpc::ClientContext* context, - google::bigtable::v2::MutateRowRequest const& request, - grpc::CompletionQueue* cq) { - metadata_update_policy.Setup(*context); - return client->AsyncMutateRow(context, request, cq); - }, - std::move(request)) - .then([](future> r) { - return r.get().status(); - }); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->AsyncApply(table_name_, std::move(mut)); } std::vector Table::BulkApply(BulkMutation mut, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->BulkApply(table_name_, std::move(mut)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return bigtable_internal::MakeFailedMutations( - google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()), - mut.size()); - } - - if (mut.empty()) return {}; - grpc::Status status; - - // Copy the policies in effect for this operation. Many policy classes change - // their state as the operation makes progress (or fails to make progress), so - // we need fresh instances. - auto backoff_policy = clone_rpc_backoff_policy(); - auto retry_policy = clone_rpc_retry_policy(); - auto idempotent_policy = clone_idempotent_mutation_policy(); - - bigtable_internal::BulkMutator mutator( - app_profile_id(), table_name_, *idempotent_policy, std::move(mut), - std::make_shared()); - while (true) { - grpc::ClientContext client_context; - backoff_policy->Setup(client_context); - retry_policy->Setup(client_context); - metadata_update_policy_.Setup(client_context); - status = mutator.MakeOneRequest(*client_, client_context); - if (!mutator.HasPendingMutations()) break; - if (!retry_policy->OnFailure(status)) break; - auto delay = backoff_policy->OnCompletion(status); - std::this_thread::sleep_for(delay); - } - return std::move(mutator).OnRetryDone(); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->BulkApply(table_name_, std::move(mut)); } future> Table::AsyncBulkApply(BulkMutation mut, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->AsyncBulkApply(table_name_, std::move(mut)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return make_ready_future(bigtable_internal::MakeFailedMutations( - google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()), - mut.size())); - } - - auto cq = background_threads_->cq(); - auto mutation_policy = clone_idempotent_mutation_policy(); - return internal::AsyncRetryBulkApply::Create( - cq, clone_rpc_retry_policy(), clone_rpc_backoff_policy(), - *mutation_policy, clone_metadata_update_policy(), client_, - app_profile_id(), table_name_, std::move(mut)); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->AsyncBulkApply(table_name_, std::move(mut)); } RowReader Table::ReadRows(RowSet row_set, Filter filter, Options opts) { @@ -222,162 +67,34 @@ RowReader Table::ReadRows(RowSet row_set, Filter filter, Options opts) { RowReader Table::ReadRows(RowSet row_set, std::int64_t rows_limit, Filter filter, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->ReadRows(table_name_, std::move(row_set), rows_limit, - std::move(filter)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return MakeRowReader( - std::make_shared( - google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()))); - } - - auto impl = std::make_shared( - client_, app_profile_id(), table_name_, std::move(row_set), rows_limit, - std::move(filter), clone_rpc_retry_policy(), clone_rpc_backoff_policy(), - metadata_update_policy_, - std::make_unique()); - return bigtable_internal::MakeRowReader(std::move(impl)); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->ReadRows(table_name_, std::move(row_set), rows_limit, + std::move(filter)); } StatusOr> Table::ReadRow(std::string row_key, Filter filter, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->ReadRow(table_name_, std::move(row_key), - std::move(filter)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()); - } - - RowSet row_set(std::move(row_key)); - std::int64_t const rows_limit = 1; - RowReader reader = - ReadRows(std::move(row_set), rows_limit, std::move(filter)); - - auto it = reader.begin(); - if (it == reader.end()) { - return std::make_pair(false, Row("", {})); - } - if (!*it) { - return it->status(); - } - auto result = std::make_pair(true, std::move(**it)); - if (++it != reader.end()) { - return google::cloud::internal::InternalError( - "internal error - RowReader returned more than one row in ReadRow(, " - "GCP_ERROR_INFO())"); - } - return result; + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->ReadRow(table_name_, std::move(row_key), + std::move(filter)); } StatusOr Table::CheckAndMutateRow( std::string row_key, Filter filter, std::vector true_mutations, std::vector false_mutations, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->CheckAndMutateRow( - table_name_, std::move(row_key), std::move(filter), - std::move(true_mutations), std::move(false_mutations)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()); - } - - grpc::Status status; - btproto::CheckAndMutateRowRequest request; - request.set_row_key(std::move(row_key)); - SetCommonTableOperationRequest( - request, app_profile_id(), table_name_); - *request.mutable_predicate_filter() = std::move(filter).as_proto(); - for (auto& m : true_mutations) { - *request.add_true_mutations() = std::move(m.op); - } - for (auto& m : false_mutations) { - *request.add_false_mutations() = std::move(m.op); - } - auto const idempotency = idempotent_mutation_policy_->is_idempotent(request) - ? Idempotency::kIdempotent - : Idempotency::kNonIdempotent; - auto response = ClientUtils::MakeCall( - *client_, clone_rpc_retry_policy(), clone_rpc_backoff_policy(), - metadata_update_policy_, &DataClient::CheckAndMutateRow, request, - "Table::CheckAndMutateRow", status, idempotency); - - if (!status.ok()) { - return MakeStatusFromRpcError(status); - } - return response.predicate_matched() ? MutationBranch::kPredicateMatched - : MutationBranch::kPredicateNotMatched; + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->CheckAndMutateRow( + table_name_, std::move(row_key), std::move(filter), + std::move(true_mutations), std::move(false_mutations)); } future> Table::AsyncCheckAndMutateRow( std::string row_key, Filter filter, std::vector true_mutations, std::vector false_mutations, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->AsyncCheckAndMutateRow( - table_name_, std::move(row_key), std::move(filter), - std::move(true_mutations), std::move(false_mutations)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return make_ready_future>( - google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO())); - } - - btproto::CheckAndMutateRowRequest request; - request.set_row_key(std::move(row_key)); - SetCommonTableOperationRequest( - request, app_profile_id(), table_name_); - *request.mutable_predicate_filter() = std::move(filter).as_proto(); - for (auto& m : true_mutations) { - *request.add_true_mutations() = std::move(m.op); - } - for (auto& m : false_mutations) { - *request.add_false_mutations() = std::move(m.op); - } - auto const idempotency = idempotent_mutation_policy_->is_idempotent(request) - ? Idempotency::kIdempotent - : Idempotency::kNonIdempotent; - - auto cq = background_threads_->cq(); - auto& client = client_; - auto metadata_update_policy = clone_metadata_update_policy(); - return google::cloud::internal::StartRetryAsyncUnaryRpc( - cq, __func__, clone_rpc_retry_policy(), clone_rpc_backoff_policy(), - idempotency, - [client, metadata_update_policy]( - grpc::ClientContext* context, - btproto::CheckAndMutateRowRequest const& request, - grpc::CompletionQueue* cq) { - metadata_update_policy.Setup(*context); - return client->AsyncCheckAndMutateRow(context, request, cq); - }, - std::move(request)) - .then([](future> f) - -> StatusOr { - auto response = f.get(); - if (!response) { - return response.status(); - } - return response->predicate_matched() - ? MutationBranch::kPredicateMatched - : MutationBranch::kPredicateNotMatched; - }); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->AsyncCheckAndMutateRow( + table_name_, std::move(row_key), std::move(filter), + std::move(true_mutations), std::move(false_mutations)); } // Call the `google.bigtable.v2.Bigtable.SampleRowKeys` RPC until @@ -386,75 +103,14 @@ future> Table::AsyncCheckAndMutateRow( // policies in effect tell us to stop. Note that each retry must clear the // samples otherwise the result is an inconsistent set of sample row keys. StatusOr> Table::SampleRows(Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->SampleRows(table_name_); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()); - } - - // Copy the policies in effect for this operation. - auto backoff_policy = clone_rpc_backoff_policy(); - auto retry_policy = clone_rpc_retry_policy(); - std::vector samples; - - // Build the RPC request for SampleRowKeys - btproto::SampleRowKeysRequest request; - btproto::SampleRowKeysResponse response; - SetCommonTableOperationRequest( - request, app_profile_id(), table_name_); - - while (true) { - grpc::ClientContext client_context; - backoff_policy->Setup(client_context); - retry_policy->Setup(client_context); - clone_metadata_update_policy().Setup(client_context); - - auto stream = client_->SampleRowKeys(&client_context, request); - while (stream->Read(&response)) { - bigtable::RowKeySample row_sample; - row_sample.offset_bytes = response.offset_bytes(); - row_sample.row_key = std::move(*response.mutable_row_key()); - samples.emplace_back(std::move(row_sample)); - } - auto status = stream->Finish(); - if (status.ok()) { - break; - } - if (!retry_policy->OnFailure(status)) { - return MakeStatusFromRpcError( - status.error_code(), - "Retry policy exhausted: " + status.error_message()); - } - samples.clear(); - auto delay = backoff_policy->OnCompletion(status); - std::this_thread::sleep_for(delay); - } - return samples; + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->SampleRows(table_name_); } future>> Table::AsyncSampleRows( Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->AsyncSampleRows(table_name_); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return make_ready_future>>( - google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO())); - } - - auto cq = background_threads_->cq(); - return internal::LegacyAsyncRowSampler::Create( - cq, client_, clone_rpc_retry_policy(), clone_rpc_backoff_policy(), - metadata_update_policy_, app_profile_id(), table_name_); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->AsyncSampleRows(table_name_); } StatusOr Table::ReadModifyWriteRowImpl( @@ -462,27 +118,8 @@ StatusOr Table::ReadModifyWriteRowImpl( SetCommonTableOperationRequest< ::google::bigtable::v2::ReadModifyWriteRowRequest>( request, app_profile_id(), table_name_); - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->ReadModifyWriteRow(std::move(request)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO()); - } - - grpc::Status status; - auto response = ClientUtils::MakeNonIdempotentCall( - *(client_), clone_rpc_retry_policy(), clone_metadata_update_policy(), - &DataClient::ReadModifyWriteRow, request, "ReadModifyWriteRowRequest", - status); - if (!status.ok()) { - return MakeStatusFromRpcError(status); - } - return bigtable_internal::TransformReadModifyWriteRowResponse( - std::move(response)); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->ReadModifyWriteRow(std::move(request)); } future> Table::AsyncReadModifyWriteRowImpl( @@ -490,107 +127,16 @@ future> Table::AsyncReadModifyWriteRowImpl( SetCommonTableOperationRequest< ::google::bigtable::v2::ReadModifyWriteRowRequest>( request, app_profile_id(), table_name_); - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->AsyncReadModifyWriteRow(std::move(request)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return make_ready_future>( - google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO())); - } - - auto cq = background_threads_->cq(); - auto& client = client_; - auto metadata_update_policy = clone_metadata_update_policy(); - return google::cloud::internal::StartRetryAsyncUnaryRpc( - cq, __func__, clone_rpc_retry_policy(), clone_rpc_backoff_policy(), - Idempotency::kNonIdempotent, - [client, metadata_update_policy]( - grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - grpc::CompletionQueue* cq) { - metadata_update_policy.Setup(*context); - return client->AsyncReadModifyWriteRow(context, request, cq); - }, - std::move(request)) - .then([](future> fut) - -> StatusOr { - auto result = fut.get(); - if (!result) return std::move(result).status(); - return bigtable_internal::TransformReadModifyWriteRowResponse( - *std::move(result)); - }); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->AsyncReadModifyWriteRow(std::move(request)); } future>> Table::AsyncReadRow(std::string row_key, Filter filter, Options opts) { - if (connection_) { - OptionsSpan span(MergeOptions(std::move(opts), options_)); - return connection_->AsyncReadRow(table_name_, std::move(row_key), - std::move(filter)); - } - if (!google::cloud::internal::IsEmpty(opts)) { - return make_ready_future>>( - google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO())); - } - - class AsyncReadRowHandler { - public: - AsyncReadRowHandler() : row_("", {}) {} - - future>> GetFuture() { - return row_promise_.get_future(); - } - - future OnRow(Row row) { - // assert(!row_received_); - row_ = std::move(row); - row_received_ = true; - // Don't satisfy the promise before `OnStreamFinished`. - // - // The `CompletionQueue`, which this object holds a reference to, should - // not be shut down before `OnStreamFinished` is called. In order to make - // sure of that, satisying the `promise<>` is deferred until then - the - // user shouldn't shutdown the `CompletionQueue` before this whole - // operation is done. - return make_ready_future(false); - } - - void OnStreamFinished(Status status) { - if (row_received_) { - // If we got a row we don't need to care about the stream status. - row_promise_.set_value(std::make_pair(true, std::move(row_))); - return; - } - if (status.ok()) { - row_promise_.set_value(std::make_pair(false, Row("", {}))); - } else { - row_promise_.set_value(std::move(status)); - } - } - - private: - Row row_; - bool row_received_{}; - promise>> row_promise_; - }; - - RowSet row_set(std::move(row_key)); - std::int64_t const rows_limit = 1; - auto handler = std::make_shared(); - AsyncReadRows([handler](Row row) { return handler->OnRow(std::move(row)); }, - [handler](Status status) { - handler->OnStreamFinished(std::move(status)); - }, - std::move(row_set), rows_limit, std::move(filter)); - return handler->GetFuture(); + OptionsSpan span(MergeOptions(std::move(opts), options_)); + return connection_->AsyncReadRow(table_name_, std::move(row_key), + std::move(filter)); } GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END diff --git a/google/cloud/bigtable/table.h b/google/cloud/bigtable/table.h index 00b16e69098ac..653b67965b036 100644 --- a/google/cloud/bigtable/table.h +++ b/google/cloud/bigtable/table.h @@ -16,12 +16,10 @@ #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_H #include "google/cloud/bigtable/completion_queue.h" -#include "google/cloud/bigtable/data_client.h" #include "google/cloud/bigtable/data_connection.h" #include "google/cloud/bigtable/filters.h" #include "google/cloud/bigtable/idempotent_mutation_policy.h" #include "google/cloud/bigtable/internal/defaults.h" -#include "google/cloud/bigtable/internal/legacy_async_row_reader.h" #include "google/cloud/bigtable/mutation_branch.h" #include "google/cloud/bigtable/mutations.h" #include "google/cloud/bigtable/options.h" @@ -52,20 +50,6 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN class MutationBatcher; -/** - * Return the full table name. - * - * The full table name is: - * - * `projects//instances//tables/` - * - * Where the project id and instance id come from the @p client parameter. - */ -inline std::string TableName(std::shared_ptr const& client, - std::string const& table_id) { - return InstanceName(client) + "/tables/" + table_id; -} - /** * The main interface to interact with data in a Cloud Bigtable table. * @@ -775,28 +759,11 @@ class Table { return (*on_finish_ptr)(std::move(status)); }; - if (connection_) { - google::cloud::internal::OptionsSpan span( - google::cloud::internal::MergeOptions(std::move(opts), options_)); - connection_->AsyncReadRows(table_name_, std::move(on_row_fn), - std::move(on_finish_fn), std::move(row_set), - rows_limit, std::move(filter)); - return; - } - if (!google::cloud::internal::IsEmpty(opts)) { - on_finish_fn(google::cloud::internal::InvalidArgumentError( - "Per-operation options only apply to `Table`s constructed " - "with a `DataConnection`.", - GCP_ERROR_INFO())); - return; - } - - bigtable_internal::LegacyAsyncRowReader::Create( - background_threads_->cq(), client_, app_profile_id(), table_name_, - std::move(on_row_fn), std::move(on_finish_fn), std::move(row_set), - rows_limit, std::move(filter), clone_rpc_retry_policy(), - clone_rpc_backoff_policy(), metadata_update_policy_, - std::make_unique()); + google::cloud::internal::OptionsSpan span( + google::cloud::internal::MergeOptions(std::move(opts), options_)); + connection_->AsyncReadRows(table_name_, std::move(on_row_fn), + std::move(on_finish_fn), std::move(row_set), + rows_limit, std::move(filter)); } /** @@ -830,176 +797,6 @@ class Table { Filter filter, Options opts = {}); - /** - * Constructor with default policies. - * - * @param client how to communicate with Cloud Bigtable, including - * credentials, the project id, and the instance id. - * @param table_id the table id within the instance defined by client. The - * full table name is `client->instance_name() + "/tables/" + table_id`. - * - * @deprecated #google::cloud::bigtable::DataConnection is the preferred way - * to communicate with the Bigtable Data API. To migrate existing code, - * see @ref migrating-from-dataclient "Migrating from DataClient". - */ - Table(std::shared_ptr client, std::string const& table_id) - : Table(std::move(client), std::string{}, table_id) {} - - /** - * Constructor with default policies. - * - * @param client how to communicate with Cloud Bigtable, including - * credentials, the project id, and the instance id. - * @param app_profile_id the app_profile_id needed for using the replication - * API. - * @param table_id the table id within the instance defined by client. The - * full table name is `client->instance_name() + "/tables/" + table_id`. - * - * @deprecated #google::cloud::bigtable::DataConnection is the preferred way - * to communicate with the Bigtable Data API. To migrate existing code, - * see @ref migrating-from-dataclient "Migrating from DataClient". - */ - Table(std::shared_ptr client, std::string app_profile_id, - std::string const& table_id) - : client_(std::move(client)), - table_(client_->project_id(), client_->instance_id(), table_id), - table_name_(table_.FullName()), - rpc_retry_policy_prototype_( - bigtable::DefaultRPCRetryPolicy(internal::kBigtableLimits)), - rpc_backoff_policy_prototype_( - bigtable::DefaultRPCBackoffPolicy(internal::kBigtableLimits)), - idempotent_mutation_policy_( - bigtable::DefaultIdempotentMutationPolicy()), - background_threads_(client_->BackgroundThreadsFactory()()), - options_(Options{}.set(std::move(app_profile_id))), - metadata_update_policy_(bigtable_internal::MakeMetadataUpdatePolicy( - table_name_, this->app_profile_id())) {} - - /** - * Constructor with explicit policies. - * - * The policies are passed by value, because this makes it easy for - * applications to create them. - * - * @par Example - * @code - * using namespace std::chrono_literals; // assuming C++14. - * auto client = bigtable::MakeClient(...); // details omitted - * bigtable::Table table(client, "my-table", - * // Allow up to 20 minutes to retry operations - * bigtable::LimitedTimeRetryPolicy(20min), - * // Start with 50 milliseconds backoff, grow - * // exponentially to 5 minutes. - * bigtable::ExponentialBackoffPolicy(50ms, 5min), - * // Only retry idempotent mutations. - * bigtable::SafeIdempotentMutationPolicy()); - * @endcode - * - * @param client how to communicate with Cloud Bigtable, including - * credentials, the project id, and the instance id. - * @param table_id the table id within the instance defined by client. The - * full table name is `client->instance_name() + "/tables/" + table_id`. - * @param policies the set of policy overrides for this object. - * @tparam Policies the types of the policies to override, the types must - * derive from one of the following types: - * - * - `IdempotentMutationPolicy` which mutations are retried. Use - * `SafeIdempotentMutationPolicy` to only retry idempotent operations, - * use `AlwaysRetryMutationPolicy` to retry all operations. Read the - * caveats in the class definition to understand the downsides of the - * latter. You can also create your own policies that decide which - * mutations to retry. - * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only - * `ExponentialBackoffPolicy` is implemented. You can also create your - * own policies that backoff using a different algorithm. - * - `RPCRetryPolicy` for how long to retry failed RPCs. Use - * `LimitedErrorCountRetryPolicy` to limit the number of failures - * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any - * request. You can also create your own policies that combine time and - * error counts. - * - * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy, - * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy, - * LimitedTimeRetryPolicy. - * - * @deprecated #google::cloud::bigtable::DataConnection is the preferred way - * to communicate with the Bigtable Data API. To migrate existing code, - * see @ref migrating-from-dataclient "Migrating from DataClient". - */ - template ::value, int> = 0 - /// @endcond - > - Table(std::shared_ptr client, std::string const& table_id, - Policies&&... policies) - : Table(std::move(client), table_id) { - ChangePolicies(std::forward(policies)...); - } - - /** - * Constructor with explicit policies. - * - * The policies are passed by value, because this makes it easy for - * applications to create them. - * - * @par Example - * @code - * using namespace std::chrono_literals; // assuming C++14. - * auto client = bigtable::MakeClient(...); // details omitted - * bigtable::Table table(client, "app_id", "my-table", - * // Allow up to 20 minutes to retry operations - * bigtable::LimitedTimeRetryPolicy(20min), - * // Start with 50 milliseconds backoff, grow - * // exponentially to 5 minutes. - * bigtable::ExponentialBackoffPolicy(50ms, 5min), - * // Only retry idempotent mutations. - * bigtable::SafeIdempotentMutationPolicy()); - * @endcode - * - * @param client how to communicate with Cloud Bigtable, including - * credentials, the project id, and the instance id. - * @param app_profile_id the app_profile_id needed for using the replication - * API. - * @param table_id the table id within the instance defined by client. The - * full table name is `client->instance_name() + "/tables/" + table_id`. - * @param policies the set of policy overrides for this object. - * @tparam Policies the types of the policies to override, the types must - * derive from one of the following types: - * - `IdempotentMutationPolicy` which mutations are retried. Use - * `SafeIdempotentMutationPolicy` to only retry idempotent operations, - * use `AlwaysRetryMutationPolicy` to retry all operations. Read the - * caveats in the class definition to understand the downsides of the - * latter. You can also create your own policies that decide which - * mutations to retry. - * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only - * `ExponentialBackoffPolicy` is implemented. You can also create your - * own policies that backoff using a different algorithm. - * - `RPCRetryPolicy` for how long to retry failed RPCs. Use - * `LimitedErrorCountRetryPolicy` to limit the number of failures - * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any - * request. You can also create your own policies that combine time and - * error counts. - * - * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy, - * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy, - * LimitedTimeRetryPolicy. - * - * @deprecated #google::cloud::bigtable::DataConnection is the preferred way - * to communicate with the Bigtable Data API. To migrate existing code, - * see @ref migrating-from-dataclient "Migrating from DataClient". - */ - template ::value, int> = 0 - /// @endcond - > - Table(std::shared_ptr client, std::string app_profile_id, - std::string const& table_id, Policies&&... policies) - : Table(std::move(client), std::move(app_profile_id), table_id) { - ChangePolicies(std::forward(policies)...); - } - private: /** * Send request ReadModifyWriteRowRequest to modify the row and get it back @@ -1066,13 +863,11 @@ class Table { ///@} friend class MutationBatcher; - std::shared_ptr client_; TableResource table_; std::string table_name_; std::shared_ptr rpc_retry_policy_prototype_; std::shared_ptr rpc_backoff_policy_prototype_; std::shared_ptr idempotent_mutation_policy_; - std::shared_ptr background_threads_; std::shared_ptr connection_; Options options_; MetadataUpdatePolicy metadata_update_policy_; diff --git a/google/cloud/bigtable/table_apply_test.cc b/google/cloud/bigtable/table_apply_test.cc deleted file mode 100644 index acbf38761b2c6..0000000000000 --- a/google/cloud/bigtable/table_apply_test.cc +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/internal/api_client_header.h" -#include "google/cloud/testing_util/chrono_literals.h" -#include "google/cloud/testing_util/status_matchers.h" -#include "google/cloud/testing_util/validate_metadata.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace bigtable = ::google::cloud::bigtable; -using ::google::cloud::testing_util::StatusIs; -using ::google::cloud::testing_util::ValidateMetadataFixture; -using ::google::cloud::testing_util::chrono_literals::operator""_ms; - -class TableApplyTest : public bigtable::testing::TableTestFixture { - protected: - TableApplyTest() : TableTestFixture(CompletionQueue{}) {} - - void IsContextMDValid(grpc::ClientContext& context, std::string const& method, - google::protobuf::Message const& request) { - return validate_metadata_fixture_.IsContextMDValid( - context, method, request, - google::cloud::internal::HandCraftedLibClientHeader()); - } - - std::function - CreateMutateRowMock(grpc::Status const& status) { - return [this, status](grpc::ClientContext* context, - google::bigtable::v2::MutateRowRequest const& request, - google::bigtable::v2::MutateRowResponse*) { - IsContextMDValid(*context, "google.bigtable.v2.Bigtable.MutateRow", - request); - return status; - }; - } - - private: - ValidateMetadataFixture validate_metadata_fixture_; -}; - -/// @test Verify that Table::Apply() works in a simplest case. -TEST_F(TableApplyTest, Simple) { - EXPECT_CALL(*client_, MutateRow) - .WillOnce(CreateMutateRowMock(grpc::Status::OK)); - - auto status = table_.Apply(bigtable::SingleRowMutation( - "bar", {bigtable::SetCell("fam", "col", 0_ms, "val")})); - ASSERT_STATUS_OK(status); -} - -/// @test Verify that Table::Apply() raises an exception on permanent failures. -TEST_F(TableApplyTest, Failure) { - EXPECT_CALL(*client_, MutateRow) - .WillRepeatedly(CreateMutateRowMock( - grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "uh-oh"))); - - auto status = table_.Apply(bigtable::SingleRowMutation( - "bar", {bigtable::SetCell("fam", "col", 0_ms, "val")})); - EXPECT_THAT(status, StatusIs(StatusCode::kFailedPrecondition)); -} - -/// @test Verify that Table::Apply() retries on partial failures. -TEST_F(TableApplyTest, Retry) { - EXPECT_CALL(*client_, MutateRow) - .WillOnce(CreateMutateRowMock( - grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again"))) - .WillOnce(CreateMutateRowMock( - grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again"))) - .WillOnce(CreateMutateRowMock( - grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again"))) - .WillOnce(CreateMutateRowMock((grpc::Status::OK))); - - auto status = table_.Apply(bigtable::SingleRowMutation( - "bar", {bigtable::SetCell("fam", "col", 0_ms, "val")})); - ASSERT_STATUS_OK(status); -} - -/// @test Verify that Table::Apply() retries only idempotent mutations. -TEST_F(TableApplyTest, RetryIdempotent) { - EXPECT_CALL(*client_, MutateRow) - .WillRepeatedly(CreateMutateRowMock( - grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again"))); - - auto status = table_.Apply(bigtable::SingleRowMutation( - "not-idempotent", {bigtable::SetCell("fam", "col", "val")})); - EXPECT_THAT(status, StatusIs(StatusCode::kUnavailable)); -} - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_bulk_apply_test.cc b/google/cloud/bigtable/table_bulk_apply_test.cc deleted file mode 100644 index d991309977d62..0000000000000 --- a/google/cloud/bigtable/table_bulk_apply_test.cc +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/mock_mutate_rows_reader.h" -#include "google/cloud/bigtable/testing/mock_policies.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/testing_util/chrono_literals.h" -#include "google/cloud/testing_util/status_matchers.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; - -using ::google::cloud::bigtable::testing::MockBackoffPolicy; -using ::google::cloud::testing_util::IsOk; -using ::google::cloud::testing_util::chrono_literals::operator""_ms; -using ::google::cloud::testing_util::chrono_literals::operator""_us; -using ::testing::An; -using ::testing::Not; -using ::testing::Return; - -/// Define types and functions used in the tests. -class TableBulkApplyTest - : public ::google::cloud::bigtable::testing::TableTestFixture { - public: - TableBulkApplyTest() : TableTestFixture(CompletionQueue{}) {} -}; -using ::google::cloud::bigtable::testing::MockMutateRowsReader; - -TEST_F(TableBulkApplyTest, Empty) { - auto failures = table_.BulkApply(BulkMutation()); - EXPECT_TRUE(failures.empty()); -} - -/// @test Verify that Table::BulkApply() works in the easy case. -TEST_F(TableBulkApplyTest, Simple) { - auto reader = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - { - auto& e = *r->add_entries(); - e.set_index(1); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*reader, Finish()).WillOnce(Return(grpc::Status::OK)); - - EXPECT_CALL(*client_, MutateRows) - .WillOnce(reader.release()->MakeMockReturner()); - - auto failures = table_.BulkApply(BulkMutation( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); - ASSERT_TRUE(failures.empty()); - SUCCEED(); -} - -/// @test Verify that Table::BulkApply() retries partial failures. -TEST_F(TableBulkApplyTest, RetryPartialFailure) { - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - // Simulate a partial (recoverable) failure. - auto& e0 = *r->add_entries(); - e0.set_index(0); - e0.mutable_status()->set_code(grpc::StatusCode::UNAVAILABLE); - auto& e1 = *r->add_entries(); - e1.set_index(1); - e1.mutable_status()->set_code(grpc::StatusCode::OK); - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish()).WillOnce(Return(grpc::Status::OK)); - - auto r2 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r2, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r2, Finish()).WillOnce(Return(grpc::Status::OK)); - - EXPECT_CALL(*client_, MutateRows) - .WillOnce(r1.release()->MakeMockReturner()) - .WillOnce(r2.release()->MakeMockReturner()); - - auto failures = table_.BulkApply(BulkMutation( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); - ASSERT_TRUE(failures.empty()); - SUCCEED(); -} - -/// @test Verify that Table::BulkApply() handles permanent failures. -TEST_F(TableBulkApplyTest, PermanentFailure) { - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - { - auto& e = *r->add_entries(); - e.set_index(1); - e.mutable_status()->set_code(grpc::StatusCode::OUT_OF_RANGE); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish()).WillOnce(Return(grpc::Status::OK)); - - EXPECT_CALL(*client_, MutateRows).WillOnce(r1.release()->MakeMockReturner()); - - auto failures = table_.BulkApply(BulkMutation( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); - EXPECT_FALSE(failures.empty()); -} - -/// @test Verify that Table::BulkApply() handles a terminated stream. -TEST_F(TableBulkApplyTest, CanceledStream) { - // Simulate a stream that returns one success and then terminates. We expect - // the BulkApply() operation to retry the request, because the mutation is in - // an undetermined state. Well, it should retry assuming it is idempotent, - // which happens to be the case in this test. - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish()).WillOnce(Return(grpc::Status::OK)); - - // Create a second stream returned by the mocks when the client retries. - auto r2 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r2, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r2, Finish()).WillOnce(Return(grpc::Status::OK)); - - EXPECT_CALL(*client_, MutateRows) - .WillOnce(r1.release()->MakeMockReturner()) - .WillOnce(r2.release()->MakeMockReturner()); - - auto failures = table_.BulkApply(BulkMutation( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); - ASSERT_TRUE(failures.empty()); - SUCCEED(); -} - -/// @test Verify that Table::BulkApply() reports correctly on too many errors. -TEST_F(TableBulkApplyTest, TooManyFailures) { - // Create a table with specific policies so we can test the behavior - // without having to depend on timers expiring. In this case tolerate only - // 3 failures. - Table custom_table( - client_, "foo_table", - // Configure the Table to stop at 3 failures. - LimitedErrorCountRetryPolicy(2), - // Use much shorter backoff than the default to test faster. - ExponentialBackoffPolicy(10_us, 40_us)); - - // Setup the mocks to fail more than 3 times. - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::ABORTED, ""))); - - auto create_cancelled_stream = [&](grpc::ClientContext*, - btproto::MutateRowsRequest const&) { - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::ABORTED, ""))); - return stream; - }; - - EXPECT_CALL(*client_, MutateRows) - .WillOnce(r1.release()->MakeMockReturner()) - .WillOnce(create_cancelled_stream) - .WillOnce(create_cancelled_stream); - - auto failures = custom_table.BulkApply(BulkMutation( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); - EXPECT_FALSE(failures.empty()); - EXPECT_EQ(google::cloud::StatusCode::kAborted, - failures.front().status().code()); -} - -TEST_F(TableBulkApplyTest, RetryPolicyUsedForOkStreamWithFailedMutations) { - // Create a table with specific policies so we can test the behavior - // without having to depend on timers expiring. In this case tolerate only - // 3 failures. - Table custom_table( - client_, "foo_table", - // Configure the Table to stop at 3 failures. - LimitedErrorCountRetryPolicy(2), - // Use much shorter backoff than the default to test faster. - ExponentialBackoffPolicy(10_us, 40_us)); - - auto create_stream = [&](grpc::ClientContext*, - btproto::MutateRowsRequest const&) { - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*stream, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - auto& e0 = *r->add_entries(); - e0.set_index(0); - e0.mutable_status()->set_code(grpc::StatusCode::UNAVAILABLE); - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - return stream; - }; - - EXPECT_CALL(*client_, MutateRows).Times(3).WillRepeatedly(create_stream); - - auto failures = custom_table.BulkApply(BulkMutation( - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); - EXPECT_FALSE(failures.empty()); - EXPECT_EQ(StatusCode::kUnavailable, failures.front().status().code()); -} - -/// @test Verify that Table::BulkApply() retries only idempotent mutations. -TEST_F(TableBulkApplyTest, RetryOnlyIdempotent) { - // We will send both idempotent and non-idempotent mutations. We prepare the - // mocks to return an empty stream in the first RPC request. That will force - // the client to only retry the idempotent mutations. - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r1, Read).WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish()).WillOnce(Return(grpc::Status::OK)); - - auto r2 = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*r2, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r2, Finish()).WillOnce(Return(grpc::Status::OK)); - - EXPECT_CALL(*client_, MutateRows) - .WillOnce(r1.release()->MakeMockReturner()) - .WillOnce(r2.release()->MakeMockReturner()); - - auto failures = table_.BulkApply(BulkMutation( - SingleRowMutation("is-idempotent", {SetCell("fam", "col", 0_ms, "qux")}), - SingleRowMutation("not-idempotent", {SetCell("fam", "col", "baz")}))); - EXPECT_EQ(1UL, failures.size()); - EXPECT_EQ(1, failures.front().original_index()); - EXPECT_THAT(failures.front().status(), Not(IsOk())); - EXPECT_FALSE(failures.empty()); -} - -/// @test Verify that Table::BulkApply() works when the RPC fails. -TEST_F(TableBulkApplyTest, FailedRPC) { - auto reader = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*reader, Read).WillOnce(Return(false)); - EXPECT_CALL(*reader, Finish()) - .WillOnce(Return(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, - "no such table"))); - - EXPECT_CALL(*client_, MutateRows) - .WillOnce(reader.release()->MakeMockReturner()); - - auto failures = table_.BulkApply(BulkMutation( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); - EXPECT_EQ(2UL, failures.size()); - EXPECT_THAT(failures.front().status(), Not(IsOk())); - EXPECT_FALSE(failures.empty()); - EXPECT_EQ(google::cloud::StatusCode::kFailedPrecondition, - failures.front().status().code()); -} - -TEST_F(TableBulkApplyTest, NoSleepIfNoPendingMutations) { - auto reader = std::make_unique( - "google.bigtable.v2.Bigtable.MutateRows"); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::MutateRowsResponse* r) { - { - auto& e = *r->add_entries(); - e.set_index(0); - e.mutable_status()->set_code(grpc::StatusCode::OK); - } - { - auto& e = *r->add_entries(); - e.set_index(1); - e.mutable_status()->set_code(grpc::StatusCode::PERMISSION_DENIED); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*reader, Finish()).WillOnce(Return(grpc::Status::OK)); - - EXPECT_CALL(*client_, MutateRows) - .WillOnce(reader.release()->MakeMockReturner()); - - // The backoff policy is cloned once in the Table constructor, and once before - // the start of the `BulkApply` call. We set expectations on the second clone. - auto b1 = std::make_unique(); - EXPECT_CALL(*b1, clone).WillOnce([]() { - auto b2 = std::make_unique(); - EXPECT_CALL(*b2, clone).WillOnce([]() { - auto mock = std::make_unique(); - EXPECT_CALL(*mock, Setup).Times(1); - EXPECT_CALL(*mock, OnCompletion(An())).Times(0); - return mock; - }); - return b2; - }); - auto table = Table(client_, kTableId, std::move(*b1)); - (void)table.BulkApply(BulkMutation( - SingleRowMutation("foo", {SetCell("fam", "col", 0_ms, "baz")}), - SingleRowMutation("bar", {SetCell("fam", "col", 0_ms, "qux")}))); -} - -} // anonymous namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_check_and_mutate_row_test.cc b/google/cloud/bigtable/table_check_and_mutate_row_test.cc deleted file mode 100644 index df0f029de5e25..0000000000000 --- a/google/cloud/bigtable/table_check_and_mutate_row_test.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/internal/api_client_header.h" -#include "google/cloud/testing_util/chrono_literals.h" -#include "google/cloud/testing_util/status_matchers.h" -#include "google/cloud/testing_util/validate_metadata.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -using ::google::cloud::testing_util::ValidateMetadataFixture; -using ::google::cloud::testing_util::chrono_literals::operator""_ms; - -class TableCheckAndMutateRowTest : public bigtable::testing::TableTestFixture { - protected: - TableCheckAndMutateRowTest() : TableTestFixture(CompletionQueue{}) {} - - void IsContextMDValid(grpc::ClientContext& context, std::string const& method, - google::protobuf::Message const& request) { - return validate_metadata_fixture_.IsContextMDValid( - context, method, request, - google::cloud::internal::HandCraftedLibClientHeader()); - } - - std::function< - grpc::Status(grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const&, - google::bigtable::v2::CheckAndMutateRowResponse*)> - CreateCheckAndMutateMock(grpc::Status const& status) { - return [this, status]( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - google::bigtable::v2::CheckAndMutateRowResponse*) { - IsContextMDValid( - *context, "google.bigtable.v2.Bigtable.CheckAndMutateRow", request); - return status; - }; - } - - private: - ValidateMetadataFixture validate_metadata_fixture_; -}; - -/// @test Verify that Table::CheckAndMutateRow() works in a simplest case. -TEST_F(TableCheckAndMutateRowTest, Simple) { - EXPECT_CALL(*client_, CheckAndMutateRow) - .WillOnce(CreateCheckAndMutateMock(grpc::Status::OK)); - - auto mut = table_.CheckAndMutateRow( - "foo", bigtable::Filter::PassAllFilter(), - {bigtable::SetCell("fam", "col", 0_ms, "it was true")}, - {bigtable::SetCell("fam", "col", 0_ms, "it was false")}); - - ASSERT_STATUS_OK(mut); -} - -#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS -/// @test Verify that Table::CheckAndMutateRow() raises an on failures. -TEST_F(TableCheckAndMutateRowTest, Failure) { - EXPECT_CALL(*client_, CheckAndMutateRow) - .WillRepeatedly(CreateCheckAndMutateMock( - grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again"))); - - EXPECT_FALSE(table_.CheckAndMutateRow( - "foo", bigtable::Filter::PassAllFilter(), - {bigtable::SetCell("fam", "col", 0_ms, "it was true")}, - {bigtable::SetCell("fam", "col", 0_ms, "it was false")})); -} -#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - -} // anonymous namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_readmodifywriterow_test.cc b/google/cloud/bigtable/table_readmodifywriterow_test.cc deleted file mode 100644 index 8bd0b22e2f2db..0000000000000 --- a/google/cloud/bigtable/table_readmodifywriterow_test.cc +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/internal/api_client_header.h" -#include "google/cloud/testing_util/is_proto_equal.h" -#include "google/cloud/testing_util/status_matchers.h" -#include "google/cloud/testing_util/validate_metadata.h" -#include -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; - -using ::google::cloud::testing_util::IsProtoEqual; -using ::google::cloud::testing_util::ValidateMetadataFixture; - -/// Define helper types and functions for this test. -class TableReadModifyWriteTest : public bigtable::testing::TableTestFixture { - public: - TableReadModifyWriteTest() : TableTestFixture(CompletionQueue{}) {} - - std::function - CreateRules(std::string const& expected_request_string, - std::string const& generated_response_string) { - return [this, expected_request_string, generated_response_string]( - grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - btproto::ReadModifyWriteRowResponse* response) { - validate_metadata_fixture_.IsContextMDValid( - *context, "google.bigtable.v2.Bigtable.ReadModifyWriteRow", request, - google::cloud::internal::HandCraftedLibClientHeader()); - btproto::ReadModifyWriteRowRequest expected_request; - EXPECT_TRUE(::google::protobuf::TextFormat::ParseFromString( - expected_request_string, &expected_request)); - EXPECT_THAT(expected_request, IsProtoEqual(request)); - - EXPECT_TRUE(::google::protobuf::TextFormat::ParseFromString( - generated_response_string, response)); - - return grpc::Status::OK; - }; - } - - private: - ValidateMetadataFixture validate_metadata_fixture_; -}; - -TEST_F(TableReadModifyWriteTest, MultipleAppendValueTest) { - std::string const row_key = "row-key"; - std::string const family1 = "family1"; - std::string const column_id1 = "colid1"; - std::string const request_text = R"""( -table_name: "projects/foo-project/instances/bar-instance/tables/baz-table" -row_key: "row-key" -rules { - family_name: "family1" - column_qualifier: "colid1" - append_value: "value1" -} -rules { - family_name: "family1" - column_qualifier: "colid1" - append_value: "-value2" -} -)"""; - - std::string const response_text = R"""( -row { - key: "response-row-key" - families { - name: "response-family1" - columns { - qualifier: "response-colid1" - cells { - value: "value1-value2" - } - } - } -} -)"""; - - auto mock_read_modify_write_row = CreateRules(request_text, response_text); - - EXPECT_CALL(*client_, ReadModifyWriteRow) - .WillOnce(mock_read_modify_write_row); - - auto row = table_.ReadModifyWriteRow( - row_key, - bigtable::ReadModifyWriteRule::AppendValue(family1, column_id1, "value1"), - bigtable::ReadModifyWriteRule::AppendValue(family1, column_id1, - "-value2")); - - ASSERT_STATUS_OK(row); - EXPECT_EQ("response-row-key", row->row_key()); - EXPECT_EQ("response-family1", row->cells().at(0).family_name()); - EXPECT_EQ("response-colid1", row->cells().at(0).column_qualifier()); - EXPECT_EQ(1, (int)row->cells().size()); - EXPECT_EQ("value1-value2", row->cells().at(0).value()); -} - -TEST_F(TableReadModifyWriteTest, MultipleIncrementAmountTest) { - std::string const row_key = "row-key"; - std::string const family1 = "family1"; - std::string const family2 = "family2"; - std::string const column_id1 = "colid1"; - std::string const column_id2 = "colid2"; - std::string const request_text = R"""( - table_name: "projects/foo-project/instances/bar-instance/tables/baz-table" - row_key: "row-key" - rules { - family_name: "family1" - column_qualifier: "colid1" - increment_amount: 1000 - } - rules { - family_name: "family1" - column_qualifier: "colid2" - increment_amount: 200 - } - rules { - family_name: "family2" - column_qualifier: "colid2" - increment_amount: 400 - } - )"""; - - std::string const response_text = R"""( - row { - key: "response-row-key" - families { - name: "response-family1" - columns { - qualifier: "response-colid1" - cells { - value: "1200" - } - } - } - families { - name: "response-family2" - columns { - qualifier: "response-colid2" - cells { - value: "400" - } - } - } - } - )"""; - - auto mock_read_modify_write_row = CreateRules(request_text, response_text); - - EXPECT_CALL(*client_, ReadModifyWriteRow) - .WillOnce(mock_read_modify_write_row); - - auto row = table_.ReadModifyWriteRow( - row_key, - bigtable::ReadModifyWriteRule::IncrementAmount(family1, column_id1, 1000), - bigtable::ReadModifyWriteRule::IncrementAmount(family1, column_id2, 200), - bigtable::ReadModifyWriteRule::IncrementAmount(family2, column_id2, 400)); - - ASSERT_STATUS_OK(row); - EXPECT_EQ("response-row-key", row->row_key()); - EXPECT_EQ("response-family1", row->cells().at(0).family_name()); - EXPECT_EQ("response-colid1", row->cells().at(0).column_qualifier()); - EXPECT_EQ(2, (int)row->cells().size()); - EXPECT_EQ("1200", row->cells().at(0).value()); - - EXPECT_EQ("response-family2", row->cells().at(1).family_name()); - EXPECT_EQ("response-colid2", row->cells().at(1).column_qualifier()); - EXPECT_EQ("400", row->cells().at(1).value()); -} - -TEST_F(TableReadModifyWriteTest, MultipleMixedRuleTest) { - std::string const row_key = "row-key"; - std::string const family1 = "family1"; - std::string const family2 = "family2"; - std::string const column_id1 = "colid1"; - std::string const column_id2 = "colid2"; - std::string const request_text = R"""( - table_name: "projects/foo-project/instances/bar-instance/tables/baz-table" - row_key: "row-key" - rules { - family_name: "family1" - column_qualifier: "colid1" - increment_amount: 1000 - } - rules { - family_name: "family1" - column_qualifier: "colid2" - append_value: "value_string" - } - rules { - family_name: "family2" - column_qualifier: "colid2" - increment_amount: 400 - } - )"""; - - std::string const response_text = R"""( - row { - key: "response-row-key" - families { - name: "response-family1" - columns { - qualifier: "response-colid1" - cells { - value: "1200" - } - } - } - families { - name: "response-family2" - columns { - qualifier: "response-colid2" - cells { - value: "value_string" - } - } - } - } - )"""; - - auto mock_read_modify_write_row = CreateRules(request_text, response_text); - - EXPECT_CALL(*client_, ReadModifyWriteRow) - .WillOnce(mock_read_modify_write_row); - - auto row = table_.ReadModifyWriteRow( - row_key, - bigtable::ReadModifyWriteRule::IncrementAmount(family1, column_id1, 1000), - bigtable::ReadModifyWriteRule::AppendValue(family1, column_id2, - "value_string"), - bigtable::ReadModifyWriteRule::IncrementAmount(family2, column_id2, 400)); - - ASSERT_STATUS_OK(row); - EXPECT_EQ("response-row-key", row->row_key()); - EXPECT_EQ("response-family1", row->cells().at(0).family_name()); - EXPECT_EQ("response-colid1", row->cells().at(0).column_qualifier()); - EXPECT_EQ(2, (int)row->cells().size()); - EXPECT_EQ("1200", row->cells().at(0).value()); - - EXPECT_EQ("response-family2", row->cells().at(1).family_name()); - EXPECT_EQ("response-colid2", row->cells().at(1).column_qualifier()); - EXPECT_EQ("value_string", row->cells().at(1).value()); -} - -TEST_F(TableReadModifyWriteTest, UnrecoverableFailureTest) { - std::string const row_key = "row-key"; - std::string const family1 = "family1"; - std::string const column_id1 = "colid1"; - - EXPECT_CALL(*client_, ReadModifyWriteRow) - .WillRepeatedly( - [](grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - google::bigtable::v2::ReadModifyWriteRowResponse*) { - ::google::cloud::testing_util::ValidateMetadataFixture fixture; - fixture.IsContextMDValid( - *context, "google.bigtable.v2.Bigtable.ReadModifyWriteRow", - request, google::cloud::internal::HandCraftedLibClientHeader()); - return grpc::Status(grpc::StatusCode::PERMISSION_DENIED, "uh oh"); - }); - - EXPECT_FALSE(table_.ReadModifyWriteRow( - row_key, - bigtable::ReadModifyWriteRule::AppendValue(family1, column_id1, "value1"), - bigtable::ReadModifyWriteRule::AppendValue(family1, column_id1, - "-value2"))); -} - -} // anonymous namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_readrow_test.cc b/google/cloud/bigtable/table_readrow_test.cc deleted file mode 100644 index f9478e030f833..0000000000000 --- a/google/cloud/bigtable/table_readrow_test.cc +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/mock_read_rows_reader.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/testing_util/status_matchers.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -namespace btproto = ::google::bigtable::v2; -using ::google::cloud::bigtable::testing::MockReadRowsReader; -using ::google::cloud::testing_util::ValidateMetadataFixture; -using ::testing::Return; - -class TableReadRowTest : public bigtable::testing::TableTestFixture { - protected: - TableReadRowTest() : TableTestFixture(CompletionQueue{}) {} - - void IsContextMDValid(grpc::ClientContext& context, std::string const& method, - google::protobuf::Message const& request) { - return validate_metadata_fixture_.IsContextMDValid( - context, method, request, - google::cloud::internal::HandCraftedLibClientHeader()); - } - - private: - ValidateMetadataFixture validate_metadata_fixture_; -}; - -TEST_F(TableReadRowTest, ReadRowSimple) { - auto const response = bigtable::testing::ReadRowsResponseFromString(R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "col" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } -)"); - - EXPECT_CALL(*client_, ReadRows) - .WillOnce([&response, this](grpc::ClientContext* context, - btproto::ReadRowsRequest const& req) { - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*stream, Read) - .WillOnce([response](btproto::ReadRowsResponse* r) { - *r = response; - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish).WillOnce(Return(grpc::Status::OK)); - - IsContextMDValid(*context, "google.bigtable.v2.Bigtable.ReadRows", req); - EXPECT_EQ(1, req.rows().row_keys_size()); - EXPECT_EQ("r1", req.rows().row_keys(0)); - EXPECT_EQ(1, req.rows_limit()); - EXPECT_EQ(table_.table_name(), req.table_name()); - return stream; - }); - - auto result = table_.ReadRow("r1", bigtable::Filter::PassAllFilter()); - ASSERT_STATUS_OK(result); - EXPECT_TRUE(std::get<0>(*result)); - auto row = std::get<1>(*result); - EXPECT_EQ("r1", row.row_key()); -} - -TEST_F(TableReadRowTest, ReadRowMissing) { - EXPECT_CALL(*client_, ReadRows) - .WillOnce([this](grpc::ClientContext* context, - btproto::ReadRowsRequest const& req) { - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish).WillOnce(Return(grpc::Status::OK)); - - IsContextMDValid(*context, "google.bigtable.v2.Bigtable.ReadRows", req); - EXPECT_EQ(1, req.rows().row_keys_size()); - EXPECT_EQ("r1", req.rows().row_keys(0)); - EXPECT_EQ(1, req.rows_limit()); - EXPECT_EQ(table_.table_name(), req.table_name()); - return stream; - }); - - auto result = table_.ReadRow("r1", bigtable::Filter::PassAllFilter()); - ASSERT_STATUS_OK(result); - EXPECT_FALSE(std::get<0>(*result)); -} - -TEST_F(TableReadRowTest, UnrecoverableFailure) { - EXPECT_CALL(*client_, ReadRows) - .WillRepeatedly([this](grpc::ClientContext* context, - btproto::ReadRowsRequest const& request) { - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*stream, Read).WillRepeatedly(Return(false)); - EXPECT_CALL(*stream, Finish) - .WillRepeatedly(Return( - grpc::Status(grpc::StatusCode::PERMISSION_DENIED, "uh oh"))); - - IsContextMDValid(*context, "google.bigtable.v2.Bigtable.ReadRows", - request); - return stream; - }); - - auto row = table_.ReadRow("r1", bigtable::Filter::PassAllFilter()); - EXPECT_FALSE(row); -} - -} // anonymous namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_readrows_test.cc b/google/cloud/bigtable/table_readrows_test.cc deleted file mode 100644 index 1b9427d47c303..0000000000000 --- a/google/cloud/bigtable/table_readrows_test.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/mock_read_rows_reader.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/testing_util/status_matchers.h" - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -using ::google::cloud::bigtable::testing::MockReadRowsReader; -using ::testing::DoAll; -using ::testing::Return; -using ::testing::SetArgPointee; -using ::testing::WithoutArgs; - -class TableReadRowsTest : public bigtable::testing::TableTestFixture { - public: - TableReadRowsTest() : TableTestFixture(CompletionQueue{}) {} -}; - -TEST_F(TableReadRowsTest, ReadRowsCanReadOneRow) { - auto response = bigtable::testing::ReadRowsResponseFromString(R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "qual" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - )"); - - // must be a new pointer, it is wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*stream, Read) - .WillOnce(DoAll(SetArgPointee<0>(response), Return(true))) - .WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK)); - EXPECT_CALL(*client_, ReadRows).WillOnce(stream->MakeMockReturner()); - - auto reader = - table_.ReadRows(bigtable::RowSet(), bigtable::Filter::PassAllFilter()); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(TableReadRowsTest, ReadRowsCanReadWithRetries) { - auto response = bigtable::testing::ReadRowsResponseFromString(R"( - chunks { - row_key: "r1" - family_name { value: "fam" } - qualifier { value: "qual" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - )"); - - auto response_retry = bigtable::testing::ReadRowsResponseFromString(R"( - chunks { - row_key: "r2" - family_name { value: "fam" } - qualifier { value: "qual" } - timestamp_micros: 42000 - value: "value" - commit_row: true - } - )"); - - // must be a new pointer, it is wrapped in unique_ptr by ReadRows - auto* stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - auto* stream_retry = - new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows"); - - EXPECT_CALL(*client_, ReadRows) - .WillOnce(stream->MakeMockReturner()) - .WillOnce(stream_retry->MakeMockReturner()); - - EXPECT_CALL(*stream, Read) - .WillOnce(DoAll(SetArgPointee<0>(response), Return(true))) - .WillOnce(Return(false)); - - EXPECT_CALL(*stream, Finish()) - .WillOnce( - Return(grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again"))); - - EXPECT_CALL(*stream_retry, Read) - .WillOnce(DoAll(SetArgPointee<0>(response_retry), Return(true))) - .WillOnce(Return(false)); - - EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - - auto reader = - table_.ReadRows(bigtable::RowSet(), bigtable::Filter::PassAllFilter()); - - auto it = reader.begin(); - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r1"); - ++it; - EXPECT_NE(it, reader.end()); - ASSERT_STATUS_OK(*it); - EXPECT_EQ((*it)->row_key(), "r2"); - EXPECT_EQ(++it, reader.end()); -} - -TEST_F(TableReadRowsTest, ReadRowsThrowsWhenTooManyErrors) { - EXPECT_CALL(*client_, ReadRows).WillRepeatedly(WithoutArgs([] { - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.ReadRows"); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish()) - .WillOnce( - Return(grpc::Status(grpc::StatusCode::UNAVAILABLE, "broken"))); - return stream; - })); - - auto table = bigtable::Table( - client_, "table_id", bigtable::LimitedErrorCountRetryPolicy(3), - bigtable::ExponentialBackoffPolicy(std::chrono::seconds(0), - std::chrono::seconds(0)), - bigtable::SafeIdempotentMutationPolicy()); - auto reader = - table.ReadRows(bigtable::RowSet(), bigtable::Filter::PassAllFilter()); - - auto it = reader.begin(); - ASSERT_NE(reader.end(), it); - ASSERT_FALSE(*it); - ++it; - ASSERT_EQ(reader.end(), it); -} - -} // anonymous namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_sample_row_keys_test.cc b/google/cloud/bigtable/table_sample_row_keys_test.cc deleted file mode 100644 index 77cb019d3ee2f..0000000000000 --- a/google/cloud/bigtable/table_sample_row_keys_test.cc +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/mock_sample_row_keys_reader.h" -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/testing_util/chrono_literals.h" -#include "google/cloud/testing_util/status_matchers.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -namespace { - -using ::google::cloud::testing_util::chrono_literals::operator""_us; -using ::google::cloud::bigtable::testing::MockSampleRowKeysReader; -using ::testing::Return; -using ::testing::Unused; - -class TableSampleRowKeysTest - : public ::google::cloud::bigtable::testing::TableTestFixture { - public: - TableSampleRowKeysTest() : TableTestFixture(CompletionQueue{}) {} -}; - -/// @test Verify that Table::SampleRows() works. -TEST_F(TableSampleRowKeysTest, SampleRowKeysTest) { - namespace btproto = ::google::bigtable::v2; - - EXPECT_CALL(*client_, SampleRowKeys).WillOnce([](Unused, Unused) { - auto reader = std::make_unique( - "google.bigtable.v2.Bigtable.SampleRowKeys"); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r) { - { - r->set_row_key("test1"); - r->set_offset_bytes(11); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*reader, Finish).WillOnce(Return(grpc::Status::OK)); - return reader; - }); - auto result = table_.SampleRows(); - ASSERT_STATUS_OK(result); - auto it = result->begin(); - EXPECT_NE(it, result->end()); - EXPECT_EQ(it->row_key, "test1"); - EXPECT_EQ(it->offset_bytes, 11); - EXPECT_EQ(++it, result->end()); -} - -/// @test Verify that Table::SampleRows() retries when unavailable. -TEST_F(TableSampleRowKeysTest, SampleRowKeysRetryTest) { - namespace btproto = ::google::bigtable::v2; - - EXPECT_CALL(*client_, SampleRowKeys) - .WillOnce([](Unused, Unused) { - auto reader = std::make_unique( - "google.bigtable.v2.Bigtable.SampleRowKeys"); - EXPECT_CALL(*reader, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r) { - { - r->set_row_key("test1"); - r->set_offset_bytes(11); - } - return true; - }) - .WillOnce(Return(false)); - - EXPECT_CALL(*reader, Finish()) - .WillOnce(Return( - grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again"))); - return reader; - }) - .WillOnce([](Unused, Unused) { - auto reader_retry = std::make_unique( - "google.bigtable.v2.Bigtable.SampleRowKeys"); - EXPECT_CALL(*reader_retry, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r) { - { - r->set_row_key("test2"); - r->set_offset_bytes(123); - } - return true; - }) - .WillOnce([](btproto::SampleRowKeysResponse* r) { - { - r->set_row_key("test3"); - r->set_offset_bytes(1234); - } - return true; - }) - .WillOnce(Return(false)); - - EXPECT_CALL(*reader_retry, Finish()).WillOnce(Return(grpc::Status::OK)); - return reader_retry; - }); - - auto results = table_.SampleRows(); - ASSERT_STATUS_OK(results); - - auto it = results->begin(); - EXPECT_NE(it, results->end()); - EXPECT_EQ("test2", it->row_key); - ++it; - EXPECT_NE(it, results->end()); - EXPECT_EQ("test3", it->row_key); - EXPECT_EQ(++it, results->end()); -} - -#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS -/// @test Verify that Table::SampleRows() reports correctly on too many errors. -TEST_F(TableSampleRowKeysTest, TooManyFailures) { - namespace btproto = ::google::bigtable::v2; - - // Create a table with specific policies so we can test the behavior - // without having to depend on timers expiring. In this case tolerate only - // 3 failures. - Table custom_table( - client_, "foo_table", - // Configure the Table to stop at 3 failures. - LimitedErrorCountRetryPolicy(2), - // Use much shorter backoff than the default to test faster. - ExponentialBackoffPolicy(10_us, 40_us), SafeIdempotentMutationPolicy()); - - // Setup the mocks to fail more than 3 times. - auto create_cancelled_stream = [](Unused, Unused) { - auto stream = std::make_unique( - "google.bigtable.v2.Bigtable.SampleRowKeys"); - EXPECT_CALL(*stream, Read).WillOnce(Return(false)); - EXPECT_CALL(*stream, Finish) - .WillOnce(Return(grpc::Status(grpc::StatusCode::ABORTED, ""))); - return stream; - }; - - EXPECT_CALL(*client_, SampleRowKeys) - .WillOnce([](Unused, Unused) { - auto r1 = std::make_unique( - "google.bigtable.v2.Bigtable.SampleRowKeys"); - EXPECT_CALL(*r1, Read) - .WillOnce([](btproto::SampleRowKeysResponse* r) { - { - r->set_row_key("test1"); - r->set_offset_bytes(11); - } - return true; - }) - .WillOnce(Return(false)); - EXPECT_CALL(*r1, Finish) - .WillOnce(Return(grpc::Status(grpc::StatusCode::ABORTED, ""))); - return r1; - }) - .WillOnce(create_cancelled_stream) - .WillOnce(create_cancelled_stream); - - EXPECT_FALSE(custom_table.SampleRows()); -} -#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS - -} // namespace -GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/table_test.cc b/google/cloud/bigtable/table_test.cc index 70c578b16fbdf..965e239e4481b 100644 --- a/google/cloud/bigtable/table_test.cc +++ b/google/cloud/bigtable/table_test.cc @@ -178,6 +178,55 @@ TEST(TableTest, AppProfileId) { EXPECT_EQ(kAppProfileId, table.app_profile_id()); } +TEST(TableTest, WithNewTarget) { + auto conn = std::make_shared(); + Table table(conn, TableResource(kProjectId, kInstanceId, kTableId), + Options{}.set(kAppProfileId)); + EXPECT_EQ(table.project_id(), kProjectId); + EXPECT_EQ(table.instance_id(), kInstanceId); + EXPECT_EQ(table.table_id(), kTableId); + EXPECT_EQ(table.table_name(), kTableName); + EXPECT_EQ(table.app_profile_id(), kAppProfileId); + + std::string const other_project_id = "other-project"; + std::string const other_instance_id = "other-instance"; + std::string const other_table_id = "other-table"; + auto other_table = + table.WithNewTarget(other_project_id, other_instance_id, other_table_id); + + EXPECT_EQ(other_table.project_id(), other_project_id); + EXPECT_EQ(other_table.instance_id(), other_instance_id); + EXPECT_EQ(other_table.table_id(), other_table_id); + EXPECT_EQ(other_table.table_name(), + TableName(other_project_id, other_instance_id, other_table_id)); + EXPECT_EQ(other_table.app_profile_id(), kAppProfileId); +} + +TEST(TableTest, WithNewTargetProfile) { + auto conn = std::make_shared(); + Table table(conn, TableResource(kProjectId, kInstanceId, kTableId), + Options{}.set(kAppProfileId)); + EXPECT_EQ(table.project_id(), kProjectId); + EXPECT_EQ(table.instance_id(), kInstanceId); + EXPECT_EQ(table.table_id(), kTableId); + EXPECT_EQ(table.table_name(), kTableName); + EXPECT_EQ(table.app_profile_id(), kAppProfileId); + + std::string const other_project_id = "other-project"; + std::string const other_instance_id = "other-instance"; + std::string const other_table_id = "other-table"; + std::string const other_profile_id = "other-profile"; + auto other_table = table.WithNewTarget(other_project_id, other_instance_id, + other_profile_id, other_table_id); + + EXPECT_EQ(other_table.project_id(), other_project_id); + EXPECT_EQ(other_table.instance_id(), other_instance_id); + EXPECT_EQ(other_table.table_id(), other_table_id); + EXPECT_EQ(other_table.table_name(), + TableName(other_project_id, other_instance_id, other_table_id)); + EXPECT_EQ(other_table.app_profile_id(), other_profile_id); +} + TEST(TableTest, Apply) { auto mock = std::make_shared(); EXPECT_CALL(*mock, Apply) diff --git a/google/cloud/bigtable/test_proxy/cbt_test_proxy.h b/google/cloud/bigtable/test_proxy/cbt_test_proxy.h index 2ad2a958ce135..6d3bc39fed60f 100644 --- a/google/cloud/bigtable/test_proxy/cbt_test_proxy.h +++ b/google/cloud/bigtable/test_proxy/cbt_test_proxy.h @@ -17,6 +17,7 @@ #include "google/cloud/bigtable/data_connection.h" #include "google/cloud/bigtable/table.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/version.h" #include "protos/google/cloud/bigtable/test_proxy/test_proxy.grpc.pb.h" #include diff --git a/google/cloud/bigtable/testing/embedded_server_test_fixture.cc b/google/cloud/bigtable/testing/embedded_server_test_fixture.cc index 5186db9eabcb1..3d8967ae186e3 100644 --- a/google/cloud/bigtable/testing/embedded_server_test_fixture.cc +++ b/google/cloud/bigtable/testing/embedded_server_test_fixture.cc @@ -13,7 +13,14 @@ // limitations under the License. #include "google/cloud/bigtable/testing/embedded_server_test_fixture.h" +#include "google/cloud/bigtable/internal/bigtable_metadata_decorator.h" +#include "google/cloud/bigtable/internal/bigtable_stub.h" +#include "google/cloud/bigtable/internal/data_connection_impl.h" +#include "google/cloud/bigtable/internal/mutate_rows_limiter.h" +#include "google/cloud/bigtable/options.h" +#include "google/cloud/bigtable/retry_policy.h" #include "google/cloud/grpc_error_delegate.h" +#include "google/cloud/internal/background_threads_impl.h" #include "google/cloud/internal/build_info.h" #include "google/cloud/internal/user_agent_prefix.h" #include @@ -53,9 +60,34 @@ void EmbeddedServerTestFixture::SetUp() { std::shared_ptr data_channel = server_->InProcessChannel(channel_arguments); - data_client_ = std::make_shared(kProjectId, kInstanceId, - std::move(data_channel)); - table_ = std::make_shared(data_client_, kTableId); + std::unique_ptr grpc_stub = + google::bigtable::v2::Bigtable::NewStub(data_channel); + std::shared_ptr stub = + std::make_shared( + std::make_shared( + std::move(grpc_stub)), + std::multimap{}, + google::cloud::internal::UserAgentPrefix()); + auto opts = + Options{} + .set( + google::cloud::bigtable::DataLimitedErrorCountRetryPolicy(7) + .clone()) + .set( + google::cloud::ExponentialBackoffPolicy( + /*initial_delay=*/std::chrono::milliseconds(200), + /*maximum_delay=*/std::chrono::seconds(45), + /*scaling=*/2.0) + .clone()); + data_connection_ = std::make_shared( + std::make_unique< + google::cloud::internal::AutomaticallyCreatedBackgroundThreads>(), + stub, std::make_shared(), + std::move(opts)); + + table_ = std::make_shared( + data_connection_, + bigtable::TableResource(kProjectId, kInstanceId, kTableId)); } void EmbeddedServerTestFixture::TearDown() { diff --git a/google/cloud/bigtable/testing/embedded_server_test_fixture.h b/google/cloud/bigtable/testing/embedded_server_test_fixture.h index 33c1fcd9f4296..1d2a4403089f8 100644 --- a/google/cloud/bigtable/testing/embedded_server_test_fixture.h +++ b/google/cloud/bigtable/testing/embedded_server_test_fixture.h @@ -17,7 +17,6 @@ #include "google/cloud/bigtable/table.h" #include "google/cloud/bigtable/table_admin.h" -#include "google/cloud/bigtable/testing/inprocess_data_client.h" #include "google/bigtable/v2/bigtable.grpc.pb.h" #include #include @@ -79,7 +78,7 @@ class EmbeddedServerTestFixture : public ::testing::Test { std::string project_id_ = kProjectId; std::string instance_id_ = kInstanceId; - std::shared_ptr data_client_; + std::shared_ptr data_connection_; std::shared_ptr table_; std::thread wait_thread_; BigtableImpl bigtable_service_; diff --git a/google/cloud/bigtable/testing/inprocess_data_client.cc b/google/cloud/bigtable/testing/inprocess_data_client.cc deleted file mode 100644 index 2b40012ec8ae4..0000000000000 --- a/google/cloud/bigtable/testing/inprocess_data_client.cc +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/testing/inprocess_data_client.h" - -namespace google { -namespace cloud { -namespace bigtable { -namespace testing { - -namespace btproto = ::google::bigtable::v2; - -grpc::Status InProcessDataClient::MutateRow( - grpc::ClientContext* context, btproto::MutateRowRequest const& request, - btproto::MutateRowResponse* response) { - return Stub()->MutateRow(context, request, response); -} - -std::unique_ptr> -InProcessDataClient::AsyncMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::MutateRowRequest const& request, - grpc::CompletionQueue* cq) { - auto result = Stub()->AsyncMutateRow(context, request, cq); - return std::unique_ptr>(result.release()); -} - -grpc::Status InProcessDataClient::CheckAndMutateRow( - grpc::ClientContext* context, - btproto::CheckAndMutateRowRequest const& request, - btproto::CheckAndMutateRowResponse* response) { - return Stub()->CheckAndMutateRow(context, request, response); -} - -std::unique_ptr> -InProcessDataClient::AsyncCheckAndMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - grpc::CompletionQueue* cq) { - auto result = Stub()->AsyncCheckAndMutateRow(context, request, cq); - return std::unique_ptr>(result.release()); -} - -grpc::Status InProcessDataClient::ReadModifyWriteRow( - grpc::ClientContext* context, - btproto::ReadModifyWriteRowRequest const& request, - btproto::ReadModifyWriteRowResponse* response) { - return Stub()->ReadModifyWriteRow(context, request, response); -} - -std::unique_ptr> -InProcessDataClient::AsyncReadModifyWriteRow( - grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - grpc::CompletionQueue* cq) { - auto result = Stub()->AsyncReadModifyWriteRow(context, request, cq); - return std::unique_ptr>(result.release()); -} - -std::unique_ptr> -InProcessDataClient::ReadRows(grpc::ClientContext* context, - btproto::ReadRowsRequest const& request) { - return Stub()->ReadRows(context, request); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface> -InProcessDataClient::AsyncReadRows(::grpc::ClientContext* context, - btproto::ReadRowsRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) { - return Stub()->AsyncReadRows(context, request, cq, tag); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::ReadRowsResponse>> -InProcessDataClient::PrepareAsyncReadRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::ReadRowsRequest const& request, - ::grpc::CompletionQueue* cq) { - return Stub()->PrepareAsyncReadRows(context, request, cq); -} - -std::unique_ptr> -InProcessDataClient::SampleRowKeys( - grpc::ClientContext* context, - btproto::SampleRowKeysRequest const& request) { - return Stub()->SampleRowKeys(context, request); -} - -std::unique_ptr> -InProcessDataClient::MutateRows(grpc::ClientContext* context, - btproto::MutateRowsRequest const& request) { - return Stub()->MutateRows(context, request); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> -InProcessDataClient::AsyncMutateRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) { - return Stub()->AsyncMutateRows(context, request, cq, tag); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> -InProcessDataClient::PrepareAsyncMutateRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq) { - return Stub()->PrepareAsyncMutateRows(context, request, cq); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> -InProcessDataClient::AsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) { - return Stub()->AsyncSampleRowKeys(context, request, cq, tag); -} - -std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> -InProcessDataClient::PrepareAsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq) { - return Stub()->PrepareAsyncSampleRowKeys(context, request, cq); -} - -} // namespace testing -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/testing/inprocess_data_client.h b/google/cloud/bigtable/testing/inprocess_data_client.h deleted file mode 100644 index 693987ffaab39..0000000000000 --- a/google/cloud/bigtable/testing/inprocess_data_client.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_INPROCESS_DATA_CLIENT_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_INPROCESS_DATA_CLIENT_H - -#include "google/cloud/bigtable/data_client.h" -#include "google/bigtable/v2/bigtable.grpc.pb.h" -#include -// TODO(#8800) - delete this class when deprecation is complete -#include "google/cloud/internal/disable_deprecation_warnings.inc" - -namespace google { -namespace cloud { -namespace bigtable { -namespace testing { - -/** - * Connect to an embedded Cloud Bigtable server implementing the data - * manipulation APIs. - * - * This class is mainly for testing purpose, it enable use of a single embedded - * server for multiple test cases. This dataclient uses a pre-defined channel. - */ -class InProcessDataClient : public bigtable::DataClient { - public: - InProcessDataClient(std::string project, std::string instance, - std::shared_ptr channel) - : project_(std::move(project)), - instance_(std::move(instance)), - channel_(std::move(channel)) {} - - using BigtableStubPtr = - std::shared_ptr; - - std::string const& project_id() const override { return project_; } - std::string const& instance_id() const override { return instance_; } - std::shared_ptr Channel() override { return channel_; } - void reset() override {} - - std::unique_ptr Stub() { - return google::bigtable::v2::Bigtable::NewStub(Channel()); - } - - ///@{ - /// @name the google.bigtable.v2.Bigtable operations. - grpc::Status MutateRow( - grpc::ClientContext* context, - google::bigtable::v2::MutateRowRequest const& request, - google::bigtable::v2::MutateRowResponse* response) override; - std::unique_ptr> - AsyncMutateRow(grpc::ClientContext* context, - google::bigtable::v2::MutateRowRequest const& request, - grpc::CompletionQueue* cq) override; - grpc::Status CheckAndMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - google::bigtable::v2::CheckAndMutateRowResponse* response) override; - std::unique_ptr> - AsyncCheckAndMutateRow( - grpc::ClientContext* context, - google::bigtable::v2::CheckAndMutateRowRequest const& request, - grpc::CompletionQueue* cq) override; - grpc::Status ReadModifyWriteRow( - grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - google::bigtable::v2::ReadModifyWriteRowResponse* response) override; - std::unique_ptr> - AsyncReadModifyWriteRow( - grpc::ClientContext* context, - google::bigtable::v2::ReadModifyWriteRowRequest const& request, - grpc::CompletionQueue* cq) override; - std::unique_ptr< - grpc::ClientReaderInterface> - ReadRows(grpc::ClientContext* context, - google::bigtable::v2::ReadRowsRequest const& request) override; - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::ReadRowsResponse>> - AsyncReadRows(::grpc::ClientContext* context, - ::google::bigtable::v2::ReadRowsRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) override; - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::ReadRowsResponse>> - PrepareAsyncReadRows(::grpc::ClientContext* context, - ::google::bigtable::v2::ReadRowsRequest const& request, - ::grpc::CompletionQueue* cq) override; - std::unique_ptr< - grpc::ClientReaderInterface> - SampleRowKeys( - grpc::ClientContext* context, - google::bigtable::v2::SampleRowKeysRequest const& request) override; - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> - AsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) override; - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::SampleRowKeysResponse>> - PrepareAsyncSampleRowKeys( - ::grpc::ClientContext* context, - ::google::bigtable::v2::SampleRowKeysRequest const& request, - ::grpc::CompletionQueue* cq) override; - std::unique_ptr< - grpc::ClientReaderInterface> - MutateRows(grpc::ClientContext* context, - google::bigtable::v2::MutateRowsRequest const& request) override; - - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> - AsyncMutateRows(::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq, void* tag) override; - - std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::MutateRowsResponse>> - PrepareAsyncMutateRows( - ::grpc::ClientContext* context, - ::google::bigtable::v2::MutateRowsRequest const& request, - ::grpc::CompletionQueue* cq) override; - ///@} - - private: - google::cloud::BackgroundThreadsFactory BackgroundThreadsFactory() override { - return google::cloud::internal::MakeBackgroundThreadsFactory(); - } - - std::string project_; - std::string instance_; - std::shared_ptr channel_; -}; - -} // namespace testing -} // namespace bigtable -} // namespace cloud -} // namespace google - -// TODO(#8800) - delete this class when deprecation is complete -#include "google/cloud/internal/diagnostics_pop.inc" - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_INPROCESS_DATA_CLIENT_H diff --git a/google/cloud/bigtable/testing/mock_data_client.h b/google/cloud/bigtable/testing/mock_data_client.h deleted file mode 100644 index 0a53659246428..0000000000000 --- a/google/cloud/bigtable/testing/mock_data_client.h +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_MOCK_DATA_CLIENT_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_MOCK_DATA_CLIENT_H - -#include "google/cloud/bigtable/table.h" -#include -#include -// TODO(#8800) - delete this class when deprecation is complete -#include "google/cloud/internal/disable_deprecation_warnings.inc" - -namespace google { -namespace cloud { -namespace bigtable { -namespace testing { - -class MockDataClient : public bigtable::DataClient { - public: - MockDataClient() = default; - - explicit MockDataClient(Options options) : options_(std::move(options)) {} - - /// @deprecated use constructor that takes `google::cloud::Options` - explicit MockDataClient(ClientOptions options) - : options_(internal::MakeOptions(std::move(options))) {} - - MOCK_METHOD(std::string const&, project_id, (), (const, override)); - MOCK_METHOD(std::string const&, instance_id, (), (const, override)); - MOCK_METHOD(std::shared_ptr, Channel, (), (override)); - MOCK_METHOD(void, reset, (), (override)); - - MOCK_METHOD(grpc::Status, MutateRow, - (grpc::ClientContext*, - google::bigtable::v2::MutateRowRequest const&, - google::bigtable::v2::MutateRowResponse*), - (override)); - MOCK_METHOD(std::unique_ptr>, - AsyncMutateRow, - (grpc::ClientContext*, - google::bigtable::v2::MutateRowRequest const&, - grpc::CompletionQueue*), - (override)); - MOCK_METHOD(grpc::Status, CheckAndMutateRow, - (grpc::ClientContext*, - google::bigtable::v2::CheckAndMutateRowRequest const&, - google::bigtable::v2::CheckAndMutateRowResponse*), - (override)); - MOCK_METHOD(std::unique_ptr>, - AsyncCheckAndMutateRow, - (grpc::ClientContext*, - google::bigtable::v2::CheckAndMutateRowRequest const&, - grpc::CompletionQueue*), - (override)); - MOCK_METHOD(grpc::Status, ReadModifyWriteRow, - (grpc::ClientContext*, - google::bigtable::v2::ReadModifyWriteRowRequest const&, - google::bigtable::v2::ReadModifyWriteRowResponse*), - (override)); - MOCK_METHOD(std::unique_ptr>, - AsyncReadModifyWriteRow, - (grpc::ClientContext*, - google::bigtable::v2::ReadModifyWriteRowRequest const&, - grpc::CompletionQueue*), - (override)); - MOCK_METHOD( - std::unique_ptr< - grpc::ClientReaderInterface>, - ReadRows, - (grpc::ClientContext*, google::bigtable::v2::ReadRowsRequest const&), - (override)); - MOCK_METHOD(std::unique_ptr>, - AsyncReadRows, - (grpc::ClientContext*, - google::bigtable::v2::ReadRowsRequest const&, - grpc::CompletionQueue*, void*), - (override)); - MOCK_METHOD(std::unique_ptr<::grpc::ClientAsyncReaderInterface< - ::google::bigtable::v2::ReadRowsResponse>>, - PrepareAsyncReadRows, - (::grpc::ClientContext*, - ::google::bigtable::v2::ReadRowsRequest const&, - ::grpc::CompletionQueue*), - (override)); - MOCK_METHOD(std::unique_ptr>, - SampleRowKeys, - (grpc::ClientContext*, - google::bigtable::v2::SampleRowKeysRequest const&), - (override)); - MOCK_METHOD(std::unique_ptr>, - AsyncSampleRowKeys, - (grpc::ClientContext*, - google::bigtable::v2::SampleRowKeysRequest const&, - grpc::CompletionQueue*, void*), - (override)); - MOCK_METHOD(std::unique_ptr>, - PrepareAsyncSampleRowKeys, - (grpc::ClientContext*, - google::bigtable::v2::SampleRowKeysRequest const&, - grpc::CompletionQueue*), - (override)); - MOCK_METHOD(std::unique_ptr>, - MutateRows, - (grpc::ClientContext*, - google::bigtable::v2::MutateRowsRequest const&), - (override)); - MOCK_METHOD(std::unique_ptr>, - AsyncMutateRows, - (grpc::ClientContext*, - google::bigtable::v2::MutateRowsRequest const&, - grpc::CompletionQueue*, void*), - (override)); - MOCK_METHOD(std::unique_ptr>, - PrepareAsyncMutateRows, - (grpc::ClientContext*, - google::bigtable::v2::MutateRowsRequest const&, - grpc::CompletionQueue*), - (override)); - - private: - google::cloud::BackgroundThreadsFactory BackgroundThreadsFactory() override { - return google::cloud::internal::MakeBackgroundThreadsFactory(options_); - } - - Options options_; -}; - -} // namespace testing -} // namespace bigtable -} // namespace cloud -} // namespace google - -// TODO(#8800) - delete this class when deprecation is complete -#include "google/cloud/internal/diagnostics_pop.inc" - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_MOCK_DATA_CLIENT_H diff --git a/google/cloud/bigtable/testing/table_integration_test.cc b/google/cloud/bigtable/testing/table_integration_test.cc index d9f8156437f7b..6a09bacf62018 100644 --- a/google/cloud/bigtable/testing/table_integration_test.cc +++ b/google/cloud/bigtable/testing/table_integration_test.cc @@ -123,8 +123,6 @@ void TableAdminTestEnvironment::TearDown() { void TableIntegrationTest::SetUp() { data_connection_ = MakeDataConnection(); - data_client_ = bigtable::MakeDataClient(TableTestEnvironment::project_id(), - TableTestEnvironment::instance_id()); // In production, we cannot use `DropAllRows()` to cleanup the table because // the integration tests sometimes consume all the 'DropRowRangeGroup' quota. @@ -164,15 +162,11 @@ void TableIntegrationTest::SetUp() { } } -bigtable::Table TableIntegrationTest::GetTable( - std::string const& implementation) { - if (implementation == "with-data-connection") { - return Table(data_connection_, - TableResource(TableTestEnvironment::project_id(), - TableTestEnvironment::instance_id(), - TableTestEnvironment::table_id())); - } - return bigtable::Table(data_client_, TableTestEnvironment::table_id()); +bigtable::Table TableIntegrationTest::GetTable() { + return Table(data_connection_, + TableResource(TableTestEnvironment::project_id(), + TableTestEnvironment::instance_id(), + TableTestEnvironment::table_id())); } std::vector TableIntegrationTest::ReadRows( @@ -188,12 +182,6 @@ std::vector TableIntegrationTest::ReadRows( return result; } -std::vector TableIntegrationTest::ReadRows( - std::string const& table_name, bigtable::Filter filter) { - bigtable::Table table(data_client_, table_name); - return ReadRows(table, std::move(filter)); -} - std::vector TableIntegrationTest::ReadRows( bigtable::Table& table, std::int64_t rows_limit, bigtable::Filter filter) { auto reader = diff --git a/google/cloud/bigtable/testing/table_integration_test.h b/google/cloud/bigtable/testing/table_integration_test.h index 8c360b5374db1..c6bbb3574f442 100644 --- a/google/cloud/bigtable/testing/table_integration_test.h +++ b/google/cloud/bigtable/testing/table_integration_test.h @@ -17,7 +17,6 @@ #include "google/cloud/bigtable/admin/bigtable_table_admin_client.h" #include "google/cloud/bigtable/cell.h" -#include "google/cloud/bigtable/data_client.h" #include "google/cloud/bigtable/table.h" #include "google/cloud/internal/random.h" #include "google/cloud/testing_util/integration_test.h" @@ -94,19 +93,12 @@ class TableIntegrationTest : public ::google::cloud::testing_util::IntegrationTest { protected: void SetUp() override; - - /// Gets a Table object for the current test. - bigtable::Table GetTable( - std::string const& implementation = "with-data-client"); + bigtable::Table GetTable(); /// Return all the cells in @p table that pass @p filter. static std::vector ReadRows(bigtable::Table& table, bigtable::Filter filter); - /// Return all the cells in @p table that pass @p filter. - std::vector ReadRows(std::string const& table_name, - bigtable::Filter filter); - static std::vector ReadRows(bigtable::Table& table, std::int64_t rows_limit, bigtable::Filter filter); @@ -179,7 +171,6 @@ class TableIntegrationTest return names; } - std::shared_ptr data_client_; std::shared_ptr data_connection_; }; diff --git a/google/cloud/bigtable/testing/table_test_fixture.cc b/google/cloud/bigtable/testing/table_test_fixture.cc deleted file mode 100644 index 9491d9409b998..0000000000000 --- a/google/cloud/bigtable/testing/table_test_fixture.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/cloud/bigtable/testing/table_test_fixture.h" -#include "google/cloud/internal/background_threads_impl.h" -#include "google/cloud/internal/throw_delegate.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -namespace testing { - -char const TableTestFixture::kProjectId[] = "foo-project"; -char const TableTestFixture::kInstanceId[] = "bar-instance"; -char const TableTestFixture::kTableId[] = "baz-table"; - -// These are hardcoded, and not computed, because we want to test the -// computation. -char const TableTestFixture::kInstanceName[] = - "projects/foo-project/instances/bar-instance"; -char const TableTestFixture::kTableName[] = - "projects/foo-project/instances/bar-instance/tables/baz-table"; - -google::bigtable::v2::ReadRowsResponse ReadRowsResponseFromString( - std::string const& repr) { - google::bigtable::v2::ReadRowsResponse response; - if (!google::protobuf::TextFormat::ParseFromString(repr, &response)) { - google::cloud::internal::ThrowRuntimeError("Failed to parse " + repr); - } - return response; -} - -std::shared_ptr TableTestFixture::SetupMockClient() { - auto client = std::make_shared( - Options{}.set(cq_)); - EXPECT_CALL(*client, project_id()) - .WillRepeatedly(::testing::ReturnRef(project_id_)); - EXPECT_CALL(*client, instance_id()) - .WillRepeatedly(::testing::ReturnRef(instance_id_)); - return client; -} - -TableTestFixture::TableTestFixture(CompletionQueue const& cq) - : cq_impl_(std::dynamic_pointer_cast< - ::google::cloud::testing_util::FakeCompletionQueueImpl>( - google::cloud::internal::GetCompletionQueueImpl(cq))), - cq_(cq), - client_(SetupMockClient()) {} - -} // namespace testing -} // namespace bigtable -} // namespace cloud -} // namespace google diff --git a/google/cloud/bigtable/testing/table_test_fixture.h b/google/cloud/bigtable/testing/table_test_fixture.h deleted file mode 100644 index 72fd4c5924898..0000000000000 --- a/google/cloud/bigtable/testing/table_test_fixture.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_TABLE_TEST_FIXTURE_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_TABLE_TEST_FIXTURE_H - -#include "google/cloud/bigtable/table.h" -#include "google/cloud/bigtable/testing/mock_data_client.h" -#include "google/cloud/testing_util/fake_completion_queue_impl.h" -#include - -namespace google { -namespace cloud { -namespace bigtable { -namespace testing { - -/// Common fixture for the bigtable::Table tests. -class TableTestFixture : public ::testing::Test { - protected: - explicit TableTestFixture(CompletionQueue const& cq); - std::shared_ptr SetupMockClient(); - - static char const kProjectId[]; - static char const kInstanceId[]; - static char const kTableId[]; - static char const kInstanceName[]; - static char const kTableName[]; - - std::string project_id_ = kProjectId; - std::string instance_id_ = kInstanceId; - std::shared_ptr<::google::cloud::testing_util::FakeCompletionQueueImpl> - cq_impl_; - CompletionQueue cq_; - std::shared_ptr client_; - bigtable::Table table_ = bigtable::Table(client_, kTableId); -}; - -google::bigtable::v2::ReadRowsResponse ReadRowsResponseFromString( - std::string const& repr); - -} // namespace testing -} // namespace bigtable -} // namespace cloud -} // namespace google - -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TESTING_TABLE_TEST_FIXTURE_H diff --git a/google/cloud/bigtable/tests/admin_integration_test.cc b/google/cloud/bigtable/tests/admin_integration_test.cc index fd056d5382c2f..456343334b381 100644 --- a/google/cloud/bigtable/tests/admin_integration_test.cc +++ b/google/cloud/bigtable/tests/admin_integration_test.cc @@ -155,7 +155,8 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTable) { // Create table ASSERT_STATUS_OK(table_admin_->CreateTable(table_id, table_config)); - bigtable::Table table(data_client_, table_id); + bigtable::Table table(MakeDataConnection(), + TableResource(project_id(), instance_id(), table_id)); // List tables auto tables = table_admin_->ListTables(btadmin::Table::NAME_ONLY); @@ -258,7 +259,6 @@ TEST_F(AdminIntegrationTest, WaitForConsistencyCheck) { // to propagate to both clusters. First create a `bigtable::Table` object. auto table = Table(MakeDataConnection(), TableResource(project_id(), id, random_table_id)); - // Insert some cells into the table. std::string const row_key1 = "check-consistency-row1"; std::string const row_key2 = "check-consistency-row2"; @@ -318,7 +318,8 @@ TEST_F(AdminIntegrationTest, CreateListGetDeleteTableWithLogging) { // Create table ASSERT_STATUS_OK(table_admin->CreateTable(table_id, table_config)); - bigtable::Table table(data_client_, table_id); + bigtable::Table table(MakeDataConnection(), + TableResource(project_id(), instance_id(), table_id)); // List tables auto tables = table_admin->ListTables(btadmin::Table::NAME_ONLY); diff --git a/google/cloud/bigtable/tests/data_async_future_integration_test.cc b/google/cloud/bigtable/tests/data_async_future_integration_test.cc index c884c571e405b..56defb4862194 100644 --- a/google/cloud/bigtable/tests/data_async_future_integration_test.cc +++ b/google/cloud/bigtable/tests/data_async_future_integration_test.cc @@ -25,18 +25,12 @@ namespace { using ::google::cloud::bigtable::testing::TableIntegrationTest; using ::google::cloud::testing_util::chrono_literals::operator""_ms; -class DataAsyncIntegrationTest - : public TableIntegrationTest, - public ::testing::WithParamInterface {}; - -INSTANTIATE_TEST_SUITE_P(, DataAsyncIntegrationTest, - ::testing::Values("with-data-connection", - "with-data-client")); +class DataAsyncIntegrationTest : public TableIntegrationTest {}; std::string const kFamily = "family1"; -TEST_P(DataAsyncIntegrationTest, TableAsyncApply) { - auto table = GetTable(GetParam()); +TEST_F(DataAsyncIntegrationTest, TableAsyncApply) { + auto table = GetTable(); std::string const row_key = "key-000010"; std::vector created{{row_key, kFamily, "cc1", 1000, "v1000"}, @@ -67,8 +61,8 @@ TEST_P(DataAsyncIntegrationTest, TableAsyncApply) { CheckEqualUnordered(expected, actual); } -TEST_P(DataAsyncIntegrationTest, TableAsyncBulkApply) { - auto table = GetTable(GetParam()); +TEST_F(DataAsyncIntegrationTest, TableAsyncBulkApply) { + auto table = GetTable(); std::string const row_key1 = "key-000010"; std::string const row_key2 = "key-000020"; @@ -115,8 +109,8 @@ TEST_P(DataAsyncIntegrationTest, TableAsyncBulkApply) { CheckEqualUnordered(expected, actual); } -TEST_P(DataAsyncIntegrationTest, TableAsyncCheckAndMutateRowPass) { - auto table = GetTable(GetParam()); +TEST_F(DataAsyncIntegrationTest, TableAsyncCheckAndMutateRowPass) { + auto table = GetTable(); std::string const key = "row-key"; @@ -142,8 +136,8 @@ TEST_P(DataAsyncIntegrationTest, TableAsyncCheckAndMutateRowPass) { CheckEqualUnordered(expected, actual); } -TEST_P(DataAsyncIntegrationTest, TableAsyncCheckAndMutateRowFail) { - auto table = GetTable(GetParam()); +TEST_F(DataAsyncIntegrationTest, TableAsyncCheckAndMutateRowFail) { + auto table = GetTable(); std::string const key = "row-key"; @@ -169,8 +163,8 @@ TEST_P(DataAsyncIntegrationTest, TableAsyncCheckAndMutateRowFail) { CheckEqualUnordered(expected, actual); } -TEST_P(DataAsyncIntegrationTest, TableAsyncReadModifyWriteAppendValueTest) { - auto table = GetTable(GetParam()); +TEST_F(DataAsyncIntegrationTest, TableAsyncReadModifyWriteAppendValueTest) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; std::string const add_suffix1 = "-suffix"; @@ -225,8 +219,8 @@ TEST_P(DataAsyncIntegrationTest, TableAsyncReadModifyWriteAppendValueTest) { actual_cells_ignore_timestamp); } -TEST_P(DataAsyncIntegrationTest, TableAsyncReadRowsAllRows) { - auto table = GetTable(GetParam()); +TEST_F(DataAsyncIntegrationTest, TableAsyncReadRowsAllRows) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; @@ -264,8 +258,8 @@ TEST_P(DataAsyncIntegrationTest, TableAsyncReadRowsAllRows) { CheckEqualUnordered(created, actual); } -TEST_P(DataAsyncIntegrationTest, TableAsyncReadRowTest) { - auto table = GetTable(GetParam()); +TEST_F(DataAsyncIntegrationTest, TableAsyncReadRowTest) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; diff --git a/google/cloud/bigtable/tests/data_integration_test.cc b/google/cloud/bigtable/tests/data_integration_test.cc index 9a835f61176e3..e9f210ac817a0 100644 --- a/google/cloud/bigtable/tests/data_integration_test.cc +++ b/google/cloud/bigtable/tests/data_integration_test.cc @@ -17,12 +17,14 @@ #include "google/cloud/bigtable/options.h" #include "google/cloud/bigtable/retry_policy.h" #include "google/cloud/bigtable/testing/table_integration_test.h" +#include "google/cloud/grpc_options.h" #include "google/cloud/log.h" #include "google/cloud/testing_util/chrono_literals.h" #include "google/cloud/testing_util/scoped_environment.h" #include "google/cloud/testing_util/scoped_log.h" #include "google/cloud/testing_util/status_matchers.h" #include "absl/strings/str_format.h" +#include "absl/strings/str_split.h" #include namespace google { @@ -43,13 +45,7 @@ using ::testing::HasSubstr; using ::testing::UnorderedElementsAre; using ms = std::chrono::milliseconds; -class DataIntegrationTest : public TableIntegrationTest, - public ::testing::WithParamInterface { -}; - -INSTANTIATE_TEST_SUITE_P(, DataIntegrationTest, - ::testing::Values("with-data-connection", - "with-data-client")); +class DataIntegrationTest : public TableIntegrationTest {}; /// Use Table::Apply() to insert a single row. void Apply(Table& table, std::string const& row_key, @@ -90,8 +86,8 @@ std::string const kFamily2 = "family2"; std::string const kFamily3 = "family3"; std::string const kFamily4 = "family4"; -TEST_P(DataIntegrationTest, TableApply) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableApply) { + auto table = GetTable(); std::string const row_key = "row-key-1"; std::vector created{{row_key, kFamily4, "c0", 1000, "v1000"}, @@ -104,8 +100,8 @@ TEST_P(DataIntegrationTest, TableApply) { CheckEqualUnordered(expected, actual); } -TEST_P(DataIntegrationTest, TableBulkApply) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableBulkApply) { + auto table = GetTable(); std::vector created{{"row-key-1", kFamily4, "c0", 1000, "v1000"}, {"row-key-1", kFamily4, "c1", 2000, "v2000"}, @@ -129,9 +125,7 @@ TEST_P(DataIntegrationTest, TableBulkApply) { CheckEqualUnordered(expected, actual); } -TEST_P(DataIntegrationTest, TableBulkApplyThrottling) { - if (GetParam() == "with-data-client") GTEST_SKIP(); - +TEST_F(DataIntegrationTest, TableBulkApplyThrottling) { // Make a custom table with throttling enabled. auto table = Table(MakeDataConnection( @@ -158,9 +152,9 @@ TEST_P(DataIntegrationTest, TableBulkApplyThrottling) { CheckEqualUnordered({expected}, actual); } -TEST_P(DataIntegrationTest, TableSingleRow) { +TEST_F(DataIntegrationTest, TableSingleRow) { std::string const row_key = "row-key-1"; - auto table = GetTable(GetParam()); + auto table = GetTable(); auto mutation = SingleRowMutation(row_key, SetCell(kFamily4, "c1", 1_ms, "V1000"), @@ -175,8 +169,8 @@ TEST_P(DataIntegrationTest, TableSingleRow) { CheckEqualUnordered(expected, actual); } -TEST_P(DataIntegrationTest, TableReadRowTest) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadRowTest) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; @@ -192,8 +186,8 @@ TEST_P(DataIntegrationTest, TableReadRowTest) { CheckEqualUnordered(expected, actual); } -TEST_P(DataIntegrationTest, TableReadRowNotExistTest) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadRowNotExistTest) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; @@ -205,8 +199,8 @@ TEST_P(DataIntegrationTest, TableReadRowNotExistTest) { EXPECT_FALSE(row_cell->first); } -TEST_P(DataIntegrationTest, TableReadRowsAllRows) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadRowsAllRows) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; std::string const row_key3(1024, '3'); // a long key @@ -237,8 +231,8 @@ TEST_P(DataIntegrationTest, TableReadRowsAllRows) { CheckEqualUnordered(created, MoveCellsFromReader(read4)); } -TEST_P(DataIntegrationTest, TableReadRowsPartialRows) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadRowsPartialRows) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; std::string const row_key3 = "row-key-3"; @@ -279,11 +273,10 @@ TEST_P(DataIntegrationTest, TableReadRowsPartialRows) { } } -TEST_P(DataIntegrationTest, TableReadRowsReverseScan) { - if (GetParam() == "with-data-client") GTEST_SKIP(); +TEST_F(DataIntegrationTest, TableReadRowsReverseScan) { // The emulator does not yet support reverse scans. if (UsingCloudBigtableEmulator()) GTEST_SKIP(); - auto table = GetTable(GetParam()); + auto table = GetTable(); std::vector created{{"row-key-1", kFamily4, "c1", 1000, "a"}, {"row-key-1", kFamily4, "c2", 2000, "b"}, @@ -303,8 +296,8 @@ TEST_P(DataIntegrationTest, TableReadRowsReverseScan) { ElementsAre("row-key-3", "row-key-2", "row-key-1", "row-key-1")); } -TEST_P(DataIntegrationTest, TableReadRowsNoRows) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadRowsNoRows) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; std::string const row_key3 = "row-key-3"; @@ -329,8 +322,8 @@ TEST_P(DataIntegrationTest, TableReadRowsNoRows) { CheckEqualUnordered(expected, MoveCellsFromReader(read3)); } -TEST_P(DataIntegrationTest, TableReadRowsWrongTable) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadRowsWrongTable) { + auto table = GetTable(); auto other_table = table.WithNewTarget(table.project_id(), table.instance_id(), RandomTableId()); @@ -343,8 +336,8 @@ TEST_P(DataIntegrationTest, TableReadRowsWrongTable) { EXPECT_EQ(read1.end(), it); } -TEST_P(DataIntegrationTest, TableCheckAndMutateRowPass) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableCheckAndMutateRowPass) { + auto table = GetTable(); std::string const key = "row-key"; std::vector created{{key, kFamily4, "c1", 0, "v1000"}}; @@ -361,8 +354,8 @@ TEST_P(DataIntegrationTest, TableCheckAndMutateRowPass) { CheckEqualUnordered(expected, actual); } -TEST_P(DataIntegrationTest, TableCheckAndMutateRowFail) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableCheckAndMutateRowFail) { + auto table = GetTable(); std::string const key = "row-key"; std::vector created{{key, kFamily4, "c1", 0, "v1000"}}; @@ -379,8 +372,8 @@ TEST_P(DataIntegrationTest, TableCheckAndMutateRowFail) { CheckEqualUnordered(expected, actual); } -TEST_P(DataIntegrationTest, TableReadModifyWriteAppendValueTest) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadModifyWriteAppendValueTest) { + auto table = GetTable(); std::string const row_key1 = "row-key-1"; std::string const row_key2 = "row-key-2"; std::string const add_suffix1 = "-suffix"; @@ -415,8 +408,8 @@ TEST_P(DataIntegrationTest, TableReadModifyWriteAppendValueTest) { actual_cells_ignore_timestamp); } -TEST_P(DataIntegrationTest, TableReadModifyWriteRowIncrementAmountTest) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadModifyWriteRowIncrementAmountTest) { + auto table = GetTable(); std::string const key = "row-key"; // An initial; big-endian int64 number with value 0. @@ -442,8 +435,8 @@ TEST_P(DataIntegrationTest, TableReadModifyWriteRowIncrementAmountTest) { CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp); } -TEST_P(DataIntegrationTest, TableReadModifyWriteRowMultipleTest) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadModifyWriteRowMultipleTest) { + auto table = GetTable(); std::string const key = "row-key"; std::string v1("\x00\x00\x00\x00\x00\x00\x00\x00", 8); @@ -486,8 +479,8 @@ TEST_P(DataIntegrationTest, TableReadModifyWriteRowMultipleTest) { CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp); } -TEST_P(DataIntegrationTest, TableCellValueInt64Test) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableCellValueInt64Test) { + auto table = GetTable(); std::string const key = "row-key"; std::vector created{{key, kFamily1, "c1", 0, 42}, @@ -521,8 +514,8 @@ TEST_P(DataIntegrationTest, TableCellValueInt64Test) { CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp); } -TEST_P(DataIntegrationTest, TableReadMultipleCellsBigValue) { - auto table = GetTable(GetParam()); +TEST_F(DataIntegrationTest, TableReadMultipleCellsBigValue) { + auto table = GetTable(); std::string const row_key = "row-key-1"; // cell vector contains 4 cells of 32 MiB each, or 128 MiB (without @@ -573,7 +566,7 @@ TEST_P(DataIntegrationTest, TableReadMultipleCellsBigValue) { CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp); } -TEST_P(DataIntegrationTest, TableApplyWithLogging) { +TEST_F(DataIntegrationTest, TableApplyWithLogging) { // In our ci builds, we set GOOGLE_CLOUD_CPP_ENABLE_TRACING to log our tests, // by default. We should unset this variable and create a fresh client in // order to have a conclusive test. @@ -585,13 +578,9 @@ TEST_P(DataIntegrationTest, TableApplyWithLogging) { // Make a `Table` with an implementation that depends on the test's value // parameter. auto make_table = [&](Options const& options) { - if (GetParam() == "with-data-connection") { - auto conn = MakeDataConnection(options); - return Table(std::move(conn), - TableResource(project_id(), instance_id(), table_id)); - } - auto data_client = MakeDataClient(project_id(), instance_id(), options); - return Table(std::move(data_client), table_id); + auto conn = MakeDataConnection(options); + return Table(std::move(conn), + TableResource(project_id(), instance_id(), table_id)); }; std::string const row_key = "row-key-1"; @@ -610,7 +599,7 @@ TEST_P(DataIntegrationTest, TableApplyWithLogging) { EXPECT_THAT(log.ExtractLines(), Not(Contains(HasSubstr("MutateRow")))); } -TEST_P(DataIntegrationTest, ClientQueryColumnFamily) { +TEST_F(DataIntegrationTest, ClientQueryColumnFamily) { if (UsingCloudBigtableEmulator()) GTEST_SKIP(); auto const table_id = testing::TableTestEnvironment::table_id(); auto retry_policy_option = DataLimitedErrorCountRetryPolicy(0).clone(); @@ -676,7 +665,7 @@ TEST_P(DataIntegrationTest, ClientQueryColumnFamily) { {Bytes(column2), Bytes(value2)}})); } -TEST_P(DataIntegrationTest, ClientQueryColumnFamilyWithHistory) { +TEST_F(DataIntegrationTest, ClientQueryColumnFamilyWithHistory) { if (UsingCloudBigtableEmulator()) GTEST_SKIP(); auto const table_id = testing::TableTestEnvironment::table_id(); auto retry_policy_option = DataLimitedErrorCountRetryPolicy(0).clone(); @@ -820,76 +809,7 @@ TEST_P(DataIntegrationTest, ClientQueryColumnFamilyWithHistory) { column_2_value_old); } -// TODO(#8800) - remove after deprecation is complete -#include "google/cloud/internal/disable_deprecation_warnings.inc" - -TEST(ConnectionRefresh, Disabled) { - auto data_client = bigtable::MakeDataClient( - testing::TableTestEnvironment::project_id(), - testing::TableTestEnvironment::instance_id(), - Options{}.set(std::chrono::seconds(0))); - // In general, it is hard to show that something has *not* happened, at best - // we can show that its side-effects have not happened. In this case we want - // to show that the channels have not been refreshed. A side-effect of - // refreshing a channel is that it enters the `READY` state, so we check that - // this has not taken place and take that as evidence that no refresh has - // taken place. - // - // After the `CompletionQueue` argument is removed from the `Bigtable` API, we - // will have an option to provide a mock `CompletionQueue` to the `DataClient` - // for test purposes and verify that no timers are created, which will be a - // superior way to write this test. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - for (int i = 0; i < internal::DefaultConnectionPoolSize(); ++i) { - auto channel = data_client->Channel(); - EXPECT_EQ(GRPC_CHANNEL_IDLE, channel->GetState(false)); - } - // Make sure things still work. - bigtable::Table table(data_client, testing::TableTestEnvironment::table_id()); - std::string const row_key = "row-key-1"; - std::vector created{{row_key, kFamily4, "c0", 1000, "v1000"}, - {row_key, kFamily4, "c1", 2000, "v2000"}}; - Apply(table, row_key, created); - // After performing some operations, some of the channels should be in ready - // state. - auto check_if_some_channel_is_ready = [&] { - for (int i = 0; i < internal::DefaultConnectionPoolSize(); ++i) { - if (data_client->Channel()->GetState(false) == GRPC_CHANNEL_READY) { - return true; - } - } - return false; - }; - EXPECT_TRUE(check_if_some_channel_is_ready()); -} - -TEST(ConnectionRefresh, Frequent) { - auto data_client = bigtable::MakeDataClient( - testing::TableTestEnvironment::project_id(), - testing::TableTestEnvironment::instance_id(), - Options{} - .set(std::chrono::milliseconds(100)) - .set(std::chrono::milliseconds(100))); - - for (;;) { - if (data_client->Channel()->GetState(false) == GRPC_CHANNEL_READY) { - // We've found a channel which changed its state from IDLE to READY, - // which means that our refreshing mechanism works. - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - // Make sure things still work. - bigtable::Table table(data_client, testing::TableTestEnvironment::table_id()); - std::string const row_key = "row-key-1"; - std::vector created{{row_key, kFamily4, "c0", 1000, "v1000"}, - {row_key, kFamily4, "c1", 2000, "v2000"}}; - Apply(table, row_key, created); -} - -TEST_P(DataIntegrationTest, SingleColumnQuery) { +TEST_F(DataIntegrationTest, SingleColumnQuery) { if (UsingCloudBigtableEmulator()) GTEST_SKIP(); auto const table_id = testing::TableTestEnvironment::table_id(); auto retry_policy_option = DataLimitedErrorCountRetryPolicy(0).clone(); @@ -952,7 +872,7 @@ TEST_P(DataIntegrationTest, SingleColumnQuery) { EXPECT_EQ(*value, value1); } -TEST_P(DataIntegrationTest, SingleColumnQueryWithHistory) { +TEST_F(DataIntegrationTest, SingleColumnQueryWithHistory) { if (UsingCloudBigtableEmulator()) GTEST_SKIP(); auto const table_id = testing::TableTestEnvironment::table_id(); auto retry_policy_option = DataLimitedErrorCountRetryPolicy(0).clone(); @@ -1056,7 +976,7 @@ TEST_P(DataIntegrationTest, SingleColumnQueryWithHistory) { EXPECT_EQ(std::get<1>(entry1), value_old); } -TEST_P(DataIntegrationTest, MultiColumnQuery) { +TEST_F(DataIntegrationTest, MultiColumnQuery) { if (UsingCloudBigtableEmulator()) GTEST_SKIP(); auto const table_id = testing::TableTestEnvironment::table_id(); auto retry_policy_option = DataLimitedErrorCountRetryPolicy(0).clone(); @@ -1123,7 +1043,7 @@ TEST_P(DataIntegrationTest, MultiColumnQuery) { RowType("multi-column-query-row-2", "v21", "v22"))); } -TEST_P(DataIntegrationTest, QueryWithNulls) { +TEST_F(DataIntegrationTest, QueryWithNulls) { if (UsingCloudBigtableEmulator()) GTEST_SKIP(); auto const table_id = testing::TableTestEnvironment::table_id(); auto retry_policy_option = DataLimitedErrorCountRetryPolicy(0).clone(); diff --git a/google/cloud/bigtable/tests/filters_integration_test.cc b/google/cloud/bigtable/tests/filters_integration_test.cc index aeea0834efb22..6f485da04b451 100644 --- a/google/cloud/bigtable/tests/filters_integration_test.cc +++ b/google/cloud/bigtable/tests/filters_integration_test.cc @@ -95,7 +95,7 @@ void CreateComplexRows(Table& table, std::string const& prefix) { }; TEST_F(FilterIntegrationTest, PassAll) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "pass-all-row-key"; std::vector expected{ {row_key, "family1", "c", 0, "v-c-0-0"}, @@ -112,7 +112,7 @@ TEST_F(FilterIntegrationTest, PassAll) { } TEST_F(FilterIntegrationTest, BlockAll) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "block-all-row-key"; std::vector created{ {row_key, "family1", "c", 0, "v-c-0-0"}, @@ -130,7 +130,7 @@ TEST_F(FilterIntegrationTest, BlockAll) { } TEST_F(FilterIntegrationTest, Latest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "latest-row-key"; std::vector created{ {row_key, "family1", "c", 0, "v-c-0-0"}, @@ -155,7 +155,7 @@ TEST_F(FilterIntegrationTest, Latest) { } TEST_F(FilterIntegrationTest, FamilyRegex) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "family-regex-row-key"; std::vector created{ {row_key, "family1", "c2", 0, "bar"}, @@ -178,7 +178,7 @@ TEST_F(FilterIntegrationTest, FamilyRegex) { } TEST_F(FilterIntegrationTest, ColumnRegex) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "column-regex-row-key"; std::vector created{ {row_key, "family1", "abc", 0, "bar"}, @@ -201,7 +201,7 @@ TEST_F(FilterIntegrationTest, ColumnRegex) { } TEST_F(FilterIntegrationTest, ColumnRange) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "column-range-row-key"; std::vector created{ {row_key, "family1", "a00", 0, "bar"}, @@ -223,7 +223,7 @@ TEST_F(FilterIntegrationTest, ColumnRange) { } TEST_F(FilterIntegrationTest, TimestampRange) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "timestamp-range-row-key"; std::vector created{ {row_key, "family1", "c0", 1000, "v1000"}, @@ -247,7 +247,7 @@ TEST_F(FilterIntegrationTest, TimestampRange) { } TEST_F(FilterIntegrationTest, RowKeysRegex) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const row_key = "row-key-regex-row-key"; std::vector created{ {row_key + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -267,7 +267,7 @@ TEST_F(FilterIntegrationTest, RowKeysRegex) { } TEST_F(FilterIntegrationTest, ValueRegex) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "value-regex-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -288,7 +288,7 @@ TEST_F(FilterIntegrationTest, ValueRegex) { } TEST_F(FilterIntegrationTest, ValueRange) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "value-range-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -311,7 +311,7 @@ TEST_F(FilterIntegrationTest, ValueRange) { } TEST_F(FilterIntegrationTest, CellsRowLimit) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "cell-row-limit-prefix"; ASSERT_NO_FATAL_FAILURE(CreateComplexRows(table, prefix)); @@ -332,7 +332,7 @@ TEST_F(FilterIntegrationTest, CellsRowLimit) { } TEST_F(FilterIntegrationTest, CellsRowOffset) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "cell-row-offset-prefix"; ASSERT_NO_FATAL_FAILURE(CreateComplexRows(table, prefix)); @@ -353,7 +353,7 @@ TEST_F(FilterIntegrationTest, CellsRowOffset) { } TEST_F(FilterIntegrationTest, RowSample) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "row-sample-prefix"; int constexpr kRowCount = 20000; @@ -408,7 +408,7 @@ TEST_F(FilterIntegrationTest, RowSample) { } TEST_F(FilterIntegrationTest, StripValueTransformer) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "strip-value-transformer-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -433,7 +433,7 @@ TEST_F(FilterIntegrationTest, StripValueTransformer) { } TEST_F(FilterIntegrationTest, ApplyLabelTransformer) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "apply-label-transformer-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -458,7 +458,7 @@ TEST_F(FilterIntegrationTest, ApplyLabelTransformer) { } TEST_F(FilterIntegrationTest, Condition) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "condition-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -486,7 +486,7 @@ TEST_F(FilterIntegrationTest, Condition) { } TEST_F(FilterIntegrationTest, Chain) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "chain-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -510,7 +510,7 @@ TEST_F(FilterIntegrationTest, Chain) { } TEST_F(FilterIntegrationTest, ChainFromRange) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "chain-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -534,7 +534,7 @@ TEST_F(FilterIntegrationTest, ChainFromRange) { } TEST_F(FilterIntegrationTest, Interleave) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "interleave-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, @@ -562,7 +562,7 @@ TEST_F(FilterIntegrationTest, Interleave) { } TEST_F(FilterIntegrationTest, InterleaveFromRange) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); std::string const prefix = "interleave-prefix"; std::vector created{ {prefix + "/abc0", "family1", "c0", 1000, "v1000"}, diff --git a/google/cloud/bigtable/tests/mutations_integration_test.cc b/google/cloud/bigtable/tests/mutations_integration_test.cc index ccd9e7ad3c574..6efaf27f79a85 100644 --- a/google/cloud/bigtable/tests/mutations_integration_test.cc +++ b/google/cloud/bigtable/tests/mutations_integration_test.cc @@ -62,7 +62,7 @@ std::string const kColumnFamily3 = "family3"; * Cloud Bigtable */ TEST_F(MutationIntegrationTest, SetCellTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cells which will be inserted into bigtable std::string const row_key = "SetCellRowKey"; @@ -86,7 +86,7 @@ TEST_F(MutationIntegrationTest, SetCellTest) { * correctly inserted into Cloud Bigtable */ TEST_F(MutationIntegrationTest, SetCellNumericValueTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cells which will be inserted into bigtable std::string const row_key = "SetCellNumRowKey"; @@ -129,7 +129,7 @@ TEST_F(MutationIntegrationTest, SetCellNumericValueErrorTest) { * correctly inserted into Cloud Bigtable. */ TEST_F(MutationIntegrationTest, SetCellIgnoreTimestampTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const row_key = "SetCellRowKey"; @@ -167,7 +167,7 @@ TEST_F(MutationIntegrationTest, SetCellIgnoreTimestampTest) { * Bigtable. */ TEST_F(MutationIntegrationTest, DeleteFromColumnForTimestampRangeTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const row_key = "DeleteColumn-Key"; @@ -212,7 +212,7 @@ TEST_F(MutationIntegrationTest, DeleteFromColumnForTimestampRangeTest) { * We expect the server (and not the client library) to reject invalid ranges. */ TEST_F(MutationIntegrationTest, DeleteFromColumnForReversedTimestampRangeTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const key = "row"; @@ -245,7 +245,7 @@ TEST_F(MutationIntegrationTest, DeleteFromColumnForReversedTimestampRangeTest) { * We expect the server (and not the client library) to reject invalid ranges. */ TEST_F(MutationIntegrationTest, DeleteFromColumnForEmptyTimestampRangeTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const key = "row"; @@ -270,7 +270,7 @@ TEST_F(MutationIntegrationTest, DeleteFromColumnForEmptyTimestampRangeTest) { * is deleting all records only for that column_identifier. */ TEST_F(MutationIntegrationTest, DeleteFromColumnForAllTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const row_key = "DeleteColumnForAll-Key"; @@ -304,7 +304,7 @@ TEST_F(MutationIntegrationTest, DeleteFromColumnForAllTest) { * timestamp only. */ TEST_F(MutationIntegrationTest, DeleteFromColumnStartingFromTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const row_key = "DeleteColumnStartingFrom-Key"; @@ -341,7 +341,7 @@ TEST_F(MutationIntegrationTest, DeleteFromColumnStartingFromTest) { * timestamp only. end_timestamp is not inclusive. */ TEST_F(MutationIntegrationTest, DeleteFromColumnEndingAtTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable cloud std::string const row_key = "DeleteColumnEndingAt-Key"; @@ -379,7 +379,7 @@ TEST_F(MutationIntegrationTest, DeleteFromColumnEndingAtTest) { * records for that family only */ TEST_F(MutationIntegrationTest, DeleteFromFamilyTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const row_key = "DeleteFamily-Key"; @@ -411,7 +411,7 @@ TEST_F(MutationIntegrationTest, DeleteFromFamilyTest) { * records for that row only */ TEST_F(MutationIntegrationTest, DeleteFromRowTest) { - auto table = GetTable("with-data-connection"); + auto table = GetTable(); // Create a vector of cell which will be inserted into bigtable std::string const row_key1 = "DeleteRowKey1"; diff --git a/google/cloud/bigtable/tests/table_sample_rows_integration_test.cc b/google/cloud/bigtable/tests/table_sample_rows_integration_test.cc index bdb78871a410c..f0006db7c6c9c 100644 --- a/google/cloud/bigtable/tests/table_sample_rows_integration_test.cc +++ b/google/cloud/bigtable/tests/table_sample_rows_integration_test.cc @@ -13,7 +13,6 @@ // limitations under the License. #include "google/cloud/bigtable/client_options.h" -#include "google/cloud/bigtable/data_client.h" #include "google/cloud/bigtable/mutations.h" #include "google/cloud/bigtable/row_key_sample.h" #include "google/cloud/bigtable/table.h" @@ -38,12 +37,6 @@ namespace { using ::google::cloud::bigtable::testing::TableTestEnvironment; using ::testing::IsEmpty; -Table GetTable() { - return Table(MakeDataClient(TableTestEnvironment::project_id(), - TableTestEnvironment::instance_id()), - TableTestEnvironment::table_id()); -} - void VerifySamples(StatusOr> samples) { ASSERT_STATUS_OK(samples); @@ -135,21 +128,6 @@ TEST_F(SampleRowsIntegrationTest, AsyncWithDataConnection) { VerifySamples(fut.get()); }; -TEST_F(SampleRowsIntegrationTest, SyncWithDataClient) { - auto table = GetTable(); - VerifySamples(table.SampleRows()); -}; - -TEST_F(SampleRowsIntegrationTest, AsyncWithDataClient) { - auto table = GetTable(); - auto fut = table.AsyncSampleRows(); - - // Block until the asynchronous operation completes. This is not what one - // would do in a real application (the synchronous API is better in that - // case), but we need to wait before checking the results. - VerifySamples(fut.get()); -}; - } // namespace GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable From 0378315ee7ff38932104fbf836c81d56f911784b Mon Sep 17 00:00:00 2001 From: mpeddada1 Date: Wed, 24 Dec 2025 16:16:26 +0000 Subject: [PATCH 2/2] fix Cmake --- google/cloud/bigtable/CMakeLists.txt | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index 2c3d3ca3c026f..2b8e9de9a3f11 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -193,16 +193,6 @@ add_library( internal/defaults.h internal/google_bytes_traits.cc internal/google_bytes_traits.h - internal/legacy_async_bulk_apply.cc - internal/legacy_async_bulk_apply.h - internal/legacy_async_row_reader.cc - internal/legacy_async_row_reader.h - internal/legacy_async_row_sampler.cc - internal/legacy_async_row_sampler.h - internal/legacy_row_reader.cc - internal/legacy_row_reader.h - internal/logging_data_client.cc - internal/logging_data_client.h internal/logging_result_set_reader.cc internal/logging_result_set_reader.h internal/metrics.cc @@ -403,7 +393,6 @@ if (BUILD_TESTING) testing/embedded_server_test_fixture.h testing/mock_async_failing_rpc_factory.h testing/mock_bigtable_stub.h - testing/mock_data_client.h testing/mock_mutate_rows_limiter.h testing/mock_mutate_rows_reader.h testing/mock_partial_result_set_reader.h @@ -414,9 +403,7 @@ if (BUILD_TESTING) testing/random_names.cc testing/random_names.h testing/table_integration_test.cc - testing/table_integration_test.h - testing/table_test_fixture.cc - testing/table_test_fixture.h) + testing/table_integration_test.h) target_link_libraries( bigtable_client_testing PUBLIC google-cloud-cpp::bigtable @@ -480,12 +467,6 @@ if (BUILD_TESTING) internal/default_row_reader_test.cc internal/defaults_test.cc internal/google_bytes_traits_test.cc - internal/legacy_async_bulk_apply_test.cc - internal/legacy_async_row_reader_test.cc - internal/legacy_async_row_sampler_test.cc - internal/legacy_bulk_mutator_test.cc - internal/legacy_row_reader_test.cc - internal/logging_data_client_test.cc internal/logging_result_set_reader_test.cc internal/metrics_test.cc internal/mutate_rows_limiter_test.cc @@ -499,7 +480,6 @@ if (BUILD_TESTING) internal/retry_traits_test.cc internal/traced_row_reader_test.cc internal/tuple_utils_test.cc - legacy_table_test.cc metadata_update_policy_test.cc mocks/mock_row_reader_test.cc mutation_batcher_test.cc @@ -517,11 +497,7 @@ if (BUILD_TESTING) rpc_retry_policy_test.cc sql_statement_test.cc table_admin_test.cc - table_apply_test.cc - table_bulk_apply_test.cc table_config_test.cc - table_readrow_test.cc - table_readrows_test.cc table_resource_test.cc table_test.cc testing/cleanup_stale_resources_test.cc