Skip to content

Commit f81af36

Browse files
committed
merge wfcommons_test
2 parents a0e22bd + 50bdbfe commit f81af36

13 files changed

Lines changed: 266 additions & 21 deletions

File tree

.github/workflows/build.yml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
name: Build
22

3-
on:
4-
push:
5-
branches:
6-
- main
3+
on: push
74

85
jobs:
96
build:
@@ -13,17 +10,28 @@ jobs:
1310
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
1411
steps:
1512
- uses: actions/checkout@v4
13+
1614
- name: Set up Python ${{ matrix.python-version }}
1715
uses: actions/setup-python@v5
1816
with:
1917
python-version: ${{ matrix.python-version }}
18+
2019
- name: Install dependencies
2120
run: |
2221
sudo apt-get install -y python3-sphinx sphinx-rtd-theme-common
23-
pip install sphinx_rtd_theme recommonmark
22+
pip install sphinx_rtd_theme recommonmark pytest pytest-cov
23+
2424
- name: Check package install
2525
run: |
26-
pip install .
26+
pip install -e .
27+
28+
- name: Run tests
29+
run: pytest -m unit --cov=wfcommons tests/
30+
31+
- name: Upload coverage
32+
if: github.ref == 'refs/heads/main'
33+
uses: codecov/codecov-action@v4
34+
2735
- name: Build documentation
2836
run: |
2937
cd docs

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ venv
4444
# Workflow Schema
4545
workflow-schema.json
4646

47+
# Binaries
48+
bin/cpu-benchmark
49+
bin/cpu-benchmark.o
50+
4751
# wfc-1.3_to_dask specifics
4852
/wfcommons/wfc-1.3_to_dask/__pycache__/
4953
/wfcommons/wfc-1.3_to_dask/.coverage

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ This Python package provides a collection of tools for:
2020
## Installation
2121

2222
WfCommons is available on [PyPI](https://pypi.org/project/wfcommons).
23-
WfCommons requires Python3.8+ and has been tested on Linux and macOS.
23+
WfCommons requires Python3.9+ and has been tested on Linux and macOS.
2424

2525
### Installation using pip
2626

docs/source/quickstart_installation.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Installation
22
============
33

44
WfCommons is available on `PyPI <https://pypi.org/project/wfcommons>`_.
5-
WfCommons requires Python3.6+ and has been tested on Linux and macOS.
5+
WfCommons requires Python3.9+ and has been tested on Linux and macOS.
66

77
Installation using pip
88
----------------------

pyproject.toml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
[build-system]
2+
requires = ["setuptools>=65.5.1"] # PEP 518 specifications
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "wfcommons"
7+
authors = [{name = "WfCommons team", email = "support@wfcommons.org"}]
8+
description = "A Framework for Enabling Scientific Workflow Research and Education"
9+
readme = "README.md"
10+
requires-python = ">=3.8"
11+
classifiers = [
12+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
13+
"Operating System :: OS Independent",
14+
"Programming Language :: Python :: 3",
15+
"Programming Language :: Python :: 3.9",
16+
"Programming Language :: Python :: 3.10",
17+
"Programming Language :: Python :: 3.11",
18+
"Programming Language :: Python :: 3.12",
19+
"Intended Audience :: Developers",
20+
"Intended Audience :: Education",
21+
"Intended Audience :: Science/Research",
22+
"Natural Language :: English",
23+
"Topic :: Documentation :: Sphinx",
24+
"Topic :: System :: Distributed Computing"
25+
]
26+
license = {text = "GNU General Public License v3 (GPLv3)"}
27+
dependencies = [
28+
"jsonschema",
29+
"matplotlib",
30+
"networkx",
31+
"numpy",
32+
"python-dateutil",
33+
"requests",
34+
"scipy",
35+
"pyyaml",
36+
"pandas",
37+
"stringcase"
38+
]
39+
dynamic = ["version"]
40+
41+
[project.urls]
42+
Homepage = "https://wfcommons.org"
43+
Source = "https://github.com/wfcommons/wfcommons"
44+
Documentation = "https://docs.wfcommons.org"
45+
Tracker = "https://github.com/wfcommons/WfCommons/issues"
46+
47+
[project.optional-dependencies]
48+
test = ["pytest", "pytest-cov"]
49+
50+
[tool.setuptools.dynamic]
51+
version = {attr = "wfcommons.version.__version__"}
52+
53+
[tool.pytest.ini_options]
54+
addopts="""
55+
--cov-context test \
56+
--cov-config pyproject.toml \
57+
--cov-report xml:coverage.xml \
58+
--cov-report term-missing \
59+
--cov ./wfcommons \
60+
--ignore wfcommons/wfbench/translator/templates \
61+
--no-cov-on-fail \
62+
-ra \
63+
-W ignore"""
64+
testpaths = [
65+
"tests"
66+
]
67+
markers = [
68+
"unit: Mark a test as a unit test"
69+
]

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def run(self):
3333

3434
setup(
3535
name='wfcommons',
36-
version=str(__version__),
36+
version="1.1",
3737
license='LGPLv3',
3838
author='WfCommons team',
3939
author_email='support@wfcommons.org',
@@ -75,7 +75,7 @@ def run(self):
7575
'Topic :: Documentation :: Sphinx',
7676
'Topic :: System :: Distributed Computing'
7777
],
78-
python_requires='>=3.8',
78+
python_requires='>=3.9',
7979
data_files=[
8080
('bin', ['bin/cpu-benchmark', 'bin/wfbench'])
8181
],

tests/unit/test_task.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2024 The WfCommons Team.
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
11+
import pytest
12+
13+
from wfcommons.common import Task, TaskType, File, FileLink, Machine, MachineSystem
14+
15+
16+
task_name = "Task Test"
17+
task_id = "task_test_1"
18+
input_files = [File(file_id="file_in_1", size=10, link=FileLink.INPUT), File(file_id="file_in_2", size=20, link=FileLink.INPUT)]
19+
output_files = [File(file_id="file_out_1", size=30, link=FileLink.OUTPUT), File(file_id="file_out_2", size=40, link=FileLink.OUTPUT)]
20+
21+
22+
class TestTask:
23+
24+
@pytest.fixture
25+
def task(self) -> Task:
26+
return Task(
27+
name=task_name,
28+
task_id=task_id,
29+
runtime=123.45,
30+
input_files=input_files,
31+
output_files=output_files,
32+
category="task_test",
33+
machines=[Machine(name="machine_1", cpu = {"coreCount": 48, "speedInMHz": 1200, "vendor": "Vendor Name"})],
34+
program="program",
35+
args=["arg_1", "arg_2"],
36+
avg_cpu=0.5,
37+
bytes_read=12345,
38+
bytes_written=54321,
39+
memory=10,
40+
energy=100,
41+
avg_power=1.0,
42+
priority=100,
43+
executedAt="2024-09-15T08:59:33.699321-04:00",
44+
task_type=TaskType.COMPUTE,
45+
launch_dir="/tmp",
46+
)
47+
48+
@pytest.mark.unit
49+
def test_task_specification(self, task: Task) -> None:
50+
51+
task_specification = {
52+
"name": task_name,
53+
"id": task_id,
54+
"parents": [],
55+
"children": [],
56+
"inputFiles": [str(f) for f in input_files],
57+
"outputFiles": [str(f) for f in output_files]
58+
}
59+
60+
assert(task_specification == task.specification_as_dict())

tests/unit/test_workflow.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2024 The WfCommons Team.
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
11+
import pathlib
12+
import pytest
13+
14+
from wfcommons.common import Task, Workflow
15+
from wfcommons.version import __version__, __schema_version__
16+
17+
18+
tasks_list = [
19+
([Task(name="task_1", task_id="task_1", runtime=15.0)]),
20+
([Task(name="task_1", task_id="task_1", runtime=15.0), Task(name="task_2", task_id="task_2", runtime=30.0)]),
21+
([Task(name="task_1", task_id="task_1", runtime=15.0), Task(name="task_2", task_id="task_2", runtime=30.0), Task(name="task_3", task_id="task_3", runtime=60.0)]),
22+
]
23+
24+
25+
class TestWorkflow:
26+
27+
@pytest.fixture
28+
def workflow(self) -> Workflow:
29+
return Workflow(
30+
name="Workflow Test",
31+
makespan=100.0
32+
)
33+
34+
@pytest.mark.unit
35+
def test_workflow_creation(self, workflow: Workflow) -> None:
36+
workflow.write_json(pathlib.Path("/tmp/workflow_test.json"))
37+
38+
workflow_json = {
39+
"name": "Workflow Test",
40+
"description": "Instance generated with WfCommons - https://wfcommons.org",
41+
"createdAt": workflow.created_at,
42+
"schemaVersion": f"{__schema_version__}",
43+
"author": {
44+
"name": f"{workflow.author_name}",
45+
"email": "support@wfcommons.org"
46+
},
47+
"workflow": {
48+
"specification": {
49+
"tasks": [],
50+
"files": []
51+
},
52+
"execution": {
53+
"makespanInSeconds": 100.0,
54+
"executedAt": workflow.executed_at,
55+
"tasks": []
56+
}
57+
},
58+
"runtimeSystem": {
59+
"name": "WfCommons",
60+
"version": f"{__version__}",
61+
"url": "https://docs.wfcommons.org/en/v1.1.dev/"
62+
}
63+
}
64+
65+
assert(workflow.workflow_json == workflow_json)
66+
67+
@pytest.mark.unit
68+
def test_workflow_empty_tasks(self, workflow: Workflow) -> None:
69+
assert(not workflow.tasks)
70+
71+
@pytest.mark.parametrize(("tasks"), tasks_list)
72+
@pytest.mark.unit
73+
def test_workflow_add_tasks(self, workflow: Workflow, tasks: list[Task]) -> None:
74+
tasks_list = []
75+
for task in tasks:
76+
workflow.add_task(task)
77+
tasks_list.append(task.task_id)
78+
assert(workflow.leaves() == tasks_list)
79+
80+
@pytest.mark.parametrize(("tasks"), tasks_list)
81+
@pytest.mark.unit
82+
def test_workflow_add_dependencies_roots(self, workflow: Workflow, tasks: list[Task]) -> None:
83+
previous_task = None
84+
for task in tasks:
85+
workflow.add_task(task)
86+
if previous_task:
87+
workflow.add_dependency(previous_task.task_id, task.task_id)
88+
previous_task = task
89+
assert(workflow.roots() == [tasks[0].task_id])
90+
91+
@pytest.mark.parametrize(("tasks"), tasks_list)
92+
@pytest.mark.unit
93+
def test_workflow_add_dependencies_leaves(self, workflow: Workflow, tasks: list[Task]) -> None:
94+
previous_task = None
95+
for task in tasks:
96+
workflow.add_task(task)
97+
if previous_task:
98+
workflow.add_dependency(previous_task.task_id, task.task_id)
99+
previous_task = task
100+
assert(workflow.leaves() == [previous_task.task_id])

wfcommons/common/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
# (at your option) any later version.
1010

1111
from .workflow import Workflow
12-
from .file import File
13-
from .file import FileLink
14-
from .task import Task
15-
from .task import TaskType
12+
from .file import File, FileLink
13+
from .task import Task, TaskType
14+
from .machine import Machine, MachineSystem

wfcommons/common/file.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ def as_dict(self) -> Dict[str, Union[str, int, FileLink]]:
5353
'id': self.file_id,
5454
'sizeInBytes': self.size
5555
}
56+
57+
def __str__(self) -> str:
58+
return self.file_id

0 commit comments

Comments
 (0)