Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit 0db6961

Browse files
committed
tests: Tests for sync client + fixes + client library versioning
1 parent 7c5d29d commit 0db6961

5 files changed

Lines changed: 574 additions & 7 deletions

File tree

google/cloud/bigtable/admin_v2/overlay/services/bigtable_table_admin/client.py

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
# See the License for the specific language governing permissions and
2828
# limitations under the License.
2929

30-
30+
import copy
3131
import functools
3232

33-
from typing import Optional, Sequence, Tuple, Union
33+
from typing import Callable, Optional, Sequence, Tuple, Union
3434
from google.api_core import gapic_v1
3535
from google.api_core import retry as retries
3636

@@ -39,16 +39,97 @@
3939
except AttributeError: # pragma: NO COVER
4040
OptionalRetry = Union[retries.Retry, object, None] # type: ignore
4141

42-
from google.api_core import operation # type: ignore
42+
from google.api_core import client_options as client_options_lib
43+
from google.auth import credentials as ga_credentials # type: ignore
44+
45+
from google.cloud.bigtable import __version__ as bigtable_version
4346
from google.cloud.bigtable.admin_v2.types import bigtable_table_admin
4447

4548
from google.cloud.bigtable.admin_v2.services.bigtable_table_admin import (
46-
BaseBigtableTableAdminClient,
49+
client as base_client,
50+
)
51+
from google.cloud.bigtable.admin_v2.services.bigtable_table_admin.transports.base import (
52+
BigtableTableAdminTransport
4753
)
4854
from google.cloud.bigtable.admin_v2.overlay.types import consistency, restore_table
4955

5056

51-
class BigtableTableAdminClient(BaseBigtableTableAdminClient):
57+
DEFAULT_CLIENT_INFO = copy.copy(base_client.DEFAULT_CLIENT_INFO)
58+
DEFAULT_CLIENT_INFO.client_library_version = f"{bigtable_version}-admin-overlay"
59+
60+
61+
class BigtableTableAdminClient(base_client.BaseBigtableTableAdminClient):
62+
def __init__(
63+
self,
64+
*,
65+
credentials: Optional[ga_credentials.Credentials] = None,
66+
transport: Optional[
67+
Union[
68+
str,
69+
BigtableTableAdminTransport,
70+
Callable[..., BigtableTableAdminTransport],
71+
]
72+
] = None,
73+
client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None,
74+
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
75+
) -> None:
76+
"""Instantiates the Bigtable table admin client.
77+
78+
Args:
79+
credentials (Optional[google.auth.credentials.Credentials]): The
80+
authorization credentials to attach to requests. These
81+
credentials identify the application to the service; if none
82+
are specified, the client will attempt to ascertain the
83+
credentials from the environment.
84+
transport (Optional[Union[str,BigtableTableAdminTransport,Callable[..., BigtableTableAdminTransport]]]):
85+
The transport to use, or a Callable that constructs and returns a new transport.
86+
If a Callable is given, it will be called with the same set of initialization
87+
arguments as used in the BigtableTableAdminTransport constructor.
88+
If set to None, a transport is chosen automatically.
89+
client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]):
90+
Custom options for the client.
91+
92+
1. The ``api_endpoint`` property can be used to override the
93+
default endpoint provided by the client when ``transport`` is
94+
not explicitly provided. Only if this property is not set and
95+
``transport`` was not explicitly provided, the endpoint is
96+
determined by the GOOGLE_API_USE_MTLS_ENDPOINT environment
97+
variable, which have one of the following values:
98+
"always" (always use the default mTLS endpoint), "never" (always
99+
use the default regular endpoint) and "auto" (auto-switch to the
100+
default mTLS endpoint if client certificate is present; this is
101+
the default value).
102+
103+
2. If the GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable
104+
is "true", then the ``client_cert_source`` property can be used
105+
to provide a client certificate for mTLS transport. If
106+
not provided, the default SSL client certificate will be used if
107+
present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not
108+
set, no client certificate will be used.
109+
110+
3. The ``universe_domain`` property can be used to override the
111+
default "googleapis.com" universe. Note that the ``api_endpoint``
112+
property still takes precedence; and ``universe_domain`` is
113+
currently not supported for mTLS.
114+
115+
client_info (google.api_core.gapic_v1.client_info.ClientInfo):
116+
The client info used to send a user-agent string along with
117+
API requests. If ``None``, then default info will be used.
118+
Generally, you only need to set this if you're developing
119+
your own client library.
120+
121+
Raises:
122+
google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport
123+
creation failed for any reason.
124+
"""
125+
super(BigtableTableAdminClient, self).__init__(
126+
credentials=credentials,
127+
transport=transport,
128+
client_options=client_options,
129+
client_info=client_info,
130+
)
131+
132+
52133
def restore_table(
53134
self,
54135
request: Optional[Union[bigtable_table_admin.RestoreTableRequest, dict]] = None,
@@ -143,6 +224,7 @@ def sample_restore_table():
143224
)
144225
return restore_table_operation
145226

227+
146228
def wait_for_consistency(
147229
self,
148230
request: Optional[
@@ -236,6 +318,7 @@ def sample_wait_for_consistency():
236318
)
237319
return consistency.CheckConsistencyPollingFuture(api_call, default_retry=retry)
238320

321+
239322
def wait_for_replication(
240323
self,
241324
request: Optional[
@@ -334,6 +417,6 @@ def sample_wait_for_replication():
334417
generate_consistency_response.consistency_token
335418
)
336419

337-
return self.await_consistency(
420+
return self.wait_for_consistency(
338421
check_consistency_request, retry=retry, timeout=timeout, metadata=metadata
339422
)

google/cloud/bigtable/admin_v2/overlay/types/consistency.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from google.api_core.future import polling
1818
from google.api_core import gapic_v1
1919
from google.api_core import retry as retries
20-
from google.bigtable.admin_v2.types import bigtable_table_admin
20+
from google.cloud.bigtable.admin_v2.types import bigtable_table_admin
2121

2222
try:
2323
OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault, None]
@@ -89,6 +89,7 @@ def done(self, retry: OptionalRetry = None):
8989
return check_consistency_response.consistent
9090
except Exception as e:
9191
self.set_exception(e)
92+
raise e
9293

9394
def cancel(self):
9495
raise NotImplementedError("Cannot cancel consistency token operation")
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2025 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
# try/except added for compatibility with python < 3.8
17+
try:
18+
from unittest import mock
19+
from unittest.mock import AsyncMock # pragma: NO COVER
20+
except ImportError: # pragma: NO COVER
21+
import mock
22+
23+
import functools
24+
25+
from google.api_core import gapic_v1
26+
from google.api_core import retry as retries
27+
from google.cloud.bigtable.admin_v2.services.bigtable_table_admin import transports
28+
from google.cloud.bigtable.admin_v2.types import bigtable_table_admin
29+
from google.cloud.bigtable.admin_v2.overlay.services.bigtable_table_admin.client import (
30+
BigtableTableAdminClient, DEFAULT_CLIENT_INFO
31+
)
32+
from google.cloud.bigtable.admin_v2.overlay.types import consistency, restore_table
33+
34+
import pytest
35+
36+
37+
PARENT_NAME = "my_parent"
38+
TABLE_NAME = "my_table"
39+
CONSISTENCY_TOKEN = "abcdefg"
40+
41+
42+
@pytest.mark.parametrize(
43+
"transport_class,transport_name",
44+
[
45+
(
46+
transports.BigtableTableAdminGrpcTransport,
47+
"grpc",
48+
),
49+
(
50+
transports.BigtableTableAdminRestTransport,
51+
"rest",
52+
),
53+
],
54+
)
55+
def test_bigtable_table_admin_client_client_version(
56+
transport_class, transport_name
57+
):
58+
with mock.patch.object(transport_class, "__init__") as patched:
59+
patched.return_value = None
60+
BigtableTableAdminClient(transport=transport_name)
61+
transport_init_call = patched.call_args
62+
assert transport_init_call.kwargs["client_info"] == DEFAULT_CLIENT_INFO
63+
64+
65+
66+
@pytest.mark.parametrize(
67+
"kwargs",
68+
[
69+
{
70+
"request": bigtable_table_admin.RestoreTableRequest(
71+
parent=PARENT_NAME,
72+
table_id=TABLE_NAME,
73+
)
74+
},
75+
{
76+
"request": {
77+
"parent": PARENT_NAME,
78+
"table_id": TABLE_NAME,
79+
},
80+
},
81+
{
82+
"request": bigtable_table_admin.RestoreTableRequest(
83+
parent=PARENT_NAME,
84+
table_id=TABLE_NAME,
85+
),
86+
"retry": mock.Mock(spec=retries.Retry),
87+
"timeout": mock.Mock(spec=retries.Retry),
88+
"metadata": [("foo", "bar")]
89+
},
90+
]
91+
)
92+
def test_bigtable_table_admin_client_restore_table(kwargs):
93+
client = BigtableTableAdminClient()
94+
95+
with mock.patch.object(restore_table, "RestoreTableOperation") as future_mock:
96+
with mock.patch.object(client, "_transport") as transport_mock:
97+
with mock.patch.object(client, "_restore_table") as restore_table_mock:
98+
operation_mock = mock.Mock()
99+
restore_table_mock.return_value = operation_mock
100+
client.restore_table(**kwargs)
101+
102+
restore_table_mock.assert_called_once_with(
103+
request=kwargs["request"],
104+
retry=kwargs.get("retry", gapic_v1.method.DEFAULT),
105+
timeout=kwargs.get("timeout", gapic_v1.method.DEFAULT),
106+
metadata=kwargs.get("metadata", ()),
107+
)
108+
future_mock.assert_called_once_with(transport_mock.operations_client, operation_mock)
109+
110+
111+
@pytest.mark.parametrize(
112+
"kwargs",
113+
[
114+
{
115+
"request": bigtable_table_admin.CheckConsistencyRequest(
116+
name=TABLE_NAME,
117+
consistency_token=CONSISTENCY_TOKEN,
118+
)
119+
},
120+
{
121+
"request": {
122+
"name": TABLE_NAME,
123+
"consistency_token": CONSISTENCY_TOKEN,
124+
},
125+
},
126+
{
127+
"name": TABLE_NAME,
128+
"consistency_token": CONSISTENCY_TOKEN,
129+
},
130+
{
131+
"request": bigtable_table_admin.CheckConsistencyRequest(
132+
name=TABLE_NAME,
133+
consistency_token=CONSISTENCY_TOKEN,
134+
),
135+
"retry": mock.Mock(spec=retries.Retry),
136+
"timeout": mock.Mock(spec=retries.Retry),
137+
"metadata": [("foo", "bar")]
138+
},
139+
]
140+
)
141+
def test_bigtable_table_admin_client_wait_for_consistency(kwargs):
142+
client = BigtableTableAdminClient()
143+
144+
future = client.wait_for_consistency(**kwargs)
145+
146+
assert type(future) == consistency.CheckConsistencyPollingFuture
147+
assert future._default_retry == kwargs.get("retry", gapic_v1.method.DEFAULT)
148+
149+
check_consistency_call = future._check_consistency_call
150+
assert type(check_consistency_call) == functools.partial
151+
152+
assert check_consistency_call.func == client.check_consistency
153+
assert check_consistency_call.args == (
154+
kwargs.get("request", None),
155+
)
156+
assert check_consistency_call.keywords == {
157+
"name": kwargs.get("name", None),
158+
"consistency_token": kwargs.get("consistency_token", None),
159+
"timeout": kwargs.get("timeout", gapic_v1.method.DEFAULT),
160+
"metadata": kwargs.get("metadata", ()),
161+
}
162+
163+
164+
@pytest.mark.parametrize(
165+
"kwargs",
166+
[
167+
{
168+
"request": bigtable_table_admin.GenerateConsistencyTokenRequest(
169+
name=TABLE_NAME,
170+
)
171+
},
172+
{
173+
"request": {
174+
"name": TABLE_NAME
175+
},
176+
},
177+
{
178+
"name": TABLE_NAME,
179+
},
180+
{
181+
"request": bigtable_table_admin.GenerateConsistencyTokenRequest(
182+
name=TABLE_NAME,
183+
),
184+
"retry": mock.Mock(spec=retries.Retry),
185+
"timeout": mock.Mock(spec=retries.Retry),
186+
"metadata": [("foo", "bar")]
187+
},
188+
]
189+
)
190+
def test_bigtable_table_admin_client_wait_for_replication(kwargs):
191+
client = BigtableTableAdminClient()
192+
193+
with mock.patch.object(client, "generate_consistency_token") as generate_mock:
194+
generate_mock.return_value = bigtable_table_admin.GenerateConsistencyTokenResponse(
195+
consistency_token=CONSISTENCY_TOKEN,
196+
)
197+
future = client.wait_for_replication(**kwargs)
198+
199+
expected_check_consistency_request = bigtable_table_admin.CheckConsistencyRequest(
200+
name=TABLE_NAME,
201+
consistency_token=CONSISTENCY_TOKEN,
202+
)
203+
204+
assert type(future) == consistency.CheckConsistencyPollingFuture
205+
assert future._default_retry == kwargs.get("retry", gapic_v1.method.DEFAULT)
206+
207+
check_consistency_call = future._check_consistency_call
208+
assert type(check_consistency_call) == functools.partial
209+
210+
assert check_consistency_call.func == client.check_consistency
211+
assert check_consistency_call.args == (
212+
expected_check_consistency_request,
213+
)
214+
assert check_consistency_call.keywords == {
215+
"name": None,
216+
"consistency_token": None,
217+
"timeout": kwargs.get("timeout", gapic_v1.method.DEFAULT),
218+
"metadata": kwargs.get("metadata", ()),
219+
}

0 commit comments

Comments
 (0)