Skip to content

Commit b4cb3a2

Browse files
committed
Add tests for new Spanner Graph snippets
1 parent 8f50e23 commit b4cb3a2

File tree

2 files changed

+251
-36
lines changed

2 files changed

+251
-36
lines changed

samples/samples/graph_snippets.py

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@
3030
# [START spanner_create_database_with_property_graph]
3131
def create_database_with_property_graph(instance_id, database_id):
3232
"""Creates a database, tables and a property graph for sample data."""
33-
from google.cloud.spanner_admin_database_v1.types import \
34-
spanner_database_admin
33+
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin
3534

3635
spanner_client = spanner.Client()
3736
database_admin_api = spanner_client.database_admin_api
@@ -104,8 +103,7 @@ def create_database_with_property_graph(instance_id, database_id):
104103
def update_allow_commit_timestamps(instance_id, database_id):
105104
"""Alters table column(s) to support commit timestamps."""
106105

107-
from google.cloud.spanner_admin_database_v1.types import \
108-
spanner_database_admin
106+
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin
109107

110108
spanner_client = spanner.Client()
111109
database_admin_api = spanner_client.database_admin_api
@@ -117,7 +115,8 @@ def update_allow_commit_timestamps(instance_id, database_id):
117115
statements=[
118116
"""ALTER TABLE AccountTransferAccount
119117
ALTER COLUMN create_time
120-
SET OPTIONS (allow_commit_timestamp = true)"""],
118+
SET OPTIONS (allow_commit_timestamp = true)"""
119+
],
121120
)
122121

123122
operation = database_admin_api.update_database_ddl(request)
@@ -147,42 +146,42 @@ def insert_data(instance_id, database_id):
147146
table="Account",
148147
columns=("id", "create_time", "is_blocked", "nick_name"),
149148
values=[
150-
(7, '2020-01-10T06:22:20.12Z', False, "Vacation Fund"),
151-
(16, '2020-01-27T17:55:09.12Z', True, "Vacation Fund"),
152-
(20, '2020-02-18T05:44:20.12Z', False, "Rainy Day Fund")
149+
(7, "2020-01-10T06:22:20.12Z", False, "Vacation Fund"),
150+
(16, "2020-01-27T17:55:09.12Z", True, "Vacation Fund"),
151+
(20, "2020-02-18T05:44:20.12Z", False, "Rainy Day Fund"),
153152
],
154153
)
155154

156155
batch.insert(
157156
table="Person",
158157
columns=("id", "name", "birthday", "country", "city"),
159158
values=[
160-
(1, "Alex", '1991-12-21T00:00:00.12Z', "Australia"," Adelaide"),
161-
(2, "Dana", '1980-10-31T00:00:00.12Z',"Czech_Republic", "Moravia"),
162-
(3, "Lee", '1986-12-07T00:00:00.12Z', "India", "Kollam")
159+
(1, "Alex", "1991-12-21T00:00:00.12Z", "Australia", " Adelaide"),
160+
(2, "Dana", "1980-10-31T00:00:00.12Z", "Czech_Republic", "Moravia"),
161+
(3, "Lee", "1986-12-07T00:00:00.12Z", "India", "Kollam"),
163162
],
164163
)
165164

166165
batch.insert(
167166
table="AccountTransferAccount",
168167
columns=("id", "to_id", "amount", "create_time", "order_number"),
169168
values=[
170-
(7, 16, 300.0, '2020-08-29T15:28:58.12Z', "304330008004315"),
171-
(7, 16, 100.0, '2020-10-04T16:55:05.12Z', "304120005529714"),
172-
(16, 20, 300.0, '2020-09-25T02:36:14.12Z', "103650009791820"),
173-
(20, 7, 500.0, '2020-10-04T16:55:05.12Z', "304120005529714"),
174-
(20, 16, 200.0, '2020-10-17T03:59:40.12Z', "302290001255747")
169+
(7, 16, 300.0, "2020-08-29T15:28:58.12Z", "304330008004315"),
170+
(7, 16, 100.0, "2020-10-04T16:55:05.12Z", "304120005529714"),
171+
(16, 20, 300.0, "2020-09-25T02:36:14.12Z", "103650009791820"),
172+
(20, 7, 500.0, "2020-10-04T16:55:05.12Z", "304120005529714"),
173+
(20, 16, 200.0, "2020-10-17T03:59:40.12Z", "302290001255747"),
175174
],
176175
)
177176

178177
batch.insert(
179178
table="PersonOwnAccount",
180179
columns=("id", "account_id", "create_time"),
181180
values=[
182-
(1, 7, '2020-01-10T06:22:20.12Z'),
183-
(2, 20, '2020-01-27T17:55:09.12Z'),
184-
(3, 16, '2020-02-18T05:44:20.12Z')
185-
]
181+
(1, 7, "2020-01-10T06:22:20.12Z"),
182+
(2, 20, "2020-01-27T17:55:09.12Z"),
183+
(3, 16, "2020-02-18T05:44:20.12Z"),
184+
],
186185
)
187186

188187
print("Inserted data.")
@@ -207,7 +206,7 @@ def insert_accounts(transaction):
207206
"INSERT INTO Account (id, create_time, is_blocked) "
208207
" VALUES"
209208
" (1, CAST('2000-08-10 08:18:48.463959-07:52' AS TIMESTAMP), false),"
210-
" (2, CAST('2000-08-12 08:18:48.463959-07:52' AS TIMESTAMP), true)"
209+
" (2, CAST('2000-08-12 07:13:16.463959-03:41' AS TIMESTAMP), true)"
211210
)
212211

213212
print("{} record(s) inserted into Account.".format(row_ct))
@@ -216,8 +215,8 @@ def insert_transfers(transaction):
216215
row_ct = transaction.execute_update(
217216
"INSERT INTO AccountTransferAccount (id, to_id, create_time, amount) "
218217
" VALUES"
219-
" (1, 2, PENDING_COMMIT_TIMESTAMP(), 100),"
220-
" (1, 1, PENDING_COMMIT_TIMESTAMP(), 200) "
218+
" (1, 2, CAST('2000-09-11 03:11:18.463959-06:36' AS TIMESTAMP), 100),"
219+
" (1, 1, CAST('2000-09-12 04:09:34.463959-05:12' AS TIMESTAMP), 200) "
221220
)
222221

223222
print("{} record(s) inserted into AccountTransferAccount.".format(row_ct))
@@ -244,14 +243,14 @@ def update_accounts(transaction):
244243
"UPDATE Account SET is_blocked = false WHERE id = 2"
245244
)
246245

247-
print("{} record(s) updated.".format(row_ct))
246+
print("{} Account record(s) updated.".format(row_ct))
248247

249248
def update_transfers(transaction):
250249
row_ct = transaction.execute_update(
251250
"UPDATE AccountTransferAccount SET amount = 300 WHERE id = 1 AND to_id = 2"
252251
)
253252

254-
print("{} record(s) updated.".format(row_ct))
253+
print("{} AccountTransferAccount record(s) updated.".format(row_ct))
255254

256255
database.run_in_transaction(update_accounts)
257256
database.run_in_transaction(update_transfers)
@@ -279,7 +278,7 @@ def update_accounts(transaction):
279278
" RETURN b.id}"
280279
)
281280

282-
print("{} record(s) updated.".format(row_ct))
281+
print("{} Account record(s) updated.".format(row_ct))
283282

284283
database.run_in_transaction(update_accounts)
285284

@@ -351,14 +350,12 @@ def delete_transfers(transaction):
351350
"DELETE FROM AccountTransferAccount WHERE id = 1 AND to_id = 2"
352351
)
353352

354-
print("{} record(s) deleted.".format(row_ct))
353+
print("{} AccountTransferAccount record(s) deleted.".format(row_ct))
355354

356355
def delete_accounts(transaction):
357-
row_ct = transaction.execute_update(
358-
"DELETE FROM Account WHERE id = 2"
359-
)
356+
row_ct = transaction.execute_update("DELETE FROM Account WHERE id = 2")
360357

361-
print("{} record(s) deleted.".format(row_ct))
358+
print("{} Account record(s) deleted.".format(row_ct))
362359

363360
database.run_in_transaction(delete_transfers)
364361
database.run_in_transaction(delete_accounts)
@@ -415,14 +412,18 @@ def delete_data(instance_id, database_id):
415412
subparsers = parser.add_subparsers(dest="command")
416413
subparsers.add_parser(
417414
"create_database_with_property_graph",
418-
help=create_database_with_property_graph.__doc__)
419-
subparsers.add_parser("update_allow_commit_timestamps",
420-
help=update_allow_commit_timestamps.__doc__)
415+
help=create_database_with_property_graph.__doc__,
416+
)
417+
subparsers.add_parser(
418+
"update_allow_commit_timestamps", help=update_allow_commit_timestamps.__doc__
419+
)
421420
subparsers.add_parser("insert_data", help=insert_data.__doc__)
422421
subparsers.add_parser("insert_data_with_dml", help=insert_data_with_dml.__doc__)
423422
subparsers.add_parser("update_data_with_dml", help=update_data_with_dml.__doc__)
424-
subparsers.add_parser("update_data_with_graph_query_in_dml",
425-
help=update_data_with_graph_query_in_dml.__doc__)
423+
subparsers.add_parser(
424+
"update_data_with_graph_query_in_dml",
425+
help=update_data_with_graph_query_in_dml.__doc__,
426+
)
426427
subparsers.add_parser("query_data", help=query_data.__doc__)
427428
subparsers.add_parser(
428429
"query_data_with_parameter", help=query_data_with_parameter.__doc__
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# Copyright 2024 Google, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# import time
16+
import uuid
17+
import pytest
18+
19+
from google.api_core import exceptions
20+
21+
from google.cloud import spanner
22+
from google.cloud.spanner_admin_database_v1.types.common import DatabaseDialect
23+
from test_utils.retry import RetryErrors
24+
25+
import graph_snippets
26+
27+
retry_429 = RetryErrors(exceptions.ResourceExhausted, delay=15)
28+
29+
CREATE_TABLE_PERSON = """\
30+
CREATE TABLE Person (
31+
id INT64 NOT NULL,
32+
name STRING(MAX),
33+
birthday TIMESTAMP,
34+
country STRING(MAX),
35+
city STRING(MAX),
36+
) PRIMARY KEY (id)
37+
"""
38+
39+
CREATE_TABLE_ACCOUNT = """\
40+
CREATE TABLE Account (
41+
id INT64 NOT NULL,
42+
create_time TIMESTAMP,
43+
is_blocked BOOL,
44+
nick_name STRING(MAX),
45+
) PRIMARY KEY (id)
46+
"""
47+
48+
CREATE_TABLE_PERSON_OWN_ACCOUNT = """\
49+
CREATE TABLE PersonOwnAccount (
50+
id INT64 NOT NULL,
51+
account_id INT64 NOT NULL,
52+
create_time TIMESTAMP,
53+
FOREIGN KEY (account_id)
54+
REFERENCES Account (id)
55+
) PRIMARY KEY (id, account_id),
56+
INTERLEAVE IN PARENT Person ON DELETE CASCADE
57+
"""
58+
59+
CREATE_TABLE_ACCOUNT_TRANSFER_ACCOUNT = """\
60+
CREATE TABLE AccountTransferAccount (
61+
id INT64 NOT NULL,
62+
to_id INT64 NOT NULL,
63+
amount FLOAT64,
64+
create_time TIMESTAMP NOT NULL,
65+
order_number STRING(MAX),
66+
FOREIGN KEY (to_id) REFERENCES Account (id)
67+
) PRIMARY KEY (id, to_id, create_time),
68+
INTERLEAVE IN PARENT Account ON DELETE CASCADE
69+
"""
70+
71+
CREATE_PROPERTY_GRAPH = """
72+
CREATE OR REPLACE PROPERTY GRAPH FinGraph
73+
NODE TABLES (Account, Person)
74+
EDGE TABLES (
75+
PersonOwnAccount
76+
SOURCE KEY(id) REFERENCES Person(id)
77+
DESTINATION KEY(account_id) REFERENCES Account(id)
78+
LABEL Owns,
79+
AccountTransferAccount
80+
SOURCE KEY(id) REFERENCES Account(id)
81+
DESTINATION KEY(to_id) REFERENCES Account(id)
82+
LABEL Transfers)
83+
"""
84+
85+
86+
@pytest.fixture(scope="module")
87+
def sample_name():
88+
return "snippets"
89+
90+
91+
@pytest.fixture(scope="module")
92+
def database_dialect():
93+
"""Spanner dialect to be used for this sample.
94+
95+
The dialect is used to initialize the dialect for the database.
96+
It can either be GoogleStandardSql or PostgreSql.
97+
"""
98+
return DatabaseDialect.GOOGLE_STANDARD_SQL
99+
100+
101+
@pytest.fixture(scope="module")
102+
def database_id():
103+
return f"test-db-{uuid.uuid4().hex[:10]}"
104+
105+
106+
@pytest.fixture(scope="module")
107+
def create_database_id():
108+
return f"create-db-{uuid.uuid4().hex[:10]}"
109+
110+
111+
@pytest.fixture(scope="module")
112+
def database_ddl():
113+
"""Sequence of DDL statements used to set up the database.
114+
115+
Sample testcase modules can override as needed.
116+
"""
117+
return [
118+
CREATE_TABLE_PERSON,
119+
CREATE_TABLE_ACCOUNT,
120+
CREATE_TABLE_PERSON_OWN_ACCOUNT,
121+
CREATE_TABLE_ACCOUNT_TRANSFER_ACCOUNT,
122+
CREATE_PROPERTY_GRAPH,
123+
]
124+
125+
126+
def test_create_database_explicit(sample_instance, create_database_id):
127+
graph_snippets.create_database_with_property_graph(
128+
sample_instance.instance_id, create_database_id
129+
)
130+
database = sample_instance.database(create_database_id)
131+
database.drop()
132+
133+
134+
@pytest.mark.dependency(name="insert_data")
135+
def test_insert_data(capsys, instance_id, sample_database):
136+
graph_snippets.insert_data(instance_id, sample_database.database_id)
137+
out, _ = capsys.readouterr()
138+
assert "Inserted data" in out
139+
140+
141+
@pytest.mark.dependency(depends=["insert_data"])
142+
def test_query_data(capsys, instance_id, sample_database):
143+
graph_snippets.query_data(instance_id, sample_database.database_id)
144+
out, _ = capsys.readouterr()
145+
assert (
146+
"sender: Dana, receiver: Alex, amount: 500.0, transfer_at: 2020-10-04 16:55:05.120000+00:00"
147+
in out
148+
)
149+
assert (
150+
"sender: Lee, receiver: Dana, amount: 300.0, transfer_at: 2020-09-25 02:36:14.120000+00:00"
151+
in out
152+
)
153+
assert (
154+
"sender: Alex, receiver: Lee, amount: 300.0, transfer_at: 2020-08-29 15:28:58.120000+00:00"
155+
in out
156+
)
157+
assert (
158+
"sender: Alex, receiver: Lee, amount: 100.0, transfer_at: 2020-10-04 16:55:05.120000+00:00"
159+
in out
160+
)
161+
assert (
162+
"sender: Dana, receiver: Lee, amount: 200.0, transfer_at: 2020-10-17 03:59:40.120000+00:00"
163+
in out
164+
)
165+
166+
167+
@pytest.mark.dependency(depends=["insert_data"])
168+
def test_query_data_with_parameter(capsys, instance_id, sample_database):
169+
graph_snippets.query_data_with_parameter(instance_id, sample_database.database_id)
170+
out, _ = capsys.readouterr()
171+
assert (
172+
"sender: Dana, receiver: Alex, amount: 500.0, transfer_at: 2020-10-04 16:55:05.120000+00:00"
173+
in out
174+
)
175+
176+
177+
@pytest.mark.dependency(name="insert_data_with_dml", depends=["insert_data"])
178+
def test_insert_data_with_dml(capsys, instance_id, sample_database):
179+
graph_snippets.insert_data_with_dml(instance_id, sample_database.database_id)
180+
out, _ = capsys.readouterr()
181+
assert "2 record(s) inserted into Account." in out
182+
assert "2 record(s) inserted into AccountTransferAccount." in out
183+
184+
185+
@pytest.mark.dependency(name="update_data_with_dml", depends=["insert_data_with_dml"])
186+
def test_update_data_with_dml(capsys, instance_id, sample_database):
187+
graph_snippets.update_data_with_dml(instance_id, sample_database.database_id)
188+
out, _ = capsys.readouterr()
189+
assert "1 Account record(s) updated." in out
190+
assert "1 AccountTransferAccount record(s) updated." in out
191+
192+
193+
@pytest.mark.dependency(depends=["update_data_with_dml"])
194+
def test_update_data_with_graph_query_in_dml(capsys, instance_id, sample_database):
195+
graph_snippets.update_data_with_graph_query_in_dml(
196+
instance_id, sample_database.database_id
197+
)
198+
out, _ = capsys.readouterr()
199+
assert "2 Account record(s) updated." in out
200+
201+
202+
@pytest.mark.dependency(depends=["update_data_with_dml"])
203+
def test_delete_data_with_graph_query_in_dml(capsys, instance_id, sample_database):
204+
graph_snippets.delete_data_with_dml(instance_id, sample_database.database_id)
205+
out, _ = capsys.readouterr()
206+
assert "1 AccountTransferAccount record(s) deleted." in out
207+
assert "1 Account record(s) deleted." in out
208+
209+
210+
@pytest.mark.dependency(depends=["insert_data"])
211+
def test_delete_data_with_graph_query_in_dml(capsys, instance_id, sample_database):
212+
graph_snippets.delete_data(instance_id, sample_database.database_id)
213+
out, _ = capsys.readouterr()
214+
assert "Deleted data." in out

0 commit comments

Comments
 (0)