Skip to content

Commit 471e1cc

Browse files
Merge pull request #108 from wfcommons/testing
Test improvements
2 parents 3d40837 + 037dda2 commit 471e1cc

File tree

4 files changed

+72
-12
lines changed

4 files changed

+72
-12
lines changed

tests/test_helpers.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
import io
66
import sys
77
import docker
8+
import networkx
89
from docker.errors import ImageNotFound
910

11+
from wfcommons.common import Workflow
12+
13+
1014
def _create_fresh_local_dir(path: str) -> pathlib.Path:
1115
dirpath = pathlib.Path(path)
1216
if dirpath.exists():
@@ -99,4 +103,30 @@ def _get_total_size_of_directory(directory_path: str):
99103
for filename in filenames:
100104
filepath = os.path.join(dirpath, filename)
101105
total_size += os.path.getsize(filepath)
102-
return total_size
106+
return total_size
107+
108+
def _compare_workflows(workflow1: Workflow, workflow_2: Workflow):
109+
110+
# Test the number of tasks
111+
assert (len(workflow1.tasks) == len(workflow_2.tasks))
112+
# Test the task graph topology
113+
assert (networkx.is_isomorphic(workflow1, workflow_2))
114+
# Test the total file size sum
115+
workflow1_input_bytes, workflow2_input_bytes = 0, 0
116+
workflow1_output_bytes, workflow2_output_bytes = 0, 0
117+
for workflow1_task, workflow2_task in zip(workflow1.tasks.values(), workflow_2.tasks.values()):
118+
# sys.stderr.write(f"WORKFLOW1: {workflow1_task.task_id} WORKFLOW2 TASK: {workflow2_task.task_id}\n")
119+
for input_file in workflow1_task.input_files:
120+
# sys.stderr.write(f"WORKFLOW1 INPUT FILE: {input_file.file_id} {input_file.size}\n")
121+
workflow1_input_bytes += input_file.size
122+
for input_file in workflow2_task.input_files:
123+
# sys.stderr.write(f"WORKFLOW2 INPUT FILE: {input_file.file_id} {input_file.size}\n")
124+
workflow2_input_bytes += input_file.size
125+
for output_file in workflow1_task.output_files:
126+
# sys.stderr.write(f"WORKFLOW1 OUTPUT FILE: {output_file.file_id} {output_file.size}\n")
127+
workflow1_output_bytes += output_file.size
128+
for output_file in workflow2_task.output_files:
129+
# sys.stderr.write(f"WORKFLOW2 OUTPUT FILE: {output_file.file_id} {output_file.size}\n")
130+
workflow2_output_bytes += output_file.size
131+
assert (workflow1_input_bytes == workflow2_input_bytes)
132+
assert (workflow1_output_bytes == workflow2_output_bytes)

tests/translators_loggers/test_translators_loggers.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@
1414
import sys
1515
import json
1616
import time
17+
import networkx
1718

1819
from tests.test_helpers import _create_fresh_local_dir
1920
from tests.test_helpers import _remove_local_dir_if_it_exists
2021
from tests.test_helpers import _start_docker_container
22+
from tests.test_helpers import _compare_workflows
23+
2124
from wfcommons import BlastRecipe
25+
from wfcommons.common import Workflow, Task
2226
from wfcommons.wfbench import WorkflowBenchmark
2327
from wfcommons.wfbench import DaskTranslator
2428
from wfcommons.wfbench import ParslTranslator
@@ -34,7 +38,7 @@
3438
from wfcommons.wfinstances.logs import TaskVineLogsParser
3539

3640

37-
def _create_workflow_benchmark():
41+
def _create_workflow_benchmark() -> (WorkflowBenchmark, int):
3842
# Create a workflow benchmark object to generate specifications based on a recipe (in /tmp/, whatever)
3943
desired_num_tasks = 45
4044
benchmark_full_path = "/tmp/blast-benchmark-{desired_num_tasks}.json"
@@ -85,8 +89,13 @@ def _additional_setup_swiftt(container):
8589
# Start a redis server in the background
8690
exit_code, output = container.exec_run(
8791
cmd=["bash", "-c", "redis-server"], detach=True, stdout=True, stderr=True)
88-
# Note that exit_code will always be None because of detach=True. So hopefully this works.
89-
# TODO?: check that the vine_worker is running....
92+
# Note that exit_code will always be None because of detach=True.
93+
94+
# Check that the redis-server is up
95+
exit_code, output = container.exec_run(
96+
cmd=["bash", "-c", "redis-cli ping"], stdout=True, stderr=True)
97+
if output.decode().strip() != 'PONG':
98+
raise Exception("Failed to start redis-server...")
9099

91100
additional_setup_methods = {
92101
"dask": noop,
@@ -242,6 +251,7 @@ def test_translator(self, backend) -> None:
242251
# Create workflow benchmark
243252
benchmark, num_tasks = _create_workflow_benchmark()
244253

254+
245255
# Create a local translation directory
246256
str_dirpath = "/tmp/" + backend + "_translated_workflow/"
247257
dirpath = pathlib.Path(str_dirpath)
@@ -270,13 +280,16 @@ def test_translator(self, backend) -> None:
270280
if backend == "pegasus":
271281
parser = PegasusLogsParser(dirpath / "work/wfcommons/pegasus/Blast-Benchmark/run0001/")
272282
elif backend == "taskvine":
273-
parser = TaskVineLogsParser(dirpath / "vine-run-info/", filenames_to_ignore=["cpu-benchmark","stress-ng"])
283+
parser = TaskVineLogsParser(dirpath / "vine-run-info/", filenames_to_ignore=["cpu-benchmark","stress-ng", "wfbench"])
274284
else:
275285
parser = None
276286

277287
if parser:
278288
sys.stderr.write("\nParsing the logs...\n")
279-
workflow = parser.build_workflow("reconstructed_workflow")
280-
# TODO: test more stuff
281-
workflow.write_json(pathlib.Path("/tmp/reconstructed_workflow.json"))
282-
assert(num_tasks == len(workflow.tasks))
289+
reconstructed_workflow : Workflow = parser.build_workflow("reconstructed_workflow")
290+
reconstructed_workflow.write_json(pathlib.Path("/tmp/reconstructed_workflow.json"))
291+
292+
original_workflow : Workflow = benchmark.workflow
293+
294+
_compare_workflows(original_workflow, reconstructed_workflow)
295+

tests/wfbench/test_wfbench.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@
1313
import pathlib
1414
import sys
1515
import json
16+
import networkx
1617

1718
from tests.test_helpers import _create_fresh_local_dir
1819
from tests.test_helpers import _start_docker_container
1920
from tests.test_helpers import _remove_local_dir_if_it_exists
2021
from tests.test_helpers import _get_total_size_of_directory
22+
from tests.test_helpers import _compare_workflows
23+
2124
from wfcommons import BlastRecipe
2225
from wfcommons.common import Workflow
2326
from wfcommons.wfbench import WorkflowBenchmark, BashTranslator
27+
from wfcommons.wfinstances import Instance
28+
2429

2530
def _directory_content_as_expected(dirpath: pathlib.Path,
2631
workflow: Workflow,
@@ -38,11 +43,16 @@ def _workflow_as_expected(dirpath: pathlib.Path,
3843
num_tasks: int,
3944
cpu_work: int,
4045
percent_cpu: float):
46+
47+
# Some checks based on the generated JSON
48+
#########################################
49+
4150
# Get the generated JSON
4251
json_path = dirpath / f"{workflow.name.lower()}-{num_tasks}.json"
4352
with json_path.open("r") as f:
4453
generated_json = json.load(f)
4554

55+
4656
# Check the number of tasks
4757
assert(len(workflow.tasks) == len(generated_json['workflow']['specification']['tasks']))
4858

@@ -59,7 +69,13 @@ def _workflow_as_expected(dirpath: pathlib.Path,
5969
for file in workflow_task.input_files:
6070
assert(file.file_id in generated_task['inputFiles'])
6171

62-
# TODO: Implement more sanity checks
72+
# Some checks based on an Instance generated from the JSON
73+
##########################################################
74+
75+
# Get the generated Workflow via an Instance
76+
reconstructed_workflow = Instance(json_path).workflow
77+
78+
_compare_workflows(workflow, reconstructed_workflow)
6379

6480
return True
6581

wfcommons/wfinstances/logs/taskvine.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ class TaskVineLogsParser(LogsParser):
3636
3737
:param vine_run_info_dir: TaskVine's vine-run-info directory.
3838
:type vine_run_info_dir: pathlib.Path
39-
:param filenames_to_ignore: TaskVine considers that executables and package files (e.g., poncho package.tgz)
39+
:param filenames_to_ignore: TaskVine sometimes considers that executables and package files
4040
are input to tasks. This argument is the list of names of files that should be
4141
ignored in the reconstructed instances, which typically do not include such
42-
files at task input.
42+
files at task input. For instance, if reconstructing a workflow from an execution
43+
of a WfBench-generated benchmark, one could pass ["wfbench", "cpu-benchmark", "stress-ng"]
4344
:type filenames_to_ignore: List[str]
4445
:param description: Workflow instance description.
4546
:type description: Optional[str]

0 commit comments

Comments
 (0)