Skip to content

Commit 279851e

Browse files
tests: remove string templating in SQL statements (#6631)
* Closes #6630 * Didn't find any functional breakages with newer versions of sqlite3 (tested with 3.49.1). * Fixed failing tests by moving away from templating variables into SQL statements.
1 parent 9b12a33 commit 279851e

File tree

4 files changed

+109
-65
lines changed

4 files changed

+109
-65
lines changed

tests/integration/test_workflow_db_mgr.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ def db_remove_column(schd: 'Scheduler', table: str, column: str) -> None:
7171
[fields[1] for fields in desc if fields[1] != column]
7272
)
7373
# Copy table data to a temporary table, and rename it back.
74-
conn.execute(rf'CREATE TABLE "tmp"({c_names})')
74+
conn.execute(rf"CREATE TABLE 'tmp'({c_names})")
7575
conn.execute(
76-
rf'INSERT INTO "tmp"({c_names}) SELECT {c_names} FROM {table}')
77-
conn.execute(rf'DROP TABLE "{table}"')
78-
conn.execute(rf'ALTER TABLE "tmp" RENAME TO "{table}"')
76+
rf"INSERT INTO 'tmp'({c_names}) SELECT {c_names} FROM {table}")
77+
conn.execute(rf"DROP TABLE '{table}'")
78+
conn.execute(rf"ALTER TABLE 'tmp' RENAME TO '{table}'")
7979
conn.commit()
8080

8181

tests/unit/test_db_compat.py

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
@pytest.fixture
3434
def _setup_db(tmp_path):
3535
"""Fixture to create old DB."""
36-
def _inner(values, db_file_name='sql.db'):
36+
def _inner(stmts, db_file_name='sql.db'):
3737
db_file = tmp_path / db_file_name
3838
db_file.parent.mkdir(parents=True, exist_ok=True)
3939
# Note: cannot use CylcWorkflowDAO here as creating outdated DB
@@ -53,8 +53,8 @@ def _inner(values, db_file_name='sql.db'):
5353
r' job_runner_name TEXT, job_id TEXT,'
5454
r' PRIMARY KEY(cycle, name, submit_num));'
5555
))
56-
for value in values:
57-
conn.execute(value)
56+
for stmt, values in stmts:
57+
conn.execute(stmt, values)
5858
conn.execute((
5959
r"INSERT INTO task_jobs VALUES"
6060
r" ('10090101T0000Z', 'foo', 1, 0, 1, '2022-12-05T14:46:06Z',"
@@ -69,13 +69,21 @@ def _inner(values, db_file_name='sql.db'):
6969

7070

7171
def test_upgrade_pre_810_fails_on_multiple_flows(_setup_db):
72-
values = [(
73-
r'INSERT INTO task_states VALUES'
74-
r" ('foo', '10050101T0000Z', '[1, 3]',"
75-
r" '2022-12-05T14:46:33Z',"
76-
r" '2022-12-05T14:46:40Z', 1, 'succeeded', 0, 0)"
72+
stmts = [(
73+
r'INSERT INTO task_states VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
74+
(
75+
'foo',
76+
'10050101T0000Z',
77+
'[1, 3]',
78+
'2022-12-05T14:46:33Z',
79+
'2022-12-05T14:46:40Z',
80+
1,
81+
'succeeded',
82+
0,
83+
0,
84+
),
7785
)]
78-
db_file_name = _setup_db(values)
86+
db_file_name = _setup_db(stmts)
7987
with CylcWorkflowDAO(db_file_name) as dao, pytest.raises(
8088
CylcError,
8189
match='^Cannot .* 8.0.x to 8.1.0 .* used.$'
@@ -84,13 +92,21 @@ def test_upgrade_pre_810_fails_on_multiple_flows(_setup_db):
8492

8593

8694
def test_upgrade_pre_810_pass_on_single_flow(_setup_db):
87-
values = [(
88-
r'INSERT INTO task_states VALUES'
89-
r" ('foo', '10050101T0000Z', '[1]',"
90-
r" '2022-12-05T14:46:33Z',"
91-
r" '2022-12-05T14:46:40Z', 1, 'succeeded', 0, 0)"
95+
stmts = [(
96+
r'INSERT INTO task_states VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
97+
(
98+
'foo',
99+
'10050101T0000Z',
100+
'[1]',
101+
'2022-12-05T14:46:33Z',
102+
'2022-12-05T14:46:40Z',
103+
1,
104+
'succeeded',
105+
0,
106+
0,
107+
),
92108
)]
93-
db_file_name = _setup_db(values)
109+
db_file_name = _setup_db(stmts)
94110
with CylcWorkflowDAO(db_file_name) as dao:
95111
WorkflowDatabaseManager.upgrade_pre_810(dao)
96112
result = dao.connect().execute(
@@ -104,14 +120,21 @@ def test_check_workflow_db_compat(_setup_db, capsys):
104120
"""
105121
# Create public and private databases with different cylc versions:
106122
create = r'CREATE TABLE workflow_params(key TEXT, value TEXT)'
107-
insert = (
108-
r'INSERT INTO workflow_params VALUES'
109-
r'("cylc_version", "{}")'
110-
)
123+
insert = r'INSERT INTO workflow_params VALUES (?, ?)'
111124
pri_path = _setup_db(
112-
[create, insert.format('7.99.99')], db_file_name='private/db')
125+
[
126+
(create, tuple()),
127+
(insert, ('cylc_version', '7.99.99')),
128+
],
129+
db_file_name='private/db',
130+
)
113131
pub_path = _setup_db(
114-
[create, insert.format('7.99.98')], db_file_name='public/db')
132+
[
133+
(create, tuple()),
134+
(insert, ('cylc_version', '7.99.98')),
135+
],
136+
db_file_name='public/db'
137+
)
115138

116139
with pytest.raises(ServiceFileError, match='99.98'):
117140
WorkflowDatabaseManager.check_db_compatibility(pub_path)
@@ -124,11 +147,11 @@ def test_cylc_7_db_wflow_params_table(_setup_db):
124147
"""Test back-compat needed by workflow state xtrigger for Cylc 7 DBs."""
125148
ptformat = "CCYY"
126149
create = r'CREATE TABLE suite_params(key TEXT, value TEXT)'
127-
insert = (
128-
r'INSERT INTO suite_params VALUES'
129-
rf'("cycle_point_format", "{ptformat}")'
130-
)
131-
db_file_name = _setup_db([create, insert])
150+
insert = r'INSERT INTO suite_params VALUES (?, ?)'
151+
db_file_name = _setup_db([
152+
(create, tuple()),
153+
(insert, ('cycle_point_format', ptformat)),
154+
])
132155
with CylcWorkflowDBChecker('foo', 'bar', db_path=db_file_name) as checker:
133156
with pytest.raises(
134157
sqlite3.OperationalError, match="no such table: workflow_params"
@@ -145,29 +168,48 @@ def test_pre_830_task_action_timers(_setup_db):
145168
index 1. TaskPool.load_db_task_action_timers() should be able to
146169
discard this field.
147170
"""
148-
values = [
149-
r'''
150-
CREATE TABLE task_action_timers(
151-
cycle TEXT, name TEXT, ctx_key TEXT, ctx TEXT, delays TEXT,
152-
num INTEGER, delay TEXT, timeout TEXT,
153-
PRIMARY KEY(cycle, name, ctx_key)
154-
);
155-
''',
156-
r'''
157-
INSERT INTO task_action_timers VALUES(
158-
'1','foo','[["event-mail", "failed"], 9]',
159-
'["TaskEventMailContext", ["event-mail", "event-mail", "[email protected]", "jfaden"]]',
160-
'[0.0]',1,'0.0','1709229449.61275'
161-
);
162-
''',
163-
r'''
164-
INSERT INTO task_action_timers VALUES(
165-
'1','foo','["try_timers", "execution-retry"]', null,
166-
'[94608000.0]',1,NULL,NULL
167-
);
168-
''',
171+
stmts = [
172+
(
173+
r'''
174+
CREATE TABLE task_action_timers(
175+
cycle TEXT, name TEXT, ctx_key TEXT, ctx TEXT, delays TEXT,
176+
num INTEGER, delay TEXT, timeout TEXT,
177+
PRIMARY KEY(cycle, name, ctx_key)
178+
);
179+
''',
180+
tuple(),
181+
),
182+
(
183+
r'INSERT INTO task_action_timers VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
184+
(
185+
'1',
186+
'foo',
187+
'[["event-mail", "failed"], 9]',
188+
(
189+
'["TaskEventMailContext", ["event-mail", "event-mail",'
190+
' "[email protected]", "jfaden"]]'
191+
),
192+
'[0.0]',
193+
1,
194+
'0.0',
195+
'1709229449.61275',
196+
)
197+
),
198+
(
199+
r'INSERT INTO task_action_timers VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
200+
(
201+
'1',
202+
'foo',
203+
'["try_timers", "execution-retry"]',
204+
None,
205+
'[94608000.0]',
206+
1,
207+
None,
208+
None,
209+
),
210+
),
169211
]
170-
db_file = _setup_db(values)
212+
db_file = _setup_db(stmts)
171213
mock_pool = Mock()
172214
load_db_task_action_timers = partial(
173215
TaskPool.load_db_task_action_timers, mock_pool

tests/unit/test_rundb.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

1717
import contextlib
18-
import json
1918
from pathlib import Path
2019
import sqlite3
2120
from types import SimpleNamespace
@@ -224,9 +223,8 @@ def test_select_latest_flow_nums(
224223
)
225224
for (fnums, timestamp) in values:
226225
conn.execute(
227-
"INSERT INTO task_states VALUES ("
228-
f"{json.dumps(serialise_set(fnums))}, {json.dumps(timestamp)}"
229-
")"
226+
'INSERT INTO task_states VALUES (?, ?)',
227+
(serialise_set(fnums), timestamp)
230228
)
231229
conn.commit()
232230

tests/unit/test_templatevars.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,25 @@ def _setup_db(tmp_path_factory):
118118
db_path = logfolder / WorkflowFiles.LogDir.DB
119119
with CylcWorkflowDAO(db_path, create_tables=True) as dao:
120120
dao.connect().execute(
121-
rf'''
121+
r'''
122122
INSERT INTO workflow_params
123123
VALUES
124-
("cylc_version", "{cylc_version}")
125-
'''
124+
(?, ?)
125+
''',
126+
("cylc_version", cylc_version),
126127
)
127-
dao.connect().execute(
128+
dao.connect().executemany(
128129
r'''
129130
INSERT INTO workflow_template_vars
130131
VALUES
131-
("FOO", "42"),
132-
("BAR", "'hello world'"),
133-
("BAZ", "'foo', 'bar', 48"),
134-
("QUX", "['foo', 'bar', 21]")
135-
'''
132+
(?, ?)
133+
''',
134+
[
135+
("FOO", "42"),
136+
("BAR", "'hello world'"),
137+
("BAZ", "'foo', 'bar', 48"),
138+
("QUX", "['foo', 'bar', 21]"),
139+
],
136140
)
137141
dao.connect().commit()
138142
yield get_template_vars_from_db(tmp_path)

0 commit comments

Comments
 (0)