Skip to content

Commit 0275739

Browse files
author
Alan Christie
committed
feat: Add smiles-to-file workflow (and test)
1 parent 2b63b3f commit 0275739

File tree

3 files changed

+61
-8
lines changed

3 files changed

+61
-8
lines changed

tests/instance_launcher.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import os
3+
import shutil
34
import subprocess
45
from datetime import datetime, timezone
56
from subprocess import CompletedProcess
@@ -14,7 +15,16 @@
1415
from tests.message_dispatcher import UnitTestMessageDispatcher
1516
from workflow.workflow_abc import InstanceLauncher, LaunchResult
1617

17-
_JOB_DIRECTORY: str = os.path.join(os.path.dirname(__file__), "jobs")
18+
# Full path to the 'jobs' directory
19+
_JOB_PATH: str = os.path.join(os.path.dirname(__file__), "jobs")
20+
# Relative path to the execution (project) directory
21+
_EXECUTION_DIRECTORY: str = os.path.join("tests", "project-root", TEST_PROJECT_ID)
22+
23+
24+
def project_file_exists(file_name: str) -> bool:
25+
"""A convenient test function to verify a file exists
26+
in the execution (project) directory."""
27+
return os.path.isfile(os.path.join(_EXECUTION_DIRECTORY, file_name))
1828

1929

2030
class UnitTestInstanceLauncher(InstanceLauncher):
@@ -43,6 +53,11 @@ def __init__(
4353
self._api_adapter = api_adapter
4454
self._msg_dispatcher = msg_dispatcher
4555

56+
# Every launcher starts with an empty execution directory...
57+
print(f"Removing execution directory ({_EXECUTION_DIRECTORY})")
58+
assert _EXECUTION_DIRECTORY.startswith("tests/project-root")
59+
shutil.rmtree(_EXECUTION_DIRECTORY, ignore_errors=True)
60+
4661
def launch(
4762
self,
4863
*,
@@ -60,6 +75,8 @@ def launch(
6075

6176
assert project_id == TEST_PROJECT_ID
6277

78+
os.makedirs(_EXECUTION_DIRECTORY, exist_ok=True)
79+
6380
# We're passed a RunningWorkflowStep ID but a record is expected to have been
6481
# created bt the caller, we simply create instance records.
6582
response = self._api_adapter.get_running_workflow_step(
@@ -74,10 +91,6 @@ def launch(
7491
response = self._api_adapter.create_task(instance_id=instance_id)
7592
task_id = response["id"]
7693

77-
# Where to run the job (i.e. in the test project directory)
78-
execution_directory = f"tests/project-root/{project_id}"
79-
os.makedirs(execution_directory, exist_ok=True)
80-
8194
# Apply variables to the step's Job command.
8295
step_specification_map = json.loads(step_specification)
8396
job = self._api_adapter.get_job(
@@ -99,15 +112,15 @@ def launch(
99112
assert status
100113

101114
# Now run the decoded command, which will be in the _JOB_DIRECTORY
102-
command = f"{_JOB_DIRECTORY}/{decoded_command}"
115+
command = f"{_JOB_PATH}/{decoded_command}"
103116
command_list = command.split()
104117
module = command_list[0]
105118
print(f"Module: {module}")
106119
assert os.path.isfile(module)
107120
subprocess_cmd: List[str] = ["python"] + command_list
108121
print(f"Subprocess command: {subprocess_cmd}")
109122
completed_process: CompletedProcess = subprocess.run(
110-
subprocess_cmd, check=False, cwd=execution_directory
123+
subprocess_cmd, check=False, cwd=_EXECUTION_DIRECTORY
111124
)
112125

113126
# Simulate a PodMessage (that will contain the instance ID),

tests/test_workflow_engine_examples.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from tests.api_adapter import UnitTestAPIAdapter
1414
from tests.config import TEST_PROJECT_ID
15-
from tests.instance_launcher import UnitTestInstanceLauncher
15+
from tests.instance_launcher import UnitTestInstanceLauncher, project_file_exists
1616
from tests.message_dispatcher import UnitTestMessageDispatcher
1717
from tests.message_queue import UnitTestMessageQueue
1818
from workflow.workflow_engine import WorkflowEngine
@@ -148,3 +148,28 @@ def test_workflow_engine_example_nop_fail(basic_engine):
148148
assert response["count"] == 1
149149
assert response["running_workflow_steps"][0]["running_workflow_step"]["done"]
150150
assert not response["running_workflow_steps"][0]["running_workflow_step"]["success"]
151+
152+
153+
def test_workflow_engine_example_smiles_to_file(basic_engine):
154+
# Arrange
155+
da, md = basic_engine
156+
# Make sure a file that should be generated by the test
157+
# does not exist before we run the test.
158+
output_file = "ethanol.smi"
159+
assert not project_file_exists(output_file)
160+
161+
# Act
162+
r_wfid = start_workflow(
163+
md, da, "example-smiles-to-file", {"smiles": "CCO", "outputFile": output_file}
164+
)
165+
166+
# Assert
167+
wait_for_workflow(da, r_wfid)
168+
# Additional, detailed checks...
169+
# Check we only haver one step, and it failed
170+
response = da.get_running_workflow_steps(running_workflow_id=r_wfid)
171+
assert response["count"] == 1
172+
assert response["running_workflow_steps"][0]["running_workflow_step"]["done"]
173+
assert response["running_workflow_steps"][0]["running_workflow_step"]["success"]
174+
# This test should generate some files now existing the project directory
175+
assert project_file_exists(output_file)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
kind: DataManagerWorkflow
3+
kind-version: "2024.1"
4+
name: smiles-to-file
5+
description: >-
6+
A workflow with one step that uses variables.
7+
The step takes an input string and the Job creates a file from it.
8+
steps:
9+
- name: step-1
10+
specification: >-
11+
{
12+
"collection": "workflow-engine-unit-test-jobs",
13+
"job": "smiles-to-file",
14+
"version": "1.0.0"
15+
}

0 commit comments

Comments
 (0)