Skip to content

Commit da12869

Browse files
author
Alan Christie
committed
test: Add mock of step outputs
1 parent 12b3602 commit da12869

File tree

4 files changed

+131
-23
lines changed

4 files changed

+131
-23
lines changed

tests/test_test_api_adapter.py

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -443,19 +443,75 @@ def test_get_running_workflow_step_by_name():
443443
assert response["id"] == rwfs_id
444444

445445

446-
def test_basic_get_running_workflow_step_output_values_for_output_when_step_unknown():
446+
def test_mock_get_running_workflow_step_output_values_for_output():
447447
# Arrange
448448
utaa = UnitTestWorkflowAPIAdapter()
449+
response = utaa.create_workflow(workflow_definition={"name": "blah"})
450+
response = utaa.create_running_workflow(
451+
user_id="dlister",
452+
workflow_id=response["id"],
453+
project_id=TEST_PROJECT_ID,
454+
variables={},
455+
)
456+
response, _ = utaa.create_running_workflow_step(
457+
running_workflow_id=response["id"], step="step-1"
458+
)
449459

450460
# Act
461+
utaa.mock_get_running_workflow_step_output_values_for_output(
462+
step_name="step-1", output_variable="results", output=["a", "b"]
463+
)
464+
465+
# Assert
451466
response, _ = utaa.get_running_workflow_step_output_values_for_output(
452467
running_workflow_step_id="r-workflow-step-00000000-0000-0000-0000-000000000001",
453-
output="outputFile",
468+
output_variable="results",
469+
)
470+
assert "output" in response
471+
assert len(response["output"]) == 2
472+
assert "a" in response["output"]
473+
assert "b" in response["output"]
474+
475+
476+
def test_basic_get_running_workflow_step_output_values_for_output_when_step_variable_name_unknown():
477+
# Arrange
478+
utaa = UnitTestWorkflowAPIAdapter()
479+
response = utaa.create_workflow(workflow_definition={"name": "blah"})
480+
response = utaa.create_running_workflow(
481+
user_id="dlister",
482+
workflow_id=response["id"],
483+
project_id=TEST_PROJECT_ID,
484+
variables={},
485+
)
486+
response, _ = utaa.create_running_workflow_step(
487+
running_workflow_id=response["id"], step="step-1"
488+
)
489+
490+
# Act
491+
utaa.mock_get_running_workflow_step_output_values_for_output(
492+
step_name="step-1", output_variable="results", output=["a", "b"]
454493
)
455494

456495
# Assert
457-
assert "outputs" in response
458-
assert len(response["outputs"]) == 0
496+
with pytest.raises(AssertionError):
497+
_, _ = utaa.get_running_workflow_step_output_values_for_output(
498+
running_workflow_step_id="r-workflow-step-00000000-0000-0000-0000-000000000001",
499+
output_variable="unknownVariable",
500+
)
501+
502+
503+
def test_basic_get_running_workflow_step_output_values_for_output_when_step_unknown():
504+
# Arrange
505+
utaa = UnitTestWorkflowAPIAdapter()
506+
507+
# Act
508+
with pytest.raises(AssertionError):
509+
_, _ = utaa.get_running_workflow_step_output_values_for_output(
510+
running_workflow_step_id="r-workflow-step-00000000-0000-0000-0000-000000000001",
511+
output_variable="outputFile",
512+
)
513+
514+
# Assert
459515

460516

461517
def test_basic_realise():

tests/test_workflow_engine_examples.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def basic_engine():
4242
print("Starting message queue...")
4343
message_queue.start()
4444

45-
yield [wapi_adapter, message_dispatcher]
45+
yield [message_dispatcher, wapi_adapter]
4646

4747
print("Stopping message queue...")
4848
message_queue.stop()
@@ -145,7 +145,7 @@ def wait_for_workflow(
145145

146146
def test_workflow_engine_example_two_step_nop(basic_engine):
147147
# Arrange
148-
da, md = basic_engine
148+
md, da = basic_engine
149149

150150
# Act
151151
r_wfid = start_workflow(md, da, "example-two-step-nop", {})
@@ -164,7 +164,7 @@ def test_workflow_engine_example_two_step_nop(basic_engine):
164164

165165
def test_workflow_engine_example_nop_fail(basic_engine):
166166
# Arrange
167-
da, md = basic_engine
167+
md, da = basic_engine
168168

169169
# Act
170170
r_wfid = start_workflow(md, da, "example-nop-fail", {})
@@ -181,7 +181,7 @@ def test_workflow_engine_example_nop_fail(basic_engine):
181181

182182
def test_workflow_engine_example_smiles_to_file(basic_engine):
183183
# Arrange
184-
da, md = basic_engine
184+
md, da = basic_engine
185185
# Make sure a file that should be generated by the test
186186
# does not exist before we run the test.
187187
output_file = "ethanol.smi"
@@ -206,7 +206,7 @@ def test_workflow_engine_example_smiles_to_file(basic_engine):
206206

207207
def test_workflow_engine_shortcut_example_1(basic_engine):
208208
# Arrange
209-
da, md = basic_engine
209+
md, da = basic_engine
210210
# Make sure files that should be generated by the test
211211
# do not exist before we run the test.
212212
output_file_a = "a.sdf"
@@ -234,7 +234,7 @@ def test_workflow_engine_shortcut_example_1(basic_engine):
234234

235235
def test_workflow_engine_simple_python_molprops(basic_engine):
236236
# Arrange
237-
da, md = basic_engine
237+
md, da = basic_engine
238238
# Make sure files that should be generated by the test
239239
# do not exist before we run the test.
240240
output_file_1 = "step1.out.smi"
@@ -315,7 +315,7 @@ def test_workflow_engine_simple_python_molprops(basic_engine):
315315

316316
def test_workflow_engine_simple_python_molprops_with_options(basic_engine):
317317
# Arrange
318-
da, md = basic_engine
318+
md, da = basic_engine
319319
# Make sure files that should be generated by the test
320320
# do not exist before we run the test.
321321
output_file_1 = "step1.out.smi"
@@ -403,7 +403,7 @@ def test_workflow_engine_simple_python_molprops_with_options(basic_engine):
403403

404404
def test_workflow_engine_simple_python_parallel(basic_engine):
405405
# Arrange
406-
da, md = basic_engine
406+
md, da = basic_engine
407407
# Make sure files that should be generated by the test
408408
# do not exist before we run the test.
409409
output_file_first = "first-step.out.smi"

tests/wapi_adapter.py

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
method.
1616
"""
1717

18+
import copy
1819
import os
1920
from http import HTTPStatus
2021
from multiprocessing import Lock
@@ -49,6 +50,7 @@
4950
f"{_PICKLE_DIRECTORY}/running-workflow-step.pickle"
5051
)
5152
_INSTANCE_PICKLE_FILE: str = f"{_PICKLE_DIRECTORY}/instance.pickle"
53+
_MOCK_STEP_OUTPUT_FILE: str = f"{_PICKLE_DIRECTORY}/mock-output.pickle"
5254

5355

5456
class UnitTestWorkflowAPIAdapter(WorkflowAPIAdapter):
@@ -73,12 +75,13 @@ def __init__(self):
7375
_RUNNING_WORKFLOW_PICKLE_FILE,
7476
_RUNNING_WORKFLOW_STEP_PICKLE_FILE,
7577
_INSTANCE_PICKLE_FILE,
78+
_MOCK_STEP_OUTPUT_FILE,
7679
]:
7780
with open(file, "wb") as pickle_file:
7881
Pickler(pickle_file).dump({})
7982
UnitTestWorkflowAPIAdapter.lock.release()
8083

81-
def get_workflow(self, *, workflow_id: str) -> dict[str, Any]:
84+
def get_workflow(self, *, workflow_id: str) -> tuple[dict[str, Any], int]:
8285
UnitTestWorkflowAPIAdapter.lock.acquire()
8386
with open(_WORKFLOW_PICKLE_FILE, "rb") as pickle_file:
8487
workflow = Unpickler(pickle_file).load()
@@ -138,7 +141,7 @@ def create_running_workflow_step(
138141
step: str,
139142
replica: int = 0,
140143
prior_running_workflow_step_id: str | None = None,
141-
) -> dict[str, Any]:
144+
) -> tuple[dict[str, Any], int]:
142145
if replica:
143146
assert replica > 0
144147

@@ -172,7 +175,7 @@ def create_running_workflow_step(
172175

173176
def get_running_workflow_step(
174177
self, *, running_workflow_step_id: str
175-
) -> dict[str, Any]:
178+
) -> tuple[dict[str, Any], int]:
176179
UnitTestWorkflowAPIAdapter.lock.acquire()
177180
with open(_RUNNING_WORKFLOW_STEP_PICKLE_FILE, "rb") as pickle_file:
178181
running_workflow_step = Unpickler(pickle_file).load()
@@ -188,7 +191,7 @@ def get_running_workflow_step(
188191

189192
def get_running_workflow_step_by_name(
190193
self, *, name: str, running_workflow_id: str, replica: int = 0
191-
) -> dict[str, Any]:
194+
) -> tuple[dict[str, Any], int]:
192195
if replica:
193196
assert replica > 0
194197
UnitTestWorkflowAPIAdapter.lock.acquire()
@@ -293,7 +296,9 @@ def get_instance(self, *, instance_id: str) -> dict[str, Any]:
293296
response = {} if instance_id not in instances else instances[instance_id]
294297
return response, 0
295298

296-
def get_job(self, *, collection: str, job: str, version: str) -> dict[str, Any]:
299+
def get_job(
300+
self, *, collection: str, job: str, version: str
301+
) -> tuple[dict[str, Any], int]:
297302
assert collection == _JOB_DEFINITIONS["collection"]
298303
assert job in _JOB_DEFINITIONS["jobs"]
299304
assert version
@@ -391,14 +396,61 @@ def get_running_workflow_steps(self, *, running_workflow_id: str) -> dict[str, A
391396
return {"count": len(steps), "running_workflow_steps": steps}
392397

393398
def get_running_workflow_step_output_values_for_output(
394-
self, *, running_workflow_step_id: str, output: str
399+
self, *, running_workflow_step_id: str, output_variable: str
395400
) -> tuple[dict[str, Any], int]:
396-
del running_workflow_step_id
397-
del output
398-
return {"outputs": []}, HTTPStatus.OK
401+
"""We use the 'mock' data to return output values, otherwise
402+
we return an empty list. And we need to get the step in order to get its name.
403+
"""
404+
# The RunningWorkflowStep must exist...
405+
step, _ = self.get_running_workflow_step(
406+
running_workflow_step_id=running_workflow_step_id
407+
)
408+
assert step
409+
step_name: str = step["name"]
410+
# Now we can inspect the 'mock' data...
411+
UnitTestWorkflowAPIAdapter.lock.acquire()
412+
with open(_MOCK_STEP_OUTPUT_FILE, "rb") as pickle_file:
413+
mock_output = Unpickler(pickle_file).load()
414+
UnitTestWorkflowAPIAdapter.lock.release()
415+
416+
if step_name not in mock_output:
417+
return {"output": []}, 0
418+
# The record's output variable must match (there's only one record per step atm)
419+
assert mock_output[step_name]["output_variable"] == output_variable
420+
# Now return what was provided to the mock method...
421+
response = {"output": copy.copy(mock_output[step_name]["output"])}
422+
return response, 0
399423

400424
def realise_outputs(
401425
self, *, running_workflow_step_id: str
402426
) -> tuple[dict[str, Any], int]:
403427
del running_workflow_step_id
404428
return {}, HTTPStatus.OK
429+
430+
# Custom (test) methods
431+
# Methods not declared in the ABC
432+
433+
def mock_get_running_workflow_step_output_values_for_output(
434+
self, *, step_name: str, output_variable: str, output: list[str]
435+
) -> None:
436+
"""Sets the output response for a step.
437+
Limitation is that there can only be one record for each step name
438+
so, for now, the output_variable is superfluous and only used
439+
to check the output variable name matches."""
440+
assert isinstance(step_name, str)
441+
assert isinstance(output_variable, str)
442+
assert isinstance(output, list)
443+
444+
UnitTestWorkflowAPIAdapter.lock.acquire()
445+
with open(_MOCK_STEP_OUTPUT_FILE, "rb") as pickle_file:
446+
mock_output = Unpickler(pickle_file).load()
447+
448+
record = {
449+
"output_variable": output_variable,
450+
"output": output,
451+
}
452+
mock_output[step_name] = record
453+
454+
with open(_MOCK_STEP_OUTPUT_FILE, "wb") as pickle_file:
455+
Pickler(pickle_file).dump(mock_output)
456+
UnitTestWorkflowAPIAdapter.lock.release()

workflow/workflow_abc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,15 +350,15 @@ def get_job(
350350

351351
@abstractmethod
352352
def get_running_workflow_step_output_values_for_output(
353-
self, *, running_workflow_step_id: str, output: str
353+
self, *, running_workflow_step_id: str, output_variable: str
354354
) -> tuple[dict[str, Any], int]:
355355
"""Gets the set of outputs generated for the output variable of a given step.
356356
The step must have stopped for this to return any meaningful value.
357357
Returned files might also include paths that are relative to the
358358
Step's instance directory."""
359359
# Should return a (possibly empty) list of paths and filenames:
360360
# {
361-
# "outputs": ["dir/file1.sdf", "dir/file2.sdf"]
361+
# "output": ["dir/file1.sdf", "dir/file2.sdf"]
362362
# }
363363

364364
@abstractmethod

0 commit comments

Comments
 (0)