Skip to content

Commit f5d0d4c

Browse files
committed
check the initial working directory before the cache attempt
1 parent 1b56338 commit f5d0d4c

7 files changed

+10253
-136
lines changed

cwltool/command_line_tool.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,14 @@ def updatePathmap(self, outdir: str, pathmap: PathMapper, fn: CWLObjectType) ->
492492
for ls in cast(list[CWLObjectType], fn.get("listing", [])):
493493
self.updatePathmap(os.path.join(outdir, cast(str, fn["basename"])), pathmap, ls)
494494

495-
def _initialworkdir(self, j: JobBase, builder: Builder) -> None:
495+
def _initialworkdir(self, j: Optional[JobBase], builder: Builder) -> None:
496+
"""
497+
Test and initialize the working directory.
498+
499+
:param j: A :py:class:`~cwltool.job.CommandLineJob` or a
500+
specialized container-based job.
501+
If 'None', then only tests will be performed, no setup.
502+
"""
496503
initialWorkdir, _ = self.get_requirement("InitialWorkDirRequirement")
497504
if initialWorkdir is None:
498505
return
@@ -760,6 +767,9 @@ def _initialworkdir(self, j: JobBase, builder: Builder) -> None:
760767
"is in 'requirements'."
761768
)
762769

770+
if j is None:
771+
return # Only testing
772+
763773
with SourceLine(initialWorkdir, "listing", WorkflowException, debug):
764774
j.generatefiles["listing"] = ls
765775
for entry in ls:
@@ -824,6 +834,7 @@ def job(
824834
_check_adjust,
825835
)
826836
visit_class([cachebuilder.files, cachebuilder.bindings], ("File"), _checksum)
837+
self._initialworkdir(None, cachebuilder) # test the initial working directory
827838

828839
cmdline = flatten(list(map(cachebuilder.generate_arg, cachebuilder.bindings)))
829840
docker_req, _ = self.get_requirement("DockerRequirement")

tests/test_caching.py

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import re
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
from .util import get_data, get_main_output, needs_docker
7+
8+
test_factors = [(""), ("--parallel"), ("--debug"), ("--parallel --debug")]
9+
10+
11+
@needs_docker
12+
@pytest.mark.parametrize("factor", test_factors)
13+
def test_cid_file_non_existing_dir(tmp_path: Path, factor: str) -> None:
14+
"""Test that --cachedir with a bad path should produce a specific error."""
15+
test_file = "cache_test_workflow.cwl"
16+
bad_cidfile_dir = tmp_path / "cidfile-dir-badpath"
17+
commands = factor.split()
18+
commands.extend(
19+
[
20+
"--record-container-id",
21+
"--cidfile-dir",
22+
str(bad_cidfile_dir),
23+
get_data("tests/wf/" + test_file),
24+
]
25+
)
26+
error_code, _, stderr = get_main_output(commands)
27+
stderr = re.sub(r"\s\s+", " ", stderr)
28+
assert "directory doesn't exist, please create it first" in stderr, stderr
29+
assert error_code == 2 or error_code == 1, stderr
30+
31+
32+
@needs_docker
33+
@pytest.mark.parametrize("factor", test_factors)
34+
def test_wf_without_container(tmp_path: Path, factor: str) -> None:
35+
"""Confirm that we can run a workflow without a container."""
36+
test_file = "hello-workflow.cwl"
37+
cache_dir = str(tmp_path / "cwltool_cache")
38+
commands = factor.split()
39+
commands.extend(
40+
[
41+
"--cachedir",
42+
cache_dir,
43+
"--outdir",
44+
str(tmp_path / "outdir"),
45+
get_data("tests/wf/" + test_file),
46+
"--usermessage",
47+
"hello",
48+
]
49+
)
50+
error_code, _, stderr = get_main_output(commands)
51+
52+
stderr = re.sub(r"\s\s+", " ", stderr)
53+
assert "completed success" in stderr
54+
assert error_code == 0
55+
56+
57+
@needs_docker
58+
@pytest.mark.parametrize("factor", test_factors)
59+
def test_issue_740_fixed(tmp_path: Path, factor: str) -> None:
60+
"""Confirm that re-running a particular workflow with caching succeeds."""
61+
test_file = "cache_test_workflow.cwl"
62+
cache_dir = str(tmp_path / "cwltool_cache")
63+
commands = factor.split()
64+
commands.extend(["--cachedir", cache_dir, get_data("tests/wf/" + test_file)])
65+
error_code, _, stderr = get_main_output(commands)
66+
67+
stderr = re.sub(r"\s\s+", " ", stderr)
68+
assert "completed success" in stderr
69+
assert error_code == 0
70+
71+
commands = factor.split()
72+
commands.extend(["--cachedir", cache_dir, get_data("tests/wf/" + test_file)])
73+
error_code, _, stderr = get_main_output(commands)
74+
75+
stderr = re.sub(r"\s\s+", " ", stderr)
76+
assert "Output of job will be cached in" not in stderr
77+
assert error_code == 0, stderr
78+
79+
80+
@needs_docker
81+
@pytest.mark.parametrize("factor", test_factors)
82+
def test_cache_relative_paths(tmp_path: Path, factor: str) -> None:
83+
"""Confirm that re-running a particular workflow with caching succeeds."""
84+
test_file = "secondary-files.cwl"
85+
test_job_file = "secondary-files-job.yml"
86+
cache_dir = str(tmp_path / "cwltool_cache")
87+
commands = factor.split()
88+
commands.extend(
89+
[
90+
"--out",
91+
str(tmp_path / "out"),
92+
"--cachedir",
93+
cache_dir,
94+
get_data(f"tests/{test_file}"),
95+
get_data(f"tests/{test_job_file}"),
96+
]
97+
)
98+
error_code, _, stderr = get_main_output(commands)
99+
100+
stderr = re.sub(r"\s\s+", " ", stderr)
101+
assert "completed success" in stderr
102+
assert error_code == 0
103+
104+
commands = factor.split()
105+
commands.extend(
106+
[
107+
"--out",
108+
str(tmp_path / "out2"),
109+
"--cachedir",
110+
cache_dir,
111+
get_data(f"tests/{test_file}"),
112+
get_data(f"tests/{test_job_file}"),
113+
]
114+
)
115+
error_code, _, stderr = get_main_output(commands)
116+
117+
stderr = re.sub(r"\s\s+", " ", stderr)
118+
assert "Output of job will be cached in" not in stderr
119+
assert error_code == 0, stderr
120+
121+
assert (tmp_path / "cwltool_cache" / "27903451fc1ee10c148a0bdeb845b2cf").exists()
122+
123+
124+
@pytest.mark.parametrize("factor", test_factors)
125+
def test_cache_default_literal_file(tmp_path: Path, factor: str) -> None:
126+
"""Confirm that running a CLT with a default literal file with caching succeeds."""
127+
test_file = "tests/wf/extract_region_specs.cwl"
128+
cache_dir = str(tmp_path / "cwltool_cache")
129+
commands = factor.split()
130+
commands.extend(
131+
[
132+
"--out",
133+
str(tmp_path / "out"),
134+
"--cachedir",
135+
cache_dir,
136+
get_data(test_file),
137+
]
138+
)
139+
error_code, _, stderr = get_main_output(commands)
140+
141+
stderr = re.sub(r"\s\s+", " ", stderr)
142+
assert "completed success" in stderr
143+
assert error_code == 0
144+
145+
146+
@pytest.mark.parametrize("factor", test_factors)
147+
def test_cache_dockerreq_hint_instead_of_req(tmp_path: Path, factor: str) -> None:
148+
"""The cache must not be checked when there is an invalid use of an absolute path in iwdr.listing."""
149+
cache_dir = str(tmp_path / "cwltool_cache")
150+
test_job_file = "tests/wf/loadContents-input.yml"
151+
# First, run the iwd-container-entryname1 conformance tests with caching turned on
152+
test1_file = "tests/wf/iwd-container-entryname1.cwl"
153+
commands1 = factor.split()
154+
commands1.extend(
155+
[
156+
"--out",
157+
str(tmp_path / "out1"),
158+
"--cachedir",
159+
cache_dir,
160+
get_data(test1_file),
161+
get_data(test_job_file),
162+
]
163+
)
164+
error_code1, _, stderr1 = get_main_output(commands1)
165+
166+
stderr1 = re.sub(r"\s\s+", " ", stderr1)
167+
assert "completed success" in stderr1
168+
assert error_code1 == 0
169+
# Second, run the iwd-container-entryname3 test, which should fail
170+
# even though it would be a cache hit, except that its DockerRequirement is
171+
# in `hints` instead of `requirements` and one of the initial working directory
172+
# items has an absolute path starting with `/`.
173+
test2_file = "tests/wf/iwd-container-entryname3.cwl"
174+
commands2 = factor.split()
175+
commands2.extend(
176+
[
177+
"--out",
178+
str(tmp_path / "out2"),
179+
"--cachedir",
180+
cache_dir,
181+
get_data(test2_file),
182+
get_data(test_job_file),
183+
]
184+
)
185+
error_code2, _, stderr2 = get_main_output(commands2)
186+
187+
stderr2 = re.sub(r"\s\s+", " ", stderr2)
188+
assert (
189+
"at index 0 of listing is invalid, name can only start with '/' "
190+
"when DockerRequirement is in 'requirements" in stderr2
191+
)
192+
assert error_code2 == 1

tests/test_examples.py

-135
Original file line numberDiff line numberDiff line change
@@ -1115,27 +1115,6 @@ def test_cid_file_dir_arg_is_file_instead_of_dir(tmp_path: Path, factor: str) ->
11151115
assert error_code == 2 or error_code == 1, stderr
11161116

11171117

1118-
@needs_docker
1119-
@pytest.mark.parametrize("factor", test_factors)
1120-
def test_cid_file_non_existing_dir(tmp_path: Path, factor: str) -> None:
1121-
"""Test that --cachedir with a bad path should produce a specific error."""
1122-
test_file = "cache_test_workflow.cwl"
1123-
bad_cidfile_dir = tmp_path / "cidfile-dir-badpath"
1124-
commands = factor.split()
1125-
commands.extend(
1126-
[
1127-
"--record-container-id",
1128-
"--cidfile-dir",
1129-
str(bad_cidfile_dir),
1130-
get_data("tests/wf/" + test_file),
1131-
]
1132-
)
1133-
error_code, _, stderr = get_main_output(commands)
1134-
stderr = re.sub(r"\s\s+", " ", stderr)
1135-
assert "directory doesn't exist, please create it first" in stderr, stderr
1136-
assert error_code == 2 or error_code == 1, stderr
1137-
1138-
11391118
@needs_docker
11401119
@pytest.mark.parametrize("factor", test_factors)
11411120
def test_cid_file_w_prefix(tmp_path: Path, factor: str) -> None:
@@ -1233,120 +1212,6 @@ def test_secondary_files_v1_0(tmp_path: Path, factor: str) -> None:
12331212
assert error_code == 0
12341213

12351214

1236-
@needs_docker
1237-
@pytest.mark.parametrize("factor", test_factors)
1238-
def test_wf_without_container(tmp_path: Path, factor: str) -> None:
1239-
"""Confirm that we can run a workflow without a container."""
1240-
test_file = "hello-workflow.cwl"
1241-
cache_dir = str(tmp_path / "cwltool_cache")
1242-
commands = factor.split()
1243-
commands.extend(
1244-
[
1245-
"--cachedir",
1246-
cache_dir,
1247-
"--outdir",
1248-
str(tmp_path / "outdir"),
1249-
get_data("tests/wf/" + test_file),
1250-
"--usermessage",
1251-
"hello",
1252-
]
1253-
)
1254-
error_code, _, stderr = get_main_output(commands)
1255-
1256-
stderr = re.sub(r"\s\s+", " ", stderr)
1257-
assert "completed success" in stderr
1258-
assert error_code == 0
1259-
1260-
1261-
@needs_docker
1262-
@pytest.mark.parametrize("factor", test_factors)
1263-
def test_issue_740_fixed(tmp_path: Path, factor: str) -> None:
1264-
"""Confirm that re-running a particular workflow with caching succeeds."""
1265-
test_file = "cache_test_workflow.cwl"
1266-
cache_dir = str(tmp_path / "cwltool_cache")
1267-
commands = factor.split()
1268-
commands.extend(["--cachedir", cache_dir, get_data("tests/wf/" + test_file)])
1269-
error_code, _, stderr = get_main_output(commands)
1270-
1271-
stderr = re.sub(r"\s\s+", " ", stderr)
1272-
assert "completed success" in stderr
1273-
assert error_code == 0
1274-
1275-
commands = factor.split()
1276-
commands.extend(["--cachedir", cache_dir, get_data("tests/wf/" + test_file)])
1277-
error_code, _, stderr = get_main_output(commands)
1278-
1279-
stderr = re.sub(r"\s\s+", " ", stderr)
1280-
assert "Output of job will be cached in" not in stderr
1281-
assert error_code == 0, stderr
1282-
1283-
1284-
@needs_docker
1285-
@pytest.mark.parametrize("factor", test_factors)
1286-
def test_cache_relative_paths(tmp_path: Path, factor: str) -> None:
1287-
"""Confirm that re-running a particular workflow with caching succeeds."""
1288-
test_file = "secondary-files.cwl"
1289-
test_job_file = "secondary-files-job.yml"
1290-
cache_dir = str(tmp_path / "cwltool_cache")
1291-
commands = factor.split()
1292-
commands.extend(
1293-
[
1294-
"--out",
1295-
str(tmp_path / "out"),
1296-
"--cachedir",
1297-
cache_dir,
1298-
get_data(f"tests/{test_file}"),
1299-
get_data(f"tests/{test_job_file}"),
1300-
]
1301-
)
1302-
error_code, _, stderr = get_main_output(commands)
1303-
1304-
stderr = re.sub(r"\s\s+", " ", stderr)
1305-
assert "completed success" in stderr
1306-
assert error_code == 0
1307-
1308-
commands = factor.split()
1309-
commands.extend(
1310-
[
1311-
"--out",
1312-
str(tmp_path / "out2"),
1313-
"--cachedir",
1314-
cache_dir,
1315-
get_data(f"tests/{test_file}"),
1316-
get_data(f"tests/{test_job_file}"),
1317-
]
1318-
)
1319-
error_code, _, stderr = get_main_output(commands)
1320-
1321-
stderr = re.sub(r"\s\s+", " ", stderr)
1322-
assert "Output of job will be cached in" not in stderr
1323-
assert error_code == 0, stderr
1324-
1325-
assert (tmp_path / "cwltool_cache" / "27903451fc1ee10c148a0bdeb845b2cf").exists()
1326-
1327-
1328-
@pytest.mark.parametrize("factor", test_factors)
1329-
def test_cache_default_literal_file(tmp_path: Path, factor: str) -> None:
1330-
"""Confirm that running a CLT with a default literal file with caching succeeds."""
1331-
test_file = "tests/wf/extract_region_specs.cwl"
1332-
cache_dir = str(tmp_path / "cwltool_cache")
1333-
commands = factor.split()
1334-
commands.extend(
1335-
[
1336-
"--out",
1337-
str(tmp_path / "out"),
1338-
"--cachedir",
1339-
cache_dir,
1340-
get_data(test_file),
1341-
]
1342-
)
1343-
error_code, _, stderr = get_main_output(commands)
1344-
1345-
stderr = re.sub(r"\s\s+", " ", stderr)
1346-
assert "completed success" in stderr
1347-
assert error_code == 0
1348-
1349-
13501215
def test_write_summary(tmp_path: Path) -> None:
13511216
"""Test --write-summary."""
13521217
commands = [

0 commit comments

Comments
 (0)