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

Commit 67c98f0

Browse files
authored
tests: Tests for sync client + fixes + client library versioning (#1132)
* tests: Tests for sync client + fixes + client library versioning * Removed raise exception * linting + name changes in tests + added test for timeout * linting * Fixed tests on Python 3.7
1 parent bd1da66 commit 67c98f0

4 files changed

Lines changed: 611 additions & 6 deletions

File tree

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

Lines changed: 87 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+
4345
from google.cloud.bigtable.admin_v2.types import bigtable_table_admin
4446

4547
from google.cloud.bigtable.admin_v2.services.bigtable_table_admin import (
46-
BaseBigtableTableAdminClient,
48+
client as base_client,
49+
)
50+
from google.cloud.bigtable.admin_v2.services.bigtable_table_admin.transports.base import (
51+
BigtableTableAdminTransport,
4752
)
4853
from google.cloud.bigtable.admin_v2.overlay.types import consistency, restore_table
4954

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

51-
class BigtableTableAdminClient(BaseBigtableTableAdminClient):
52133
def restore_table(
53134
self,
54135
request: Optional[Union[bigtable_table_admin.RestoreTableRequest, dict]] = None,
@@ -334,6 +415,6 @@ def sample_wait_for_replication():
334415
generate_consistency_response.consistency_token
335416
)
336417

337-
return self.await_consistency(
418+
return self.wait_for_consistency(
338419
check_consistency_request, retry=retry, timeout=timeout, metadata=metadata
339420
)
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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+
except ImportError: # pragma: NO COVER
20+
import mock
21+
22+
import functools
23+
24+
from google.api_core import gapic_v1
25+
from google.api_core import retry as retries
26+
from google.cloud.bigtable.admin_v2.services.bigtable_table_admin import transports
27+
from google.cloud.bigtable.admin_v2.types import bigtable_table_admin
28+
from google.cloud.bigtable.admin_v2.overlay.services.bigtable_table_admin.client import (
29+
BigtableTableAdminClient,
30+
DEFAULT_CLIENT_INFO,
31+
)
32+
from google.cloud.bigtable.admin_v2.overlay.types import consistency, restore_table
33+
34+
from google.cloud.bigtable import __version__ as bigtable_version
35+
36+
import pytest
37+
38+
39+
PARENT_NAME = "my_parent"
40+
TABLE_NAME = "my_table"
41+
CONSISTENCY_TOKEN = "abcdefg"
42+
43+
44+
@pytest.mark.parametrize(
45+
"transport_class,transport_name",
46+
[
47+
(
48+
transports.BigtableTableAdminGrpcTransport,
49+
"grpc",
50+
),
51+
(
52+
transports.BigtableTableAdminRestTransport,
53+
"rest",
54+
),
55+
],
56+
)
57+
def test_bigtable_table_admin_client_client_version(transport_class, transport_name):
58+
with mock.patch.object(transport_class, "__init__") as patched:
59+
patched.return_value = None
60+
BigtableTableAdminClient(transport=transport_name)
61+
62+
# call_args.kwargs is not supported in Python 3.7, so find them from the tuple
63+
# instead. It's always the last item in the call_args tuple.
64+
transport_init_call_kwargs = patched.call_args[-1]
65+
assert transport_init_call_kwargs["client_info"] == DEFAULT_CLIENT_INFO
66+
67+
assert (
68+
DEFAULT_CLIENT_INFO.client_library_version
69+
== f"{bigtable_version}-admin-overlay"
70+
)
71+
72+
73+
@pytest.mark.parametrize(
74+
"kwargs",
75+
[
76+
{
77+
"request": bigtable_table_admin.RestoreTableRequest(
78+
parent=PARENT_NAME,
79+
table_id=TABLE_NAME,
80+
)
81+
},
82+
{
83+
"request": {
84+
"parent": PARENT_NAME,
85+
"table_id": TABLE_NAME,
86+
},
87+
},
88+
{
89+
"request": bigtable_table_admin.RestoreTableRequest(
90+
parent=PARENT_NAME,
91+
table_id=TABLE_NAME,
92+
),
93+
"retry": mock.Mock(spec=retries.Retry),
94+
"timeout": mock.Mock(spec=retries.Retry),
95+
"metadata": [("foo", "bar")],
96+
},
97+
],
98+
)
99+
def test_bigtable_table_admin_client_restore_table(kwargs):
100+
client = BigtableTableAdminClient()
101+
102+
with mock.patch.object(restore_table, "RestoreTableOperation") as future_mock:
103+
with mock.patch.object(client, "_transport") as transport_mock:
104+
with mock.patch.object(client, "_restore_table") as restore_table_mock:
105+
operation_mock = mock.Mock()
106+
restore_table_mock.return_value = operation_mock
107+
client.restore_table(**kwargs)
108+
109+
restore_table_mock.assert_called_once_with(
110+
request=kwargs["request"],
111+
retry=kwargs.get("retry", gapic_v1.method.DEFAULT),
112+
timeout=kwargs.get("timeout", gapic_v1.method.DEFAULT),
113+
metadata=kwargs.get("metadata", ()),
114+
)
115+
future_mock.assert_called_once_with(
116+
transport_mock.operations_client, operation_mock
117+
)
118+
119+
120+
@pytest.mark.parametrize(
121+
"kwargs",
122+
[
123+
{
124+
"request": bigtable_table_admin.CheckConsistencyRequest(
125+
name=TABLE_NAME,
126+
consistency_token=CONSISTENCY_TOKEN,
127+
)
128+
},
129+
{
130+
"request": {
131+
"name": TABLE_NAME,
132+
"consistency_token": CONSISTENCY_TOKEN,
133+
},
134+
},
135+
{
136+
"name": TABLE_NAME,
137+
"consistency_token": CONSISTENCY_TOKEN,
138+
},
139+
{
140+
"request": bigtable_table_admin.CheckConsistencyRequest(
141+
name=TABLE_NAME,
142+
consistency_token=CONSISTENCY_TOKEN,
143+
),
144+
"retry": mock.Mock(spec=retries.Retry),
145+
"timeout": mock.Mock(spec=retries.Retry),
146+
"metadata": [("foo", "bar")],
147+
},
148+
],
149+
)
150+
def test_bigtable_table_admin_client_wait_for_consistency(kwargs):
151+
client = BigtableTableAdminClient()
152+
153+
future = client.wait_for_consistency(**kwargs)
154+
155+
assert isinstance(future, consistency.CheckConsistencyPollingFuture)
156+
assert future._default_retry == kwargs.get("retry", gapic_v1.method.DEFAULT)
157+
158+
check_consistency_call = future._check_consistency_call
159+
assert isinstance(check_consistency_call, functools.partial)
160+
161+
assert check_consistency_call.func == client.check_consistency
162+
assert check_consistency_call.args == (kwargs.get("request", None),)
163+
assert check_consistency_call.keywords == {
164+
"name": kwargs.get("name", None),
165+
"consistency_token": kwargs.get("consistency_token", None),
166+
"timeout": kwargs.get("timeout", gapic_v1.method.DEFAULT),
167+
"metadata": kwargs.get("metadata", ()),
168+
}
169+
170+
171+
@pytest.mark.parametrize(
172+
"kwargs",
173+
[
174+
{
175+
"request": bigtable_table_admin.GenerateConsistencyTokenRequest(
176+
name=TABLE_NAME,
177+
)
178+
},
179+
{
180+
"request": {"name": TABLE_NAME},
181+
},
182+
{
183+
"name": TABLE_NAME,
184+
},
185+
{
186+
"request": bigtable_table_admin.GenerateConsistencyTokenRequest(
187+
name=TABLE_NAME,
188+
),
189+
"retry": mock.Mock(spec=retries.Retry),
190+
"timeout": mock.Mock(spec=retries.Retry),
191+
"metadata": [("foo", "bar")],
192+
},
193+
],
194+
)
195+
def test_bigtable_table_admin_client_wait_for_replication(kwargs):
196+
client = BigtableTableAdminClient()
197+
198+
with mock.patch.object(client, "generate_consistency_token") as generate_mock:
199+
generate_mock.return_value = (
200+
bigtable_table_admin.GenerateConsistencyTokenResponse(
201+
consistency_token=CONSISTENCY_TOKEN,
202+
)
203+
)
204+
future = client.wait_for_replication(**kwargs)
205+
206+
expected_check_consistency_request = (
207+
bigtable_table_admin.CheckConsistencyRequest(
208+
name=TABLE_NAME,
209+
consistency_token=CONSISTENCY_TOKEN,
210+
)
211+
)
212+
213+
assert isinstance(future, consistency.CheckConsistencyPollingFuture)
214+
assert future._default_retry == kwargs.get("retry", gapic_v1.method.DEFAULT)
215+
216+
check_consistency_call = future._check_consistency_call
217+
assert isinstance(check_consistency_call, functools.partial)
218+
219+
assert check_consistency_call.func == client.check_consistency
220+
assert check_consistency_call.args == (expected_check_consistency_request,)
221+
assert check_consistency_call.keywords == {
222+
"name": None,
223+
"consistency_token": None,
224+
"timeout": kwargs.get("timeout", gapic_v1.method.DEFAULT),
225+
"metadata": kwargs.get("metadata", ()),
226+
}

0 commit comments

Comments
 (0)