Skip to content

Commit b29d621

Browse files
committed
test(bigtable): add conformance test for ExecuteQuery
1 parent 829bce3 commit b29d621

File tree

3 files changed

+162
-3
lines changed

3 files changed

+162
-3
lines changed

google/cloud/bigtable/test_proxy/cbt_test_proxy.cc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <google/protobuf/util/time_util.h>
2626
#include <chrono>
2727

28+
#include "google/cloud/bigtable/client.h"
29+
2830
namespace google {
2931
namespace cloud {
3032
namespace bigtable {
@@ -34,6 +36,8 @@ namespace {
3436
namespace v2 = ::google::bigtable::v2;
3537
namespace testpb = ::google::bigtable::testproxy;
3638

39+
using ms = std::chrono::milliseconds;
40+
3741
// Convert `Status` to `grpc::Status`, discarding any `details`.
3842
::grpc::Status ToGrpcStatus(Status const& status) {
3943
return ::grpc::Status(static_cast<grpc::StatusCode>(status.code()),
@@ -360,6 +364,66 @@ grpc::Status CbtTestProxy::ReadModifyWriteRow(
360364
return grpc::Status();
361365
}
362366

367+
368+
grpc::Status CbtTestProxy::ExecuteQuery(grpc::ServerContext*,
369+
const google::bigtable::testproxy::ExecuteQueryRequest* request,
370+
google::bigtable::testproxy::ExecuteQueryResult* response) {
371+
// Client options
372+
auto retry_policy_option = DataLimitedErrorCountRetryPolicy(0).clone();
373+
auto backoff_policy_option =
374+
google::cloud::internal::ExponentialBackoffPolicy(ms(0), ms(0), 2.0)
375+
.clone();
376+
auto query_refresh_option =
377+
bigtable::experimental::QueryPlanRefreshLimitedErrorCountRetryPolicy(0)
378+
.clone();
379+
auto opts =
380+
Options{}
381+
.set<DataRetryPolicyOption>(std::move(retry_policy_option))
382+
.set<DataBackoffPolicyOption>(std::move(backoff_policy_option))
383+
.set<bigtable::experimental::QueryPlanRefreshRetryPolicyOption>(
384+
std::move(query_refresh_option));
385+
386+
// Retrieve connection
387+
auto const& conn = GetConnection(request->client_id());
388+
if (!conn.ok()) return ToGrpcStatus(std::move(conn).status());
389+
auto client = bigtable::Client(*conn, opts);
390+
auto request_proto = request->request();
391+
392+
// Call prepare query
393+
auto instance = MakeInstanceResource(request_proto.instance_name());
394+
bigtable::SqlStatement sql_statement{request_proto.query()};
395+
auto prepared_query = client.PrepareQuery(*std::move(instance), sql_statement);
396+
if (!prepared_query.ok()) return ToGrpcStatus(std::move(prepared_query).status());
397+
398+
// Bind parameters
399+
std::unordered_map<std::string, Value> params;
400+
for (auto const& param : request_proto.params()) {
401+
auto value = bigtable_internal::FromProto(param.second.type(), param.second);
402+
params.insert(std::make_pair(param.first, std::move(value)));
403+
}
404+
auto bound_query = prepared_query->BindParameters(params);
405+
RowStream result = client.ExecuteQuery(std::move(bound_query), {});
406+
407+
Status status;
408+
for (auto const& row : result) {
409+
if (!row.ok()) {
410+
status = row.status();
411+
GCP_LOG(INFO) << "Error reading row: " << row.status();
412+
continue;
413+
}
414+
google::bigtable::testproxy::SqlRow proxy_row;
415+
for (auto const& value : row->values()) {
416+
*proxy_row.add_values() = bigtable_internal::ToProto(value).second;
417+
}
418+
*response->add_rows() = std::move(proxy_row);
419+
}
420+
421+
// TODO: we need to set response->mutable_metadata()
422+
423+
*response->mutable_status() = ToRpcStatus(status);
424+
return grpc::Status();
425+
}
426+
363427
StatusOr<std::shared_ptr<DataConnection>> CbtTestProxy::GetConnection(
364428
std::string const& client_id) {
365429
std::lock_guard<std::mutex> lk(mu_);

google/cloud/bigtable/test_proxy/cbt_test_proxy.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,18 @@ class CbtTestProxy final
9191
::google::bigtable::testproxy::ReadModifyWriteRowRequest const* request,
9292
::google::bigtable::testproxy::RowResult* response) override;
9393

94-
private:
94+
grpc::Status ExecuteQuery(grpc::ServerContext* context,
95+
const google::bigtable::testproxy::ExecuteQueryRequest* request,
96+
google::bigtable::testproxy::ExecuteQueryResult* response) override;
97+
98+
private:
9599
StatusOr<std::shared_ptr<DataConnection>> GetConnection(
96100
std::string const& client_id);
97101

98102
StatusOr<Table> GetTableFromRequest(std::string const& client_id,
99103
std::string const& table_name);
100104

105+
private:
101106
std::unordered_map<std::string, std::shared_ptr<DataConnection>> connections_;
102107
std::mutex mu_;
103108
};

protos/google/cloud/bigtable/test_proxy/test_proxy.proto

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2023 Google LLC
1+
// Copyright 2025 Google LLC
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -12,22 +12,56 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
// Copied from https://github.com/googleapis/cndb-client-testing-protos/blob/16a532ea8a56164b921e5f015f04d39e531f8d4d/google/bigtable/testproxy/test_proxy.proto
16+
1517
syntax = "proto3";
1618

1719
package google.bigtable.testproxy;
1820

1921
import "google/api/client.proto";
2022
import "google/bigtable/v2/bigtable.proto";
2123
import "google/bigtable/v2/data.proto";
24+
import "google/protobuf/descriptor.proto";
2225
import "google/protobuf/duration.proto";
2326
import "google/rpc/status.proto";
2427

25-
option go_package = "./testproxypb";
28+
option go_package = "cloud.google.com/go/bigtable/testproxy/testproxypb;testproxypb";
2629
option java_multiple_files = true;
2730
option java_package = "com.google.cloud.bigtable.testproxy";
2831

32+
// A config flag that dictates how the optional features should be enabled
33+
// during the client creation. The optional features customize how the client
34+
// interacts with the server, and are defined in
35+
// https://github.com/googleapis/googleapis/blob/master/google/bigtable/v2/feature_flags.proto
36+
enum OptionalFeatureConfig {
37+
OPTIONAL_FEATURE_CONFIG_DEFAULT = 0;
38+
39+
OPTIONAL_FEATURE_CONFIG_ENABLE_ALL = 1;
40+
}
41+
2942
// Request to test proxy service to create a client object.
3043
message CreateClientRequest {
44+
message SecurityOptions {
45+
// Access token to use for client credentials. If empty, the client will not
46+
// use any call credentials. Certain implementations may require `use_ssl`
47+
// to be set when using this.
48+
string access_token = 1;
49+
50+
// Whether to use SSL channel credentials when connecting to the data
51+
// endpoint.
52+
bool use_ssl = 2;
53+
54+
// If using SSL channel credentials, override the SSL endpoint to match the
55+
// host that is specified in the backend's certificate. Also sets the
56+
// client's authority header value.
57+
string ssl_endpoint_override = 3;
58+
59+
// PEM encoding of the server root certificates. If not set, the default
60+
// root certs will be used instead. The default can be overridden via the
61+
// GRPC_DEFAULT_SSL_ROOTS_FILE_PATH env var.
62+
string ssl_root_certs_pem = 4;
63+
}
64+
3165
// A unique ID associated with the client object to be created.
3266
string client_id = 1;
3367

@@ -52,6 +86,21 @@ message CreateClientRequest {
5286
// the created client. Otherwise, the default timeout from the client library
5387
// will be used. Note that the override applies to all the methods.
5488
google.protobuf.Duration per_operation_timeout = 6;
89+
90+
// Optional config that dictates how the optional features should be enabled
91+
// during the client creation. Please check the enum type's docstring above.
92+
OptionalFeatureConfig optional_feature_config = 7;
93+
94+
// Options to allow connecting to backends with channel and/or call
95+
// credentials. This is needed internally by Cloud Bigtable's own testing
96+
// frameworks.It is not necessary to support these fields for client
97+
// conformance testing.
98+
//
99+
// WARNING: this allows the proxy to connect to a real production
100+
// CBT backend with the right options, however, the proxy itself is insecure
101+
// so it is not recommended to use it with real credentials or outside testing
102+
// contexts.
103+
SecurityOptions security_options = 8;
55104
}
56105

57106
// Response from test proxy service for CreateClientRequest.
@@ -203,6 +252,44 @@ message ReadModifyWriteRowRequest {
203252
google.bigtable.v2.ReadModifyWriteRowRequest request = 2;
204253
}
205254

255+
// Request to test proxy service to execute a query.
256+
message ExecuteQueryRequest {
257+
// The ID of the target client object.
258+
string client_id = 1;
259+
260+
// The raw request to the Bigtable server.
261+
google.bigtable.v2.ExecuteQueryRequest request = 2;
262+
263+
// A collection of proto descriptor files for deserializing PROTO/ENUM columns
264+
// in the query result. The descriptor files must be provided in dependency
265+
// order.
266+
google.protobuf.FileDescriptorSet file_descriptor_set = 3;
267+
}
268+
269+
// Response from test proxy service for ExecuteQueryRequest.
270+
message ExecuteQueryResult {
271+
// The RPC status from the client binding.
272+
google.rpc.Status status = 1;
273+
274+
// Name and type information for the query result.
275+
ResultSetMetadata metadata = 4;
276+
277+
// Encoded version of the ResultSet. Should not contain type information.
278+
repeated SqlRow rows = 3;
279+
}
280+
281+
// Schema information for the query result.
282+
message ResultSetMetadata {
283+
// Column metadata for each column inthe query result.
284+
repeated google.bigtable.v2.ColumnMetadata columns = 1;
285+
}
286+
287+
// Representation of a single row in the query result.
288+
message SqlRow {
289+
// Columnar values returned by the query.
290+
repeated google.bigtable.v2.Value values = 1;
291+
}
292+
206293
// Note that all RPCs are unary, even when the equivalent client binding call
207294
// may be streaming. This is an intentional simplification.
208295
//
@@ -265,4 +352,7 @@ service CloudBigtableV2TestProxy {
265352

266353
// Performs a read-modify-write operation with the client.
267354
rpc ReadModifyWriteRow(ReadModifyWriteRowRequest) returns (RowResult) {}
355+
356+
// Executes a BTQL query with the client.
357+
rpc ExecuteQuery(ExecuteQueryRequest) returns (ExecuteQueryResult) {}
268358
}

0 commit comments

Comments
 (0)