Skip to content

Commit 285c23f

Browse files
180 remove dependency on test harness (#182)
* 180 - replace test harness Job with new class and tests * 180 - Remove install of test harness and remove from readme * 180 - remove mention of erebus * 180 - update requirements
1 parent 4bd6e94 commit 285c23f

File tree

7 files changed

+213
-33
lines changed

7 files changed

+213
-33
lines changed

.github/workflows/PythonLinting.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
2727
pip install -r requirements.txt
2828
29-
- name: Install janus and erebus as packages
29+
- name: Install janus as package
3030
run: |
3131
chmod +x ./scripts/install_repositories.sh && ./scripts/install_repositories.sh
3232

.github/workflows/test-workflow.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
conda install -y -c conda-forge cvxopt
3838
conda install -y -c conda-forge pygraphviz
3939
40-
- name: Install janus and erebus as packages
40+
- name: Install janus as package
4141
run: |
4242
chmod +x ./scripts/install_repositories.sh && ./scripts/install_repositories.sh
4343
@@ -74,7 +74,7 @@ jobs:
7474
sudo apt install -y libsuitesparse-dev
7575
sudo apt install -y libsuitesparse-dev
7676
77-
- name: Install janus and erebus as packages
77+
- name: Install janus as package
7878
run: |
7979
chmod +x ./scripts/install_repositories.sh && ./scripts/install_repositories.sh
8080
@@ -106,7 +106,7 @@ jobs:
106106
python-version: '3.11.9'
107107
cache: 'pip'
108108

109-
- name: Install janus and erebus as packages
109+
- name: Install janus as package
110110
run: |
111111
chmod +x ./scripts/install_repositories.sh && ./scripts/install_repositories.sh
112112

README.md

+2-6
Original file line numberDiff line numberDiff line change
@@ -339,17 +339,13 @@ Documentation for tel2puml can be found in the [docs](docs) folder. This contain
339339

340340
## Dependencies
341341

342-
TEL2PUML depends on two other repositories:
342+
TEL2PUML depends on one other repository:
343343

344344
1. [Janus](https://github.com/xtuml/janus):
345345

346346
Janus ingests PUML activity diagram files and generates event sequences from them.
347347

348-
2. [Erebus](https://github.com/xtuml/erebus):
349-
350-
Erebus is a test harness framework for the protocol verifier.
351-
352-
These dependencies are automatically managed when using the devcontainer setup or when running the `install_repositories.sh` script during manual installation.
348+
This dependency is automatically managed when using the devcontainer setup or when running the `install_repositories.sh` script during manual installation.
353349

354350
## Contributing
355351

requirements.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ numba~=0.59.0
1010
ijson~=3.3.0
1111
xxhash~=3.5.0
1212
pydantic~=2.9.1
13-
jq~=1.8.0
13+
jq~=1.8.0
14+
pyyaml~=6.0.2
15+
sqlalchemy~=2.0.35

scripts/install_repositories.sh

+1-12
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,4 @@ git checkout tags/v1.0.0 -b latest
1212
pip install -r requirements.txt
1313
pip install .
1414
cd ..
15-
rm -f -r janus/
16-
17-
# erebus - test harness
18-
cd /tmp/
19-
git clone https://github.com/xtuml/erebus.git
20-
cd erebus
21-
git fetch --all --tags
22-
git checkout tags/v0.2.1-beta -b latest
23-
pip install -r requirements.txt
24-
pip install .
25-
cd ..
26-
rm -f -r erebus/
15+
rm -f -r janus/

tel2puml/pv_event_simulator.py

+84-8
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,92 @@
22

33
from typing import Generator, Any, Optional
44
import random
5+
from uuid import uuid4
56

6-
from test_harness.protocol_verifier.simulator_data import ( # type: ignore[import-untyped] # noqa: E501
7-
Job,
8-
generate_single_events,
9-
)
107
from test_event_generator.io.run import puml_file_to_test_events # type: ignore[import-untyped] # noqa: E501
118
from tel2puml.tel2puml_types import DUMMY_START_EVENT, PVEvent, DUMMY_EVENT
129

1310

11+
class Job:
12+
"""A class to represent a job."""
13+
14+
def __init__(self) -> None:
15+
"""Initializes the job."""
16+
self.events: list[PVEvent] = []
17+
18+
def parse_input_job(self, jobfile: list[dict[str, Any]]) -> None:
19+
"""Parses the input job file.
20+
21+
:param jobfile: The job file to parse.
22+
:type jobfile: `list`[`dict`[`str`, `Any`]]
23+
"""
24+
if len(self.events) > 0:
25+
raise ValueError("The job already has events.")
26+
for event in jobfile:
27+
pv_event = transform_dict_into_pv_event(event)
28+
self.events.append(pv_event)
29+
30+
@staticmethod
31+
def sim_event(
32+
event: PVEvent,
33+
job_id: str,
34+
event_id_map: dict[str, str],
35+
) -> PVEvent:
36+
"""Simulates an event.
37+
38+
:param event: The event to simulate.
39+
:type event: :class:`PVEvent`
40+
:param job_id: The job id.
41+
:type job_id: `str`
42+
:param event_id_map: The event id map.
43+
:type event_id_map: `dict`[`str`, `str`]
44+
:return: The simulated event.
45+
:rtype: :class:`PVEvent`
46+
raises ValueError: If the some event ids are not in the event id map.
47+
"""
48+
previous_events: list[str] = []
49+
if "previousEventIds" in event:
50+
if isinstance(event["previousEventIds"], str):
51+
previous_events = [event["previousEventIds"]]
52+
else:
53+
previous_events = event["previousEventIds"]
54+
if not set([*previous_events, event["eventId"]]).issubset(
55+
event_id_map.keys()
56+
):
57+
raise ValueError(
58+
"The some event ids are not in the event id map."
59+
)
60+
sim_event = event.copy()
61+
sim_event["eventId"] = event_id_map[event["eventId"]]
62+
sim_event["jobId"] = job_id
63+
sim_event["previousEventIds"] = [
64+
event_id_map[previous_event_id]
65+
for previous_event_id in previous_events
66+
]
67+
return sim_event
68+
69+
def create_new_event_id_map(self) -> dict[str, str]:
70+
"""Creates a new event id map.
71+
72+
:return: The new event id map.
73+
:rtype: `dict`[`str`, `str`]
74+
"""
75+
return {event["eventId"]: str(uuid4()) for event in self.events}
76+
77+
def simulate_job(self) -> Generator[PVEvent, Any, None]:
78+
"""Simulates the job.
79+
80+
:return: A generator that yields the events of the job.
81+
:rtype: `Generator`[:class:`PVEvent`, `Any`, `None`]
82+
"""
83+
event_id_map: dict[str, str] = self.create_new_event_id_map()
84+
job_id = str(uuid4())
85+
for event in self.events:
86+
yield self.sim_event(
87+
event, job_id, event_id_map
88+
)
89+
90+
1491
def generate_test_data(
1592
input_puml_file: str,
1693
template_all_paths: bool = True,
@@ -222,9 +299,8 @@ def generate_event_jsons(
222299
:return: A generator that yields the event jsons.
223300
:rtype: `Generator`[`PVEvent`, `Any`, `None`]
224301
"""
225-
for generator_of_datums in generate_single_events(jobs):
226-
for datum in generator_of_datums:
227-
yield transform_dict_into_pv_event(datum.kwargs["list_dict"][0])
302+
for job in jobs:
303+
yield from job.simulate_job()
228304

229305

230306
def generate_valid_jobs_from_puml_file(
@@ -250,5 +326,5 @@ def generate_valid_jobs_from_puml_file(
250326
list(test_jobs_with_info.keys())[0]
251327
]["ValidSols"][0]:
252328
job = Job()
253-
job.parse_input_jobfile(test_job_event_list)
329+
job.parse_input_job(test_job_event_list)
254330
yield job

tests/tel2puml/test_pv_event_simulator.py

+119-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,127 @@
11
"""tests for module test_data_creation.py"""
2+
from typing import Any
3+
4+
import pytest
5+
from pytest import MonkeyPatch
6+
27
from tel2puml.pv_event_simulator import (
38
generate_valid_jobs_from_puml_file,
49
generate_event_jsons,
510
generate_test_data,
6-
generate_test_data_event_sequences_from_puml
11+
generate_test_data_event_sequences_from_puml,
12+
Job,
713
)
14+
from tel2puml.tel2puml_types import PVEvent
15+
16+
17+
class TestJob:
18+
"""Test class for Job"""
19+
def input_job(self) -> list[PVEvent]:
20+
"""Returns a list of PVEvent objects"""
21+
return [
22+
PVEvent(
23+
eventType="A",
24+
jobId="B",
25+
timestamp="2021-01-01T00:00:00",
26+
eventId=f"{i}",
27+
jobName="C",
28+
applicationName="D",
29+
previousEventIds=[] if i == 0 else [f"{i-1}"],
30+
)
31+
for i in range(2)
32+
]
33+
34+
def input_job_with_dict(self) -> list[dict[str, Any]]:
35+
"""Returns a list of dictionaries representing PVEvent objects"""
36+
return [
37+
{**event} for event in self.input_job()
38+
]
39+
40+
def test_init(self) -> None:
41+
"""tests for Job.__init__"""
42+
job = Job()
43+
assert job.events == []
44+
45+
def test_parse_input_job(self) -> None:
46+
"""tests for Job.parse_input_job_file"""
47+
job = Job()
48+
job.parse_input_job(self.input_job_with_dict())
49+
assert len(job.events) == 2
50+
assert job.events == self.input_job()
51+
52+
def test_sim_event(self) -> None:
53+
"""tests for Job.sim_event"""
54+
events = self.input_job()
55+
event = events[1]
56+
sim_event = Job.sim_event(event, "X", {"0": "map0", "1": "map1"})
57+
expected_event = PVEvent(
58+
eventType="A",
59+
jobId="X",
60+
timestamp="2021-01-01T00:00:00",
61+
eventId="map1",
62+
jobName="C",
63+
applicationName="D",
64+
previousEventIds=["map0"],
65+
)
66+
assert sim_event == expected_event
67+
# test case where event id map does not contain the event id
68+
with pytest.raises(ValueError):
69+
Job.sim_event(event, "X", {"0": "map0"})
70+
# test case where event id map does not contain the previous event id
71+
with pytest.raises(ValueError):
72+
Job.sim_event(event, "X", {"1": "map1"})
73+
# test positive case where the previous event is a string
74+
event["previousEventIds"] = "0"
75+
sim_event = Job.sim_event(event, "X", {"0": "map0", "1": "map1"})
76+
assert sim_event == expected_event
77+
78+
@staticmethod
79+
@pytest.fixture
80+
def patch_uuid4(monkeypatch: MonkeyPatch) -> None:
81+
"""fixture to patch uuid4"""
82+
import tel2puml.pv_event_simulator
83+
84+
to_pop_from = ["map0", "map1", "X"]
85+
monkeypatch.setattr(
86+
tel2puml.pv_event_simulator, "uuid4", lambda: to_pop_from.pop(0)
87+
)
88+
89+
@pytest.mark.usefixtures("patch_uuid4")
90+
def test_create_new_event_id_map(self) -> None:
91+
"""tests for Job.create_new_event_id_map"""
92+
job = Job()
93+
job.parse_input_job(self.input_job_with_dict())
94+
event_id_map = job.create_new_event_id_map()
95+
assert event_id_map == {"0": "map0", "1": "map1"}
96+
# test case where the job has no events
97+
job.events = []
98+
event_id_map = job.create_new_event_id_map()
99+
assert event_id_map == {}
100+
101+
@pytest.mark.usefixtures("patch_uuid4")
102+
def test_simulate_job(self) -> None:
103+
"""tests for Job.simulate_job"""
104+
job = Job()
105+
job.parse_input_job(self.input_job_with_dict())
106+
events = list(job.simulate_job())
107+
assert len(events) == 2
108+
for i, out_event, expected_event in zip(
109+
range(2), events, self.input_job()
110+
):
111+
assert (
112+
out_event["applicationName"]
113+
== expected_event["applicationName"]
114+
)
115+
assert out_event["eventType"] == expected_event["eventType"]
116+
assert out_event["jobId"] == "X"
117+
assert out_event["timestamp"] == expected_event["timestamp"]
118+
assert out_event["jobName"] == expected_event["jobName"]
119+
if i == 0:
120+
assert out_event["previousEventIds"] == []
121+
assert out_event["eventId"] == "map0"
122+
else:
123+
assert out_event["previousEventIds"] == ["map0"]
124+
assert out_event["eventId"] == "map1"
8125

9126

10127
def test_generate_valid_jobs_from_puml_file() -> None:
@@ -15,7 +132,7 @@ def test_generate_valid_jobs_from_puml_file() -> None:
15132
assert len(result) == 1
16133
job = result[0]
17134
assert len(job.events) == 6
18-
assert set([event.event_type for event in job.events]) == set(
135+
assert set([event["eventType"] for event in job.events]) == set(
19136
["A", "B", "C", "D", "E", "F"]
20137
)
21138

0 commit comments

Comments
 (0)