Skip to content

Commit fbb1440

Browse files
samples: add code samples for PostgreSql dialect (#836)
* samples: add code samples for PostgreSql dialect * linting * fix: remove unnecessary imports * remove unused import * fix: change method doc references in parser * add another command * test: add samples tests for PG * fix: linting * feat: sample tests config changes * refactor * refactor * refactor * refactor * add database dialect * database dialect fixture change * fix ddl * yield operation as well * skip backup tests * config changes * fix * minor lint fix * some tests were getting skipped. fixing it. * fix test * fix test and skip few tests for faster testing * re-enable tests Co-authored-by: Astha Mohta <[email protected]> Co-authored-by: Astha Mohta <[email protected]>
1 parent fb1948d commit fbb1440

File tree

6 files changed

+2214
-125
lines changed

6 files changed

+2214
-125
lines changed

samples/samples/conftest.py

Lines changed: 88 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
import uuid
1818

1919
from google.api_core import exceptions
20+
21+
from google.cloud import spanner_admin_database_v1
22+
from google.cloud.spanner_admin_database_v1.types.common import DatabaseDialect
2023
from google.cloud.spanner_v1 import backup
2124
from google.cloud.spanner_v1 import client
2225
from google.cloud.spanner_v1 import database
@@ -26,17 +29,32 @@
2629

2730
INSTANCE_CREATION_TIMEOUT = 560 # seconds
2831

32+
OPERATION_TIMEOUT_SECONDS = 120 # seconds
33+
2934
retry_429 = retry.RetryErrors(exceptions.ResourceExhausted, delay=15)
3035

3136

3237
@pytest.fixture(scope="module")
3338
def sample_name():
3439
"""Sample testcase modules must define this fixture.
3540
36-
The name is used to label the instance created by the sample, to
37-
aid in debugging leaked instances.
38-
"""
39-
raise NotImplementedError("Define 'sample_name' fixture in sample test driver")
41+
The name is used to label the instance created by the sample, to
42+
aid in debugging leaked instances.
43+
"""
44+
raise NotImplementedError(
45+
"Define 'sample_name' fixture in sample test driver")
46+
47+
48+
@pytest.fixture(scope="module")
49+
def database_dialect():
50+
"""Database dialect to be used for this sample.
51+
52+
The dialect is used to initialize the dialect for the database.
53+
It can either be GoogleStandardSql or PostgreSql.
54+
"""
55+
# By default, we consider GOOGLE_STANDARD_SQL dialect. Other specific tests
56+
# can override this if required.
57+
return DatabaseDialect.GOOGLE_STANDARD_SQL
4058

4159

4260
@pytest.fixture(scope="session")
@@ -87,7 +105,7 @@ def multi_region_instance_id():
87105
@pytest.fixture(scope="module")
88106
def instance_config(spanner_client):
89107
return "{}/instanceConfigs/{}".format(
90-
spanner_client.project_name, "regional-us-central1"
108+
spanner_client.project_name, "regional-us-central1"
91109
)
92110

93111

@@ -98,20 +116,20 @@ def multi_region_instance_config(spanner_client):
98116

99117
@pytest.fixture(scope="module")
100118
def sample_instance(
101-
spanner_client,
102-
cleanup_old_instances,
103-
instance_id,
104-
instance_config,
105-
sample_name,
119+
spanner_client,
120+
cleanup_old_instances,
121+
instance_id,
122+
instance_config,
123+
sample_name,
106124
):
107125
sample_instance = spanner_client.instance(
108-
instance_id,
109-
instance_config,
110-
labels={
111-
"cloud_spanner_samples": "true",
112-
"sample_name": sample_name,
113-
"created": str(int(time.time())),
114-
},
126+
instance_id,
127+
instance_config,
128+
labels={
129+
"cloud_spanner_samples": "true",
130+
"sample_name": sample_name,
131+
"created": str(int(time.time())),
132+
},
115133
)
116134
op = retry_429(sample_instance.create)()
117135
op.result(INSTANCE_CREATION_TIMEOUT) # block until completion
@@ -133,20 +151,20 @@ def sample_instance(
133151

134152
@pytest.fixture(scope="module")
135153
def multi_region_instance(
136-
spanner_client,
137-
cleanup_old_instances,
138-
multi_region_instance_id,
139-
multi_region_instance_config,
140-
sample_name,
154+
spanner_client,
155+
cleanup_old_instances,
156+
multi_region_instance_id,
157+
multi_region_instance_config,
158+
sample_name,
141159
):
142160
multi_region_instance = spanner_client.instance(
143-
multi_region_instance_id,
144-
multi_region_instance_config,
145-
labels={
146-
"cloud_spanner_samples": "true",
147-
"sample_name": sample_name,
148-
"created": str(int(time.time())),
149-
},
161+
multi_region_instance_id,
162+
multi_region_instance_config,
163+
labels={
164+
"cloud_spanner_samples": "true",
165+
"sample_name": sample_name,
166+
"created": str(int(time.time())),
167+
},
150168
)
151169
op = retry_429(multi_region_instance.create)()
152170
op.result(INSTANCE_CREATION_TIMEOUT) # block until completion
@@ -170,30 +188,59 @@ def multi_region_instance(
170188
def database_id():
171189
"""Id for the database used in samples.
172190
173-
Sample testcase modules can override as needed.
174-
"""
191+
Sample testcase modules can override as needed.
192+
"""
175193
return "my-database-id"
176194

177195

178196
@pytest.fixture(scope="module")
179197
def database_ddl():
180198
"""Sequence of DDL statements used to set up the database.
181199
182-
Sample testcase modules can override as needed.
183-
"""
200+
Sample testcase modules can override as needed.
201+
"""
184202
return []
185203

186204

187205
@pytest.fixture(scope="module")
188-
def sample_database(sample_instance, database_id, database_ddl):
206+
def sample_database(
207+
spanner_client,
208+
sample_instance,
209+
database_id,
210+
database_ddl,
211+
database_dialect):
212+
if database_dialect == DatabaseDialect.POSTGRESQL:
213+
sample_database = sample_instance.database(
214+
database_id,
215+
database_dialect=DatabaseDialect.POSTGRESQL,
216+
)
217+
218+
if not sample_database.exists():
219+
operation = sample_database.create()
220+
operation.result(OPERATION_TIMEOUT_SECONDS)
221+
222+
request = spanner_admin_database_v1.UpdateDatabaseDdlRequest(
223+
database=sample_database.name,
224+
statements=database_ddl,
225+
)
226+
227+
operation =\
228+
spanner_client.database_admin_api.update_database_ddl(request)
229+
operation.result(OPERATION_TIMEOUT_SECONDS)
230+
231+
yield sample_database
232+
233+
sample_database.drop()
234+
return
189235

190236
sample_database = sample_instance.database(
191-
database_id,
192-
ddl_statements=database_ddl,
237+
database_id,
238+
ddl_statements=database_ddl,
193239
)
194240

195241
if not sample_database.exists():
196-
sample_database.create()
242+
operation = sample_database.create()
243+
operation.result(OPERATION_TIMEOUT_SECONDS)
197244

198245
yield sample_database
199246

@@ -203,8 +250,8 @@ def sample_database(sample_instance, database_id, database_ddl):
203250
@pytest.fixture(scope="module")
204251
def kms_key_name(spanner_client):
205252
return "projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}".format(
206-
spanner_client.project,
207-
"us-central1",
208-
"spanner-test-keyring",
209-
"spanner-test-cmek",
253+
spanner_client.project,
254+
"us-central1",
255+
"spanner-test-keyring",
256+
"spanner-test-cmek",
210257
)

samples/samples/noxfile.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ def blacken(session: nox.sessions.Session) -> None:
180180
# format = isort + black
181181
#
182182

183+
183184
@nox.session
184185
def format(session: nox.sessions.Session) -> None:
185186
"""
@@ -207,7 +208,9 @@ def _session_tests(
207208
session: nox.sessions.Session, post_install: Callable = None
208209
) -> None:
209210
# check for presence of tests
210-
test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob("**/test_*.py", recursive=True)
211+
test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob(
212+
"**/test_*.py", recursive=True
213+
)
211214
test_list.extend(glob.glob("**/tests", recursive=True))
212215

213216
if len(test_list) == 0:
@@ -229,9 +232,7 @@ def _session_tests(
229232

230233
if os.path.exists("requirements-test.txt"):
231234
if os.path.exists("constraints-test.txt"):
232-
session.install(
233-
"-r", "requirements-test.txt", "-c", "constraints-test.txt"
234-
)
235+
session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt")
235236
else:
236237
session.install("-r", "requirements-test.txt")
237238
with open("requirements-test.txt") as rtfile:
@@ -244,9 +245,9 @@ def _session_tests(
244245
post_install(session)
245246

246247
if "pytest-parallel" in packages:
247-
concurrent_args.extend(['--workers', 'auto', '--tests-per-worker', 'auto'])
248+
concurrent_args.extend(["--workers", "auto", "--tests-per-worker", "auto"])
248249
elif "pytest-xdist" in packages:
249-
concurrent_args.extend(['-n', 'auto'])
250+
concurrent_args.extend(["-n", "auto"])
250251

251252
session.run(
252253
"pytest",
@@ -276,7 +277,7 @@ def py(session: nox.sessions.Session) -> None:
276277

277278

278279
def _get_repo_root() -> Optional[str]:
279-
""" Returns the root folder of the project. """
280+
"""Returns the root folder of the project."""
280281
# Get root of this repository. Assume we don't have directories nested deeper than 10 items.
281282
p = Path(os.getcwd())
282283
for i in range(10):

0 commit comments

Comments
 (0)