toil 6.1.0a1__py3-none-any.whl → 7.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toil/__init__.py +1 -232
- toil/batchSystems/abstractBatchSystem.py +41 -17
- toil/batchSystems/abstractGridEngineBatchSystem.py +79 -65
- toil/batchSystems/awsBatch.py +8 -8
- toil/batchSystems/cleanup_support.py +7 -3
- toil/batchSystems/contained_executor.py +4 -5
- toil/batchSystems/gridengine.py +1 -1
- toil/batchSystems/htcondor.py +5 -5
- toil/batchSystems/kubernetes.py +25 -11
- toil/batchSystems/local_support.py +3 -3
- toil/batchSystems/lsf.py +9 -9
- toil/batchSystems/mesos/batchSystem.py +4 -4
- toil/batchSystems/mesos/executor.py +3 -2
- toil/batchSystems/options.py +9 -0
- toil/batchSystems/singleMachine.py +11 -10
- toil/batchSystems/slurm.py +129 -16
- toil/batchSystems/torque.py +1 -1
- toil/bus.py +45 -3
- toil/common.py +56 -31
- toil/cwl/cwltoil.py +442 -371
- toil/deferred.py +1 -1
- toil/exceptions.py +1 -1
- toil/fileStores/abstractFileStore.py +69 -20
- toil/fileStores/cachingFileStore.py +6 -22
- toil/fileStores/nonCachingFileStore.py +6 -15
- toil/job.py +270 -86
- toil/jobStores/abstractJobStore.py +37 -31
- toil/jobStores/aws/jobStore.py +280 -218
- toil/jobStores/aws/utils.py +60 -31
- toil/jobStores/conftest.py +2 -2
- toil/jobStores/fileJobStore.py +3 -3
- toil/jobStores/googleJobStore.py +3 -4
- toil/leader.py +89 -38
- toil/lib/aws/__init__.py +26 -10
- toil/lib/aws/iam.py +2 -2
- toil/lib/aws/session.py +62 -22
- toil/lib/aws/utils.py +73 -37
- toil/lib/conversions.py +24 -1
- toil/lib/ec2.py +118 -69
- toil/lib/expando.py +1 -1
- toil/lib/generatedEC2Lists.py +8 -8
- toil/lib/io.py +42 -4
- toil/lib/misc.py +1 -3
- toil/lib/resources.py +57 -16
- toil/lib/retry.py +12 -5
- toil/lib/threading.py +29 -14
- toil/lib/throttle.py +1 -1
- toil/options/common.py +31 -30
- toil/options/wdl.py +5 -0
- toil/provisioners/__init__.py +9 -3
- toil/provisioners/abstractProvisioner.py +12 -2
- toil/provisioners/aws/__init__.py +20 -15
- toil/provisioners/aws/awsProvisioner.py +406 -329
- toil/provisioners/gceProvisioner.py +2 -2
- toil/provisioners/node.py +13 -5
- toil/server/app.py +1 -1
- toil/statsAndLogging.py +93 -23
- toil/test/__init__.py +27 -12
- toil/test/batchSystems/batchSystemTest.py +40 -33
- toil/test/batchSystems/batch_system_plugin_test.py +79 -0
- toil/test/batchSystems/test_slurm.py +22 -7
- toil/test/cactus/__init__.py +0 -0
- toil/test/cactus/test_cactus_integration.py +58 -0
- toil/test/cwl/cwlTest.py +245 -236
- toil/test/cwl/seqtk_seq.cwl +1 -1
- toil/test/docs/scriptsTest.py +11 -14
- toil/test/jobStores/jobStoreTest.py +40 -54
- toil/test/lib/aws/test_iam.py +2 -2
- toil/test/lib/test_ec2.py +1 -1
- toil/test/options/__init__.py +13 -0
- toil/test/options/options.py +37 -0
- toil/test/provisioners/aws/awsProvisionerTest.py +51 -34
- toil/test/provisioners/clusterTest.py +99 -16
- toil/test/server/serverTest.py +2 -2
- toil/test/src/autoDeploymentTest.py +1 -1
- toil/test/src/dockerCheckTest.py +2 -1
- toil/test/src/environmentTest.py +125 -0
- toil/test/src/fileStoreTest.py +1 -1
- toil/test/src/jobDescriptionTest.py +18 -8
- toil/test/src/jobTest.py +1 -1
- toil/test/src/realtimeLoggerTest.py +4 -0
- toil/test/src/workerTest.py +52 -19
- toil/test/utils/toilDebugTest.py +62 -4
- toil/test/utils/utilsTest.py +23 -21
- toil/test/wdl/wdltoil_test.py +49 -21
- toil/test/wdl/wdltoil_test_kubernetes.py +77 -0
- toil/toilState.py +68 -9
- toil/utils/toilDebugFile.py +1 -1
- toil/utils/toilDebugJob.py +153 -26
- toil/utils/toilLaunchCluster.py +12 -2
- toil/utils/toilRsyncCluster.py +7 -2
- toil/utils/toilSshCluster.py +7 -3
- toil/utils/toilStats.py +310 -266
- toil/utils/toilStatus.py +98 -52
- toil/version.py +11 -11
- toil/wdl/wdltoil.py +644 -225
- toil/worker.py +125 -83
- {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/LICENSE +25 -0
- toil-7.0.0.dist-info/METADATA +158 -0
- {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/RECORD +103 -96
- {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/WHEEL +1 -1
- toil-6.1.0a1.dist-info/METADATA +0 -125
- {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/entry_points.txt +0 -0
- {toil-6.1.0a1.dist-info → toil-7.0.0.dist-info}/top_level.txt +0 -0
toil/test/cwl/cwlTest.py
CHANGED
|
@@ -23,13 +23,22 @@ import sys
|
|
|
23
23
|
import unittest
|
|
24
24
|
import uuid
|
|
25
25
|
import zipfile
|
|
26
|
+
|
|
26
27
|
from functools import partial
|
|
27
28
|
from io import StringIO
|
|
28
29
|
from pathlib import Path
|
|
29
|
-
from typing import
|
|
30
|
+
from typing import (TYPE_CHECKING,
|
|
31
|
+
Callable,
|
|
32
|
+
Dict,
|
|
33
|
+
List,
|
|
34
|
+
Optional,
|
|
35
|
+
cast)
|
|
30
36
|
from unittest.mock import Mock, call
|
|
31
37
|
from urllib.request import urlretrieve
|
|
32
38
|
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from cwltool.utils import CWLObjectType
|
|
41
|
+
|
|
33
42
|
import pytest
|
|
34
43
|
|
|
35
44
|
pkg_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) # noqa
|
|
@@ -37,10 +46,10 @@ sys.path.insert(0, pkg_root) # noqa
|
|
|
37
46
|
|
|
38
47
|
from schema_salad.exceptions import ValidationException
|
|
39
48
|
|
|
40
|
-
from toil.cwl.utils import (
|
|
49
|
+
from toil.cwl.utils import (DirectoryStructure,
|
|
50
|
+
download_structure,
|
|
41
51
|
visit_cwl_class_and_reduce,
|
|
42
52
|
visit_top_cwl_class)
|
|
43
|
-
from toil.exceptions import FailedJobsException
|
|
44
53
|
from toil.fileStores import FileID
|
|
45
54
|
from toil.fileStores.abstractFileStore import AbstractFileStore
|
|
46
55
|
from toil.lib.threading import cpu_count
|
|
@@ -63,7 +72,6 @@ from toil.test import (ToilTest,
|
|
|
63
72
|
needs_torque,
|
|
64
73
|
needs_wes_server,
|
|
65
74
|
slow)
|
|
66
|
-
from toil.test.provisioners.clusterTest import AbstractClusterTest
|
|
67
75
|
|
|
68
76
|
log = logging.getLogger(__name__)
|
|
69
77
|
CONFORMANCE_TEST_TIMEOUT = 10000
|
|
@@ -74,14 +82,14 @@ def run_conformance_tests(
|
|
|
74
82
|
yml: str,
|
|
75
83
|
runner: Optional[str] = None,
|
|
76
84
|
caching: bool = False,
|
|
77
|
-
batchSystem: str = None,
|
|
78
|
-
selected_tests: str = None,
|
|
79
|
-
selected_tags: str = None,
|
|
80
|
-
skipped_tests: str = None,
|
|
85
|
+
batchSystem: Optional[str] = None,
|
|
86
|
+
selected_tests: Optional[str] = None,
|
|
87
|
+
selected_tags: Optional[str] = None,
|
|
88
|
+
skipped_tests: Optional[str] = None,
|
|
81
89
|
extra_args: Optional[List[str]] = None,
|
|
82
90
|
must_support_all_features: bool = False,
|
|
83
91
|
junit_file: Optional[str] = None,
|
|
84
|
-
):
|
|
92
|
+
) -> None:
|
|
85
93
|
"""
|
|
86
94
|
Run the CWL conformance tests.
|
|
87
95
|
|
|
@@ -199,6 +207,8 @@ def run_conformance_tests(
|
|
|
199
207
|
raise e
|
|
200
208
|
|
|
201
209
|
|
|
210
|
+
TesterFuncType = Callable[[str, str, "CWLObjectType"], None]
|
|
211
|
+
|
|
202
212
|
@needs_cwl
|
|
203
213
|
class CWLWorkflowTest(ToilTest):
|
|
204
214
|
"""
|
|
@@ -207,19 +217,19 @@ class CWLWorkflowTest(ToilTest):
|
|
|
207
217
|
inputs.
|
|
208
218
|
"""
|
|
209
219
|
|
|
210
|
-
def setUp(self):
|
|
220
|
+
def setUp(self) -> None:
|
|
211
221
|
"""Runs anew before each test to create farm fresh temp dirs."""
|
|
212
222
|
self.outDir = f"/tmp/toil-cwl-test-{str(uuid.uuid4())}"
|
|
213
223
|
os.makedirs(self.outDir)
|
|
214
224
|
self.rootDir = self._projectRootPath()
|
|
215
225
|
|
|
216
|
-
def tearDown(self):
|
|
226
|
+
def tearDown(self) -> None:
|
|
217
227
|
"""Clean up outputs."""
|
|
218
228
|
if os.path.exists(self.outDir):
|
|
219
229
|
shutil.rmtree(self.outDir)
|
|
220
230
|
unittest.TestCase.tearDown(self)
|
|
221
231
|
|
|
222
|
-
def test_cwl_cmdline_input(self):
|
|
232
|
+
def test_cwl_cmdline_input(self) -> None:
|
|
223
233
|
"""
|
|
224
234
|
Test that running a CWL workflow with inputs specified on the command line passes.
|
|
225
235
|
"""
|
|
@@ -230,7 +240,15 @@ class CWLWorkflowTest(ToilTest):
|
|
|
230
240
|
# If the workflow runs, it must have had options
|
|
231
241
|
cwltoil.main(args, stdout=st)
|
|
232
242
|
|
|
233
|
-
def _tester(
|
|
243
|
+
def _tester(
|
|
244
|
+
self,
|
|
245
|
+
cwlfile: str,
|
|
246
|
+
jobfile: str,
|
|
247
|
+
expect: "CWLObjectType",
|
|
248
|
+
main_args: List[str] = [],
|
|
249
|
+
out_name: str = "output",
|
|
250
|
+
output_here: bool = False,
|
|
251
|
+
) -> None:
|
|
234
252
|
from toil.cwl import cwltoil
|
|
235
253
|
|
|
236
254
|
st = StringIO()
|
|
@@ -264,7 +282,9 @@ class CWLWorkflowTest(ToilTest):
|
|
|
264
282
|
self.assertTrue(os.path.exists(v["path"]))
|
|
265
283
|
self.assertFalse(os.stat(v["path"]).st_mode & stat.S_IXUSR)
|
|
266
284
|
|
|
267
|
-
def _debug_worker_tester(
|
|
285
|
+
def _debug_worker_tester(
|
|
286
|
+
self, cwlfile: str, jobfile: str, expect: "CWLObjectType"
|
|
287
|
+
) -> None:
|
|
268
288
|
from toil.cwl import cwltoil
|
|
269
289
|
|
|
270
290
|
st = StringIO()
|
|
@@ -284,21 +304,21 @@ class CWLWorkflowTest(ToilTest):
|
|
|
284
304
|
out["output"].pop("nameroot", None)
|
|
285
305
|
self.assertEqual(out, expect)
|
|
286
306
|
|
|
287
|
-
def revsort(self, cwl_filename, tester_fn):
|
|
307
|
+
def revsort(self, cwl_filename: str, tester_fn: TesterFuncType) -> None:
|
|
288
308
|
tester_fn(
|
|
289
309
|
"src/toil/test/cwl/" + cwl_filename,
|
|
290
310
|
"src/toil/test/cwl/revsort-job.json",
|
|
291
311
|
self._expected_revsort_output(self.outDir),
|
|
292
312
|
)
|
|
293
313
|
|
|
294
|
-
def revsort_no_checksum(self, cwl_filename, tester_fn):
|
|
314
|
+
def revsort_no_checksum(self, cwl_filename: str, tester_fn: TesterFuncType) -> None:
|
|
295
315
|
tester_fn(
|
|
296
316
|
"src/toil/test/cwl/" + cwl_filename,
|
|
297
317
|
"src/toil/test/cwl/revsort-job.json",
|
|
298
318
|
self._expected_revsort_nochecksum_output(self.outDir),
|
|
299
319
|
)
|
|
300
320
|
|
|
301
|
-
def download(self, inputs, tester_fn):
|
|
321
|
+
def download(self, inputs: str, tester_fn: TesterFuncType) -> None:
|
|
302
322
|
input_location = os.path.join("src/toil/test/cwl", inputs)
|
|
303
323
|
tester_fn(
|
|
304
324
|
"src/toil/test/cwl/download.cwl",
|
|
@@ -306,7 +326,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
306
326
|
self._expected_download_output(self.outDir),
|
|
307
327
|
)
|
|
308
328
|
|
|
309
|
-
def load_contents(self, inputs, tester_fn):
|
|
329
|
+
def load_contents(self, inputs: str, tester_fn: TesterFuncType) -> None:
|
|
310
330
|
input_location = os.path.join("src/toil/test/cwl", inputs)
|
|
311
331
|
tester_fn(
|
|
312
332
|
"src/toil/test/cwl/load_contents.cwl",
|
|
@@ -314,7 +334,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
314
334
|
self._expected_load_contents_output(self.outDir),
|
|
315
335
|
)
|
|
316
336
|
|
|
317
|
-
def download_directory(self, inputs, tester_fn):
|
|
337
|
+
def download_directory(self, inputs: str, tester_fn: TesterFuncType) -> None:
|
|
318
338
|
input_location = os.path.join("src/toil/test/cwl", inputs)
|
|
319
339
|
tester_fn(
|
|
320
340
|
"src/toil/test/cwl/download_directory.cwl",
|
|
@@ -322,7 +342,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
322
342
|
self._expected_download_output(self.outDir),
|
|
323
343
|
)
|
|
324
344
|
|
|
325
|
-
def download_subdirectory(self, inputs, tester_fn):
|
|
345
|
+
def download_subdirectory(self, inputs: str, tester_fn: TesterFuncType) -> None:
|
|
326
346
|
input_location = os.path.join("src/toil/test/cwl", inputs)
|
|
327
347
|
tester_fn(
|
|
328
348
|
"src/toil/test/cwl/download_subdirectory.cwl",
|
|
@@ -330,7 +350,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
330
350
|
self._expected_download_output(self.outDir),
|
|
331
351
|
)
|
|
332
352
|
|
|
333
|
-
def test_mpi(self):
|
|
353
|
+
def test_mpi(self) -> None:
|
|
334
354
|
from toil.cwl import cwltoil
|
|
335
355
|
|
|
336
356
|
stdout = StringIO()
|
|
@@ -355,7 +375,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
355
375
|
self.assertTrue(isinstance(two_pids[1], int))
|
|
356
376
|
|
|
357
377
|
@needs_aws_s3
|
|
358
|
-
def test_s3_as_secondary_file(self):
|
|
378
|
+
def test_s3_as_secondary_file(self) -> None:
|
|
359
379
|
from toil.cwl import cwltoil
|
|
360
380
|
|
|
361
381
|
stdout = StringIO()
|
|
@@ -374,21 +394,21 @@ class CWLWorkflowTest(ToilTest):
|
|
|
374
394
|
with open(out["output"]["location"][len("file://") :]) as f:
|
|
375
395
|
self.assertEqual(f.read().strip(), "When is s4 coming out?")
|
|
376
396
|
|
|
377
|
-
def test_run_revsort(self):
|
|
397
|
+
def test_run_revsort(self) -> None:
|
|
378
398
|
self.revsort("revsort.cwl", self._tester)
|
|
379
399
|
|
|
380
|
-
def test_run_revsort_nochecksum(self):
|
|
400
|
+
def test_run_revsort_nochecksum(self) -> None:
|
|
381
401
|
self.revsort_no_checksum(
|
|
382
402
|
"revsort.cwl", partial(self._tester, main_args=["--no-compute-checksum"])
|
|
383
403
|
)
|
|
384
404
|
|
|
385
|
-
def test_run_revsort2(self):
|
|
405
|
+
def test_run_revsort2(self) -> None:
|
|
386
406
|
self.revsort("revsort2.cwl", self._tester)
|
|
387
407
|
|
|
388
|
-
def test_run_revsort_debug_worker(self):
|
|
408
|
+
def test_run_revsort_debug_worker(self) -> None:
|
|
389
409
|
self.revsort("revsort.cwl", self._debug_worker_tester)
|
|
390
410
|
|
|
391
|
-
def test_run_colon_output(self):
|
|
411
|
+
def test_run_colon_output(self) -> None:
|
|
392
412
|
self._tester(
|
|
393
413
|
"src/toil/test/cwl/colon_test_output.cwl",
|
|
394
414
|
"src/toil/test/cwl/colon_test_output_job.yaml",
|
|
@@ -396,7 +416,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
396
416
|
out_name="result",
|
|
397
417
|
)
|
|
398
418
|
|
|
399
|
-
def test_glob_dir_bypass_file_store(self):
|
|
419
|
+
def test_glob_dir_bypass_file_store(self) -> None:
|
|
400
420
|
self.maxDiff = 1000
|
|
401
421
|
try:
|
|
402
422
|
# We need to output to the current directory to make sure that
|
|
@@ -416,58 +436,58 @@ class CWLWorkflowTest(ToilTest):
|
|
|
416
436
|
pass
|
|
417
437
|
|
|
418
438
|
@needs_aws_s3
|
|
419
|
-
def test_download_s3(self):
|
|
439
|
+
def test_download_s3(self) -> None:
|
|
420
440
|
self.download("download_s3.json", self._tester)
|
|
421
441
|
|
|
422
|
-
def test_download_http(self):
|
|
442
|
+
def test_download_http(self) -> None:
|
|
423
443
|
self.download("download_http.json", self._tester)
|
|
424
444
|
|
|
425
|
-
def test_download_https(self):
|
|
445
|
+
def test_download_https(self) -> None:
|
|
426
446
|
self.download("download_https.json", self._tester)
|
|
427
447
|
|
|
428
|
-
def test_download_https_reference(self):
|
|
448
|
+
def test_download_https_reference(self) -> None:
|
|
429
449
|
self.download("download_https.json", partial(self._tester, main_args=["--reference-inputs"]))
|
|
430
450
|
|
|
431
|
-
def test_download_file(self):
|
|
451
|
+
def test_download_file(self) -> None:
|
|
432
452
|
self.download("download_file.json", self._tester)
|
|
433
453
|
|
|
434
454
|
@needs_aws_s3
|
|
435
|
-
def test_download_directory_s3(self):
|
|
455
|
+
def test_download_directory_s3(self) -> None:
|
|
436
456
|
self.download_directory("download_directory_s3.json", self._tester)
|
|
437
457
|
|
|
438
458
|
@needs_aws_s3
|
|
439
|
-
def test_download_directory_s3_reference(self):
|
|
459
|
+
def test_download_directory_s3_reference(self) -> None:
|
|
440
460
|
self.download_directory("download_directory_s3.json", partial(self._tester, main_args=["--reference-inputs"]))
|
|
441
461
|
|
|
442
|
-
def test_download_directory_file(self):
|
|
462
|
+
def test_download_directory_file(self) -> None:
|
|
443
463
|
self.download_directory("download_directory_file.json", self._tester)
|
|
444
464
|
|
|
445
465
|
@needs_aws_s3
|
|
446
|
-
def test_download_subdirectory_s3(self):
|
|
466
|
+
def test_download_subdirectory_s3(self) -> None:
|
|
447
467
|
self.download_subdirectory("download_subdirectory_s3.json", self._tester)
|
|
448
468
|
|
|
449
|
-
def test_download_subdirectory_file(self):
|
|
469
|
+
def test_download_subdirectory_file(self) -> None:
|
|
450
470
|
self.download_subdirectory("download_subdirectory_file.json", self._tester)
|
|
451
471
|
|
|
452
472
|
# We also want to make sure we can run a bare tool with loadContents on the inputs, which requires accessing the input data early in the leader.
|
|
453
473
|
|
|
454
474
|
@needs_aws_s3
|
|
455
|
-
def test_load_contents_s3(self):
|
|
475
|
+
def test_load_contents_s3(self) -> None:
|
|
456
476
|
self.load_contents("download_s3.json", self._tester)
|
|
457
477
|
|
|
458
|
-
def test_load_contents_http(self):
|
|
478
|
+
def test_load_contents_http(self) -> None:
|
|
459
479
|
self.load_contents("download_http.json", self._tester)
|
|
460
480
|
|
|
461
|
-
def test_load_contents_https(self):
|
|
481
|
+
def test_load_contents_https(self) -> None:
|
|
462
482
|
self.load_contents("download_https.json", self._tester)
|
|
463
483
|
|
|
464
|
-
def test_load_contents_file(self):
|
|
484
|
+
def test_load_contents_file(self) -> None:
|
|
465
485
|
self.load_contents("download_file.json", self._tester)
|
|
466
486
|
|
|
467
487
|
@slow
|
|
468
488
|
@pytest.mark.integrative
|
|
469
|
-
@unittest.skip
|
|
470
|
-
def test_bioconda(self):
|
|
489
|
+
@unittest.skip("Fails too often due to remote service")
|
|
490
|
+
def test_bioconda(self) -> None:
|
|
471
491
|
self._tester(
|
|
472
492
|
"src/toil/test/cwl/seqtk_seq.cwl",
|
|
473
493
|
"src/toil/test/cwl/seqtk_seq_job.json",
|
|
@@ -476,10 +496,20 @@ class CWLWorkflowTest(ToilTest):
|
|
|
476
496
|
out_name="output1",
|
|
477
497
|
)
|
|
478
498
|
|
|
499
|
+
@needs_docker
|
|
500
|
+
def test_default_args(self) -> None:
|
|
501
|
+
self._tester(
|
|
502
|
+
"src/toil/test/cwl/seqtk_seq.cwl",
|
|
503
|
+
"src/toil/test/cwl/seqtk_seq_job.json",
|
|
504
|
+
self._expected_seqtk_output(self.outDir),
|
|
505
|
+
main_args=["--default-container", "quay.io/biocontainers/seqtk:1.4--he4a0461_1"],
|
|
506
|
+
out_name="output1",
|
|
507
|
+
)
|
|
508
|
+
|
|
479
509
|
@needs_docker
|
|
480
510
|
@pytest.mark.integrative
|
|
481
|
-
@unittest.skip
|
|
482
|
-
def test_biocontainers(self):
|
|
511
|
+
@unittest.skip("Fails too often due to remote service")
|
|
512
|
+
def test_biocontainers(self) -> None:
|
|
483
513
|
self._tester(
|
|
484
514
|
"src/toil/test/cwl/seqtk_seq.cwl",
|
|
485
515
|
"src/toil/test/cwl/seqtk_seq_job.json",
|
|
@@ -491,7 +521,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
491
521
|
@needs_docker
|
|
492
522
|
@needs_docker_cuda
|
|
493
523
|
@needs_local_cuda
|
|
494
|
-
def test_cuda(self):
|
|
524
|
+
def test_cuda(self) -> None:
|
|
495
525
|
self._tester(
|
|
496
526
|
"src/toil/test/cwl/nvidia_smi.cwl",
|
|
497
527
|
"src/toil/test/cwl/empty.json",
|
|
@@ -500,14 +530,13 @@ class CWLWorkflowTest(ToilTest):
|
|
|
500
530
|
)
|
|
501
531
|
|
|
502
532
|
@slow
|
|
503
|
-
def test_restart(self):
|
|
533
|
+
def test_restart(self) -> None:
|
|
504
534
|
"""
|
|
505
535
|
Enable restarts with toil-cwl-runner -- run failing test, re-run correct test.
|
|
506
536
|
Only implemented for single machine.
|
|
507
537
|
"""
|
|
508
538
|
log.info("Running CWL Test Restart. Expecting failure, then success.")
|
|
509
539
|
from toil.cwl import cwltoil
|
|
510
|
-
from toil.jobStores.abstractJobStore import NoSuchJobStoreException
|
|
511
540
|
|
|
512
541
|
outDir = self._createTempDir()
|
|
513
542
|
cwlDir = os.path.join(self._projectRootPath(), "src", "toil", "test", "cwl")
|
|
@@ -529,7 +558,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
529
558
|
][-1]
|
|
530
559
|
os.symlink(os.path.join(cal_path, "date"), f'{os.path.join(outDir, "rev")}')
|
|
531
560
|
|
|
532
|
-
def path_with_bogus_rev():
|
|
561
|
+
def path_with_bogus_rev() -> str:
|
|
533
562
|
# append to the front of the PATH so that we check there first
|
|
534
563
|
return f"{outDir}:" + os.environ["PATH"]
|
|
535
564
|
|
|
@@ -537,22 +566,23 @@ class CWLWorkflowTest(ToilTest):
|
|
|
537
566
|
# Force a failure by trying to use an incorrect version of `rev` from the PATH
|
|
538
567
|
os.environ["PATH"] = path_with_bogus_rev()
|
|
539
568
|
try:
|
|
540
|
-
|
|
569
|
+
subprocess.check_output(["toil-cwl-runner"] + cmd, env=os.environ.copy(), stderr=subprocess.STDOUT)
|
|
541
570
|
self.fail("Expected problem job with incorrect PATH did not fail")
|
|
542
|
-
except
|
|
571
|
+
except subprocess.CalledProcessError:
|
|
543
572
|
pass
|
|
544
573
|
# Finish the job with a correct PATH
|
|
545
574
|
os.environ["PATH"] = orig_path
|
|
546
|
-
|
|
575
|
+
cmd.insert(0, "--restart")
|
|
576
|
+
cwltoil.main(cmd)
|
|
547
577
|
# Should fail because previous job completed successfully
|
|
548
578
|
try:
|
|
549
|
-
|
|
579
|
+
subprocess.check_output(["toil-cwl-runner"] + cmd, env=os.environ.copy(), stderr=subprocess.STDOUT)
|
|
550
580
|
self.fail("Restart with missing directory did not fail")
|
|
551
|
-
except
|
|
581
|
+
except subprocess.CalledProcessError:
|
|
552
582
|
pass
|
|
553
583
|
|
|
554
584
|
@needs_aws_s3
|
|
555
|
-
def test_streamable(self, extra_args: List[str] = None):
|
|
585
|
+
def test_streamable(self, extra_args: Optional[List[str]] = None) -> None:
|
|
556
586
|
"""
|
|
557
587
|
Test that a file with 'streamable'=True is a named pipe.
|
|
558
588
|
This is a CWL1.2 feature.
|
|
@@ -585,13 +615,13 @@ class CWLWorkflowTest(ToilTest):
|
|
|
585
615
|
self.assertEqual(f.read().strip(), "When is s4 coming out?")
|
|
586
616
|
|
|
587
617
|
@needs_aws_s3
|
|
588
|
-
def test_streamable_reference(self):
|
|
618
|
+
def test_streamable_reference(self) -> None:
|
|
589
619
|
"""
|
|
590
620
|
Test that a streamable file is a stream even when passed around by URI.
|
|
591
621
|
"""
|
|
592
622
|
self.test_streamable(extra_args=["--reference-inputs"])
|
|
593
623
|
|
|
594
|
-
def test_preemptible(self):
|
|
624
|
+
def test_preemptible(self) -> None:
|
|
595
625
|
"""
|
|
596
626
|
Tests that the http://arvados.org/cwl#UsePreemptible extension is supported.
|
|
597
627
|
"""
|
|
@@ -615,7 +645,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
615
645
|
with open(out[out_name]["location"][len("file://") :]) as f:
|
|
616
646
|
self.assertEqual(f.read().strip(), "hello")
|
|
617
647
|
|
|
618
|
-
def test_preemptible_expression(self):
|
|
648
|
+
def test_preemptible_expression(self) -> None:
|
|
619
649
|
"""
|
|
620
650
|
Tests that the http://arvados.org/cwl#UsePreemptible extension is validated.
|
|
621
651
|
"""
|
|
@@ -639,7 +669,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
639
669
|
|
|
640
670
|
|
|
641
671
|
@staticmethod
|
|
642
|
-
def _expected_seqtk_output(outDir):
|
|
672
|
+
def _expected_seqtk_output(outDir: str) -> "CWLObjectType":
|
|
643
673
|
path = os.path.join(outDir, "out")
|
|
644
674
|
loc = "file://" + path
|
|
645
675
|
return {
|
|
@@ -654,7 +684,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
654
684
|
}
|
|
655
685
|
|
|
656
686
|
@staticmethod
|
|
657
|
-
def _expected_revsort_output(outDir):
|
|
687
|
+
def _expected_revsort_output(outDir: str) -> "CWLObjectType":
|
|
658
688
|
path = os.path.join(outDir, "output.txt")
|
|
659
689
|
loc = "file://" + path
|
|
660
690
|
return {
|
|
@@ -669,7 +699,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
669
699
|
}
|
|
670
700
|
|
|
671
701
|
@staticmethod
|
|
672
|
-
def _expected_revsort_nochecksum_output(outDir):
|
|
702
|
+
def _expected_revsort_nochecksum_output(outDir: str) -> "CWLObjectType":
|
|
673
703
|
path = os.path.join(outDir, "output.txt")
|
|
674
704
|
loc = "file://" + path
|
|
675
705
|
return {
|
|
@@ -683,7 +713,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
683
713
|
}
|
|
684
714
|
|
|
685
715
|
@staticmethod
|
|
686
|
-
def _expected_download_output(outDir):
|
|
716
|
+
def _expected_download_output(outDir: str) -> "CWLObjectType":
|
|
687
717
|
path = os.path.join(outDir, "output.txt")
|
|
688
718
|
loc = "file://" + path
|
|
689
719
|
return {
|
|
@@ -698,7 +728,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
698
728
|
}
|
|
699
729
|
|
|
700
730
|
@staticmethod
|
|
701
|
-
def _expected_glob_dir_output(out_dir):
|
|
731
|
+
def _expected_glob_dir_output(out_dir: str) -> "CWLObjectType":
|
|
702
732
|
dir_path = os.path.join(out_dir, "shouldmake")
|
|
703
733
|
dir_loc = "file://" + dir_path
|
|
704
734
|
file_path = os.path.join(dir_path, "test.txt")
|
|
@@ -727,7 +757,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
727
757
|
}
|
|
728
758
|
|
|
729
759
|
@classmethod
|
|
730
|
-
def _expected_load_contents_output(cls, out_dir):
|
|
760
|
+
def _expected_load_contents_output(cls, out_dir: str) -> "CWLObjectType":
|
|
731
761
|
"""
|
|
732
762
|
Generate the putput we expect from load_contents.cwl, when sending
|
|
733
763
|
output files to the given directory.
|
|
@@ -737,7 +767,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
737
767
|
return expected
|
|
738
768
|
|
|
739
769
|
@staticmethod
|
|
740
|
-
def _expected_colon_output(outDir):
|
|
770
|
+
def _expected_colon_output(outDir: str) -> "CWLObjectType":
|
|
741
771
|
path = os.path.join(outDir, "A:Gln2Cys_result")
|
|
742
772
|
loc = "file://" + os.path.join(outDir, "A%3AGln2Cys_result")
|
|
743
773
|
return {
|
|
@@ -761,7 +791,7 @@ class CWLWorkflowTest(ToilTest):
|
|
|
761
791
|
}
|
|
762
792
|
}
|
|
763
793
|
|
|
764
|
-
def _expected_streaming_output(self, outDir):
|
|
794
|
+
def _expected_streaming_output(self, outDir: str) -> "CWLObjectType":
|
|
765
795
|
path = os.path.join(outDir, "output.txt")
|
|
766
796
|
loc = "file://" + path
|
|
767
797
|
return {
|
|
@@ -783,7 +813,7 @@ class CWLv10Test(ToilTest):
|
|
|
783
813
|
Run the CWL 1.0 conformance tests in various environments.
|
|
784
814
|
"""
|
|
785
815
|
|
|
786
|
-
def setUp(self):
|
|
816
|
+
def setUp(self) -> None:
|
|
787
817
|
"""Runs anew before each test to create farm fresh temp dirs."""
|
|
788
818
|
self.outDir = f"/tmp/toil-cwl-test-{str(uuid.uuid4())}"
|
|
789
819
|
os.makedirs(self.outDir)
|
|
@@ -804,7 +834,7 @@ class CWLv10Test(ToilTest):
|
|
|
804
834
|
shutil.move("common-workflow-language-%s" % testhash, self.cwlSpec)
|
|
805
835
|
os.remove("spec.zip")
|
|
806
836
|
|
|
807
|
-
def tearDown(self):
|
|
837
|
+
def tearDown(self) -> None:
|
|
808
838
|
"""Clean up outputs."""
|
|
809
839
|
if os.path.exists(self.outDir):
|
|
810
840
|
shutil.rmtree(self.outDir)
|
|
@@ -812,99 +842,106 @@ class CWLv10Test(ToilTest):
|
|
|
812
842
|
|
|
813
843
|
@slow
|
|
814
844
|
@pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
|
|
815
|
-
def test_run_conformance_with_caching(self):
|
|
845
|
+
def test_run_conformance_with_caching(self) -> None:
|
|
816
846
|
self.test_run_conformance(caching=True)
|
|
817
847
|
|
|
818
848
|
@slow
|
|
819
849
|
@pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
|
|
820
850
|
def test_run_conformance(
|
|
821
|
-
self,
|
|
822
|
-
|
|
851
|
+
self,
|
|
852
|
+
batchSystem: Optional[str] = None,
|
|
853
|
+
caching: bool = False,
|
|
854
|
+
selected_tests: Optional[str] = None,
|
|
855
|
+
skipped_tests: Optional[str] = None,
|
|
856
|
+
extra_args: Optional[List[str]] = None,
|
|
857
|
+
) -> None:
|
|
823
858
|
run_conformance_tests(
|
|
824
859
|
workDir=self.workDir,
|
|
825
860
|
yml="conformance_test_v1.0.yaml",
|
|
826
861
|
caching=caching,
|
|
827
862
|
batchSystem=batchSystem,
|
|
828
863
|
selected_tests=selected_tests,
|
|
864
|
+
skipped_tests=skipped_tests,
|
|
865
|
+
extra_args=extra_args,
|
|
829
866
|
)
|
|
830
867
|
|
|
831
868
|
@slow
|
|
832
869
|
@needs_lsf
|
|
833
|
-
@unittest.skip
|
|
834
|
-
def test_lsf_cwl_conformance(self,
|
|
835
|
-
|
|
870
|
+
@unittest.skip("Not run")
|
|
871
|
+
def test_lsf_cwl_conformance(self, caching: bool = False) -> None:
|
|
872
|
+
self.test_run_conformance(batchSystem="lsf", caching=caching)
|
|
836
873
|
|
|
837
874
|
@slow
|
|
838
875
|
@needs_slurm
|
|
839
|
-
@unittest.skip
|
|
840
|
-
def test_slurm_cwl_conformance(self,
|
|
841
|
-
|
|
876
|
+
@unittest.skip("Not run")
|
|
877
|
+
def test_slurm_cwl_conformance(self, caching: bool = False) -> None:
|
|
878
|
+
self.test_run_conformance(batchSystem="slurm", caching=caching)
|
|
842
879
|
|
|
843
880
|
@slow
|
|
844
881
|
@needs_torque
|
|
845
|
-
@unittest.skip
|
|
846
|
-
def test_torque_cwl_conformance(self,
|
|
847
|
-
|
|
882
|
+
@unittest.skip("Not run")
|
|
883
|
+
def test_torque_cwl_conformance(self, caching: bool = False) -> None:
|
|
884
|
+
self.test_run_conformance(batchSystem="torque", caching=caching)
|
|
848
885
|
|
|
849
886
|
@slow
|
|
850
887
|
@needs_gridengine
|
|
851
|
-
@unittest.skip
|
|
852
|
-
def test_gridengine_cwl_conformance(self,
|
|
853
|
-
|
|
888
|
+
@unittest.skip("Not run")
|
|
889
|
+
def test_gridengine_cwl_conformance(self, caching: bool = False) -> None:
|
|
890
|
+
self.test_run_conformance(batchSystem="grid_engine", caching=caching)
|
|
854
891
|
|
|
855
892
|
@slow
|
|
856
893
|
@needs_mesos
|
|
857
|
-
@unittest.skip
|
|
858
|
-
def test_mesos_cwl_conformance(self,
|
|
859
|
-
|
|
894
|
+
@unittest.skip("Not run")
|
|
895
|
+
def test_mesos_cwl_conformance(self, caching: bool = False) -> None:
|
|
896
|
+
self.test_run_conformance(batchSystem="mesos", caching=caching)
|
|
860
897
|
|
|
861
898
|
@slow
|
|
862
899
|
@needs_kubernetes
|
|
863
|
-
def test_kubernetes_cwl_conformance(self,
|
|
864
|
-
|
|
900
|
+
def test_kubernetes_cwl_conformance(self, caching: bool = False) -> None:
|
|
901
|
+
self.test_run_conformance(
|
|
902
|
+
caching=caching,
|
|
865
903
|
batchSystem="kubernetes",
|
|
866
904
|
extra_args=["--retryCount=3"],
|
|
867
905
|
# This test doesn't work with
|
|
868
906
|
# Singularity; see
|
|
869
907
|
# https://github.com/common-workflow-language/cwltool/blob/7094ede917c2d5b16d11f9231fe0c05260b51be6/conformance-test.sh#L99-L117
|
|
870
908
|
skipped_tests="docker_entrypoint",
|
|
871
|
-
**kwargs,
|
|
872
909
|
)
|
|
873
910
|
|
|
874
911
|
@slow
|
|
875
912
|
@needs_lsf
|
|
876
|
-
@unittest.skip
|
|
877
|
-
def test_lsf_cwl_conformance_with_caching(self):
|
|
878
|
-
|
|
913
|
+
@unittest.skip("Not run")
|
|
914
|
+
def test_lsf_cwl_conformance_with_caching(self) -> None:
|
|
915
|
+
self.test_lsf_cwl_conformance(caching=True)
|
|
879
916
|
|
|
880
917
|
@slow
|
|
881
918
|
@needs_slurm
|
|
882
|
-
@unittest.skip
|
|
883
|
-
def test_slurm_cwl_conformance_with_caching(self):
|
|
884
|
-
|
|
919
|
+
@unittest.skip("Not run")
|
|
920
|
+
def test_slurm_cwl_conformance_with_caching(self) -> None:
|
|
921
|
+
self.test_slurm_cwl_conformance(caching=True)
|
|
885
922
|
|
|
886
923
|
@slow
|
|
887
924
|
@needs_torque
|
|
888
|
-
@unittest.skip
|
|
889
|
-
def test_torque_cwl_conformance_with_caching(self):
|
|
890
|
-
|
|
925
|
+
@unittest.skip("Not run")
|
|
926
|
+
def test_torque_cwl_conformance_with_caching(self) -> None:
|
|
927
|
+
self.test_torque_cwl_conformance(caching=True)
|
|
891
928
|
|
|
892
929
|
@slow
|
|
893
930
|
@needs_gridengine
|
|
894
|
-
@unittest.skip
|
|
895
|
-
def test_gridengine_cwl_conformance_with_caching(self):
|
|
896
|
-
|
|
931
|
+
@unittest.skip("Not run")
|
|
932
|
+
def test_gridengine_cwl_conformance_with_caching(self) -> None:
|
|
933
|
+
self.test_gridengine_cwl_conformance(caching=True)
|
|
897
934
|
|
|
898
935
|
@slow
|
|
899
936
|
@needs_mesos
|
|
900
|
-
@unittest.skip
|
|
901
|
-
def test_mesos_cwl_conformance_with_caching(self):
|
|
902
|
-
|
|
937
|
+
@unittest.skip("Not run")
|
|
938
|
+
def test_mesos_cwl_conformance_with_caching(self) -> None:
|
|
939
|
+
self.test_mesos_cwl_conformance(caching=True)
|
|
903
940
|
|
|
904
941
|
@slow
|
|
905
942
|
@needs_kubernetes
|
|
906
|
-
def test_kubernetes_cwl_conformance_with_caching(self):
|
|
907
|
-
|
|
943
|
+
def test_kubernetes_cwl_conformance_with_caching(self) -> None:
|
|
944
|
+
self.test_kubernetes_cwl_conformance(caching=True)
|
|
908
945
|
|
|
909
946
|
|
|
910
947
|
@needs_cwl
|
|
@@ -914,8 +951,12 @@ class CWLv11Test(ToilTest):
|
|
|
914
951
|
Run the CWL 1.1 conformance tests in various environments.
|
|
915
952
|
"""
|
|
916
953
|
|
|
954
|
+
rootDir: str
|
|
955
|
+
cwlSpec: str
|
|
956
|
+
test_yaml: str
|
|
957
|
+
|
|
917
958
|
@classmethod
|
|
918
|
-
def setUpClass(cls):
|
|
959
|
+
def setUpClass(cls) -> None:
|
|
919
960
|
"""Runs anew before each test."""
|
|
920
961
|
cls.rootDir = cls._projectRootPath()
|
|
921
962
|
cls.cwlSpec = os.path.join(cls.rootDir, "src/toil/test/cwl/spec_v11")
|
|
@@ -929,37 +970,50 @@ class CWLv11Test(ToilTest):
|
|
|
929
970
|
)
|
|
930
971
|
p.communicate()
|
|
931
972
|
|
|
932
|
-
def tearDown(self):
|
|
973
|
+
def tearDown(self) -> None:
|
|
933
974
|
"""Clean up outputs."""
|
|
934
975
|
unittest.TestCase.tearDown(self)
|
|
935
976
|
|
|
936
977
|
@slow
|
|
937
978
|
@pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
|
|
938
|
-
def test_run_conformance(
|
|
939
|
-
|
|
979
|
+
def test_run_conformance(
|
|
980
|
+
self,
|
|
981
|
+
caching: bool = False,
|
|
982
|
+
batchSystem: Optional[str] = None,
|
|
983
|
+
skipped_tests: Optional[str] = None,
|
|
984
|
+
extra_args: Optional[List[str]] = None,
|
|
985
|
+
) -> None:
|
|
986
|
+
run_conformance_tests(
|
|
987
|
+
workDir=self.cwlSpec,
|
|
988
|
+
yml=self.test_yaml,
|
|
989
|
+
caching=caching,
|
|
990
|
+
batchSystem=batchSystem,
|
|
991
|
+
skipped_tests=skipped_tests,
|
|
992
|
+
extra_args=extra_args,
|
|
993
|
+
)
|
|
940
994
|
|
|
941
995
|
@slow
|
|
942
996
|
@pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
|
|
943
|
-
def test_run_conformance_with_caching(self):
|
|
997
|
+
def test_run_conformance_with_caching(self) -> None:
|
|
944
998
|
self.test_run_conformance(caching=True)
|
|
945
999
|
|
|
946
1000
|
@slow
|
|
947
1001
|
@needs_kubernetes
|
|
948
|
-
def test_kubernetes_cwl_conformance(self,
|
|
949
|
-
|
|
1002
|
+
def test_kubernetes_cwl_conformance(self, caching: bool = False) -> None:
|
|
1003
|
+
self.test_run_conformance(
|
|
950
1004
|
batchSystem="kubernetes",
|
|
951
1005
|
extra_args=["--retryCount=3"],
|
|
952
1006
|
# These tests don't work with
|
|
953
1007
|
# Singularity; see
|
|
954
1008
|
# https://github.com/common-workflow-language/cwltool/blob/7094ede917c2d5b16d11f9231fe0c05260b51be6/conformance-test.sh#L99-L117
|
|
955
1009
|
skipped_tests="docker_entrypoint,stdin_shorcut",
|
|
956
|
-
|
|
1010
|
+
caching=caching,
|
|
957
1011
|
)
|
|
958
1012
|
|
|
959
1013
|
@slow
|
|
960
1014
|
@needs_kubernetes
|
|
961
|
-
def test_kubernetes_cwl_conformance_with_caching(self):
|
|
962
|
-
|
|
1015
|
+
def test_kubernetes_cwl_conformance_with_caching(self) -> None:
|
|
1016
|
+
self.test_kubernetes_cwl_conformance(caching=True)
|
|
963
1017
|
|
|
964
1018
|
|
|
965
1019
|
@needs_cwl
|
|
@@ -969,8 +1023,12 @@ class CWLv12Test(ToilTest):
|
|
|
969
1023
|
Run the CWL 1.2 conformance tests in various environments.
|
|
970
1024
|
"""
|
|
971
1025
|
|
|
1026
|
+
rootDir: str
|
|
1027
|
+
cwlSpec: str
|
|
1028
|
+
test_yaml: str
|
|
1029
|
+
|
|
972
1030
|
@classmethod
|
|
973
|
-
def setUpClass(cls):
|
|
1031
|
+
def setUpClass(cls) -> None:
|
|
974
1032
|
"""Runs anew before each test."""
|
|
975
1033
|
cls.rootDir = cls._projectRootPath()
|
|
976
1034
|
cls.cwlSpec = os.path.join(cls.rootDir, "src/toil/test/cwl/spec_v12")
|
|
@@ -984,22 +1042,41 @@ class CWLv12Test(ToilTest):
|
|
|
984
1042
|
)
|
|
985
1043
|
p.communicate()
|
|
986
1044
|
|
|
987
|
-
def tearDown(self):
|
|
1045
|
+
def tearDown(self) -> None:
|
|
988
1046
|
"""Clean up outputs."""
|
|
989
1047
|
unittest.TestCase.tearDown(self)
|
|
990
1048
|
|
|
991
1049
|
@slow
|
|
992
1050
|
@pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
|
|
993
|
-
def test_run_conformance(
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1051
|
+
def test_run_conformance(
|
|
1052
|
+
self,
|
|
1053
|
+
runner: Optional[str] = None,
|
|
1054
|
+
caching: bool = False,
|
|
1055
|
+
batchSystem: Optional[str] = None,
|
|
1056
|
+
selected_tests: Optional[str] = None,
|
|
1057
|
+
skipped_tests: Optional[str] = None,
|
|
1058
|
+
extra_args: Optional[List[str]] = None,
|
|
1059
|
+
must_support_all_features: bool = False,
|
|
1060
|
+
junit_file: Optional[str] = None,
|
|
1061
|
+
) -> None:
|
|
1062
|
+
if junit_file is None:
|
|
1063
|
+
junit_file = os.path.join(self.rootDir, "conformance-1.2.junit.xml")
|
|
1064
|
+
run_conformance_tests(
|
|
1065
|
+
workDir=self.cwlSpec,
|
|
1066
|
+
yml=self.test_yaml,
|
|
1067
|
+
runner=runner,
|
|
1068
|
+
caching=caching,
|
|
1069
|
+
batchSystem=batchSystem,
|
|
1070
|
+
selected_tests=selected_tests,
|
|
1071
|
+
skipped_tests=skipped_tests,
|
|
1072
|
+
extra_args=extra_args,
|
|
1073
|
+
must_support_all_features=must_support_all_features,
|
|
1074
|
+
junit_file=junit_file,
|
|
1075
|
+
)
|
|
999
1076
|
|
|
1000
1077
|
@slow
|
|
1001
1078
|
@pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
|
|
1002
|
-
def test_run_conformance_with_caching(self):
|
|
1079
|
+
def test_run_conformance_with_caching(self) -> None:
|
|
1003
1080
|
self.test_run_conformance(
|
|
1004
1081
|
caching=True,
|
|
1005
1082
|
junit_file = os.path.join(
|
|
@@ -1009,7 +1086,7 @@ class CWLv12Test(ToilTest):
|
|
|
1009
1086
|
|
|
1010
1087
|
@slow
|
|
1011
1088
|
@pytest.mark.timeout(CONFORMANCE_TEST_TIMEOUT)
|
|
1012
|
-
def test_run_conformance_with_in_place_update(self):
|
|
1089
|
+
def test_run_conformance_with_in_place_update(self) -> None:
|
|
1013
1090
|
"""
|
|
1014
1091
|
Make sure that with --bypass-file-store we properly support in place
|
|
1015
1092
|
update on a single node, and that this doesn't break any other
|
|
@@ -1024,12 +1101,15 @@ class CWLv12Test(ToilTest):
|
|
|
1024
1101
|
|
|
1025
1102
|
@slow
|
|
1026
1103
|
@needs_kubernetes
|
|
1027
|
-
def test_kubernetes_cwl_conformance(
|
|
1028
|
-
|
|
1029
|
-
|
|
1104
|
+
def test_kubernetes_cwl_conformance(
|
|
1105
|
+
self, caching: bool = False, junit_file: Optional[str] = None
|
|
1106
|
+
) -> None:
|
|
1107
|
+
if junit_file is None:
|
|
1108
|
+
junit_file = os.path.join(
|
|
1030
1109
|
self.rootDir, "kubernetes-conformance-1.2.junit.xml"
|
|
1031
1110
|
)
|
|
1032
|
-
|
|
1111
|
+
self.test_run_conformance(
|
|
1112
|
+
caching=caching,
|
|
1033
1113
|
batchSystem="kubernetes",
|
|
1034
1114
|
extra_args=["--retryCount=3"],
|
|
1035
1115
|
# This test doesn't work with
|
|
@@ -1038,13 +1118,13 @@ class CWLv12Test(ToilTest):
|
|
|
1038
1118
|
# and
|
|
1039
1119
|
# https://github.com/common-workflow-language/cwltool/issues/1441#issuecomment-826747975
|
|
1040
1120
|
skipped_tests="docker_entrypoint",
|
|
1041
|
-
|
|
1121
|
+
junit_file=junit_file,
|
|
1042
1122
|
)
|
|
1043
1123
|
|
|
1044
1124
|
@slow
|
|
1045
1125
|
@needs_kubernetes
|
|
1046
|
-
def test_kubernetes_cwl_conformance_with_caching(self):
|
|
1047
|
-
|
|
1126
|
+
def test_kubernetes_cwl_conformance_with_caching(self) -> None:
|
|
1127
|
+
self.test_kubernetes_cwl_conformance(
|
|
1048
1128
|
caching=True,
|
|
1049
1129
|
junit_file=os.path.join(
|
|
1050
1130
|
self.rootDir, "kubernetes-caching-conformance-1.2.junit.xml"
|
|
@@ -1053,7 +1133,7 @@ class CWLv12Test(ToilTest):
|
|
|
1053
1133
|
|
|
1054
1134
|
@slow
|
|
1055
1135
|
@needs_wes_server
|
|
1056
|
-
def test_wes_server_cwl_conformance(self):
|
|
1136
|
+
def test_wes_server_cwl_conformance(self) -> None:
|
|
1057
1137
|
"""
|
|
1058
1138
|
Run the CWL conformance tests via WES. TOIL_WES_ENDPOINT must be
|
|
1059
1139
|
specified. If the WES server requires authentication, set TOIL_WES_USER
|
|
@@ -1078,96 +1158,16 @@ class CWLv12Test(ToilTest):
|
|
|
1078
1158
|
# 1. `cwltool --print-deps` doesn't seem to include secondary files from the default
|
|
1079
1159
|
# e.g.: https://github.com/common-workflow-language/cwl-v1.2/blob/1.2.1_proposed/tests/mixed-versions/wf-v10.cwl#L4-L10
|
|
1080
1160
|
|
|
1081
|
-
|
|
1161
|
+
self.test_run_conformance(
|
|
1082
1162
|
runner="toil-wes-cwl-runner",
|
|
1083
1163
|
selected_tests="1-309,313-337",
|
|
1084
1164
|
extra_args=extra_args,
|
|
1085
1165
|
)
|
|
1086
1166
|
|
|
1087
1167
|
|
|
1088
|
-
@needs_aws_ec2
|
|
1089
|
-
@needs_fetchable_appliance
|
|
1090
|
-
@slow
|
|
1091
|
-
class CWLOnARMTest(AbstractClusterTest):
|
|
1092
|
-
"""
|
|
1093
|
-
Run the CWL 1.2 conformance tests on ARM specifically.
|
|
1094
|
-
"""
|
|
1095
|
-
|
|
1096
|
-
def __init__(self, methodName):
|
|
1097
|
-
super().__init__(methodName=methodName)
|
|
1098
|
-
self.clusterName = "cwl-test-" + str(uuid.uuid4())
|
|
1099
|
-
self.leaderNodeType = "t4g.2xlarge"
|
|
1100
|
-
self.clusterType = "kubernetes"
|
|
1101
|
-
# We need to be running in a directory which Flatcar and the Toil Appliance both have
|
|
1102
|
-
self.cwl_test_dir = "/tmp/toil/cwlTests"
|
|
1103
|
-
|
|
1104
|
-
def setUp(self):
|
|
1105
|
-
super().setUp()
|
|
1106
|
-
self.jobStore = f"aws:{self.awsRegion()}:cluster-{uuid.uuid4()}"
|
|
1107
|
-
|
|
1108
|
-
@needs_env_var("CI_COMMIT_SHA", "a git commit sha")
|
|
1109
|
-
def test_cwl_on_arm(self):
|
|
1110
|
-
# Make a cluster
|
|
1111
|
-
self.launchCluster()
|
|
1112
|
-
# get the leader so we know the IP address - we don't need to wait since create cluster
|
|
1113
|
-
# already ensures the leader is running
|
|
1114
|
-
self.cluster = cluster_factory(
|
|
1115
|
-
provisioner="aws", zone=self.zone, clusterName=self.clusterName
|
|
1116
|
-
)
|
|
1117
|
-
self.leader = self.cluster.getLeader()
|
|
1118
|
-
|
|
1119
|
-
commit = os.environ["CI_COMMIT_SHA"]
|
|
1120
|
-
self.sshUtil(
|
|
1121
|
-
[
|
|
1122
|
-
"bash",
|
|
1123
|
-
"-c",
|
|
1124
|
-
f"mkdir -p {self.cwl_test_dir} && cd {self.cwl_test_dir} && git clone https://github.com/DataBiosphere/toil.git",
|
|
1125
|
-
]
|
|
1126
|
-
)
|
|
1127
|
-
|
|
1128
|
-
# We use CI_COMMIT_SHA to retrieve the Toil version needed to run the CWL tests
|
|
1129
|
-
self.sshUtil(
|
|
1130
|
-
["bash", "-c", f"cd {self.cwl_test_dir}/toil && git checkout {commit}"]
|
|
1131
|
-
)
|
|
1132
|
-
|
|
1133
|
-
# --never-download prevents silent upgrades to pip, wheel and setuptools
|
|
1134
|
-
self.sshUtil(
|
|
1135
|
-
[
|
|
1136
|
-
"bash",
|
|
1137
|
-
"-c",
|
|
1138
|
-
f"virtualenv --system-site-packages --never-download {self.venvDir}",
|
|
1139
|
-
]
|
|
1140
|
-
)
|
|
1141
|
-
self.sshUtil(
|
|
1142
|
-
[
|
|
1143
|
-
"bash",
|
|
1144
|
-
"-c",
|
|
1145
|
-
f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && make prepare && make develop extras=[all]",
|
|
1146
|
-
]
|
|
1147
|
-
)
|
|
1148
|
-
|
|
1149
|
-
# Runs the CWLv12Test on an ARM instance
|
|
1150
|
-
self.sshUtil(
|
|
1151
|
-
[
|
|
1152
|
-
"bash",
|
|
1153
|
-
"-c",
|
|
1154
|
-
f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && pytest --log-cli-level DEBUG -r s src/toil/test/cwl/cwlTest.py::CWLv12Test::test_run_conformance",
|
|
1155
|
-
]
|
|
1156
|
-
)
|
|
1157
|
-
|
|
1158
|
-
# We know if it succeeds it should save a junit XML for us to read.
|
|
1159
|
-
# Bring it back to be an artifact.
|
|
1160
|
-
self.rsync_util(
|
|
1161
|
-
f":{self.cwl_test_dir}/toil/conformance-1.2.junit.xml",
|
|
1162
|
-
os.path.join(
|
|
1163
|
-
self._projectRootPath(),
|
|
1164
|
-
"arm-conformance-1.2.junit.xml"
|
|
1165
|
-
)
|
|
1166
|
-
)
|
|
1167
|
-
|
|
1168
1168
|
@needs_cwl
|
|
1169
1169
|
@pytest.mark.cwl_small_log_dir
|
|
1170
|
-
def test_workflow_echo_string_scatter_stderr_log_dir(tmp_path: Path):
|
|
1170
|
+
def test_workflow_echo_string_scatter_stderr_log_dir(tmp_path: Path) -> None:
|
|
1171
1171
|
log_dir = tmp_path / "cwl-logs"
|
|
1172
1172
|
job_store = "test_workflow_echo_string_scatter_stderr_log_dir"
|
|
1173
1173
|
toil = "toil-cwl-runner"
|
|
@@ -1274,7 +1274,7 @@ def test_log_dir_echo_stderr(tmp_path: Path) -> None:
|
|
|
1274
1274
|
|
|
1275
1275
|
@needs_cwl
|
|
1276
1276
|
@pytest.mark.cwl_small_log_dir
|
|
1277
|
-
def test_filename_conflict_resolution(tmp_path: Path):
|
|
1277
|
+
def test_filename_conflict_resolution(tmp_path: Path) -> None:
|
|
1278
1278
|
out_dir = tmp_path / "cwl-out-dir"
|
|
1279
1279
|
toil = "toil-cwl-runner"
|
|
1280
1280
|
options = [
|
|
@@ -1297,7 +1297,7 @@ def test_filename_conflict_resolution(tmp_path: Path):
|
|
|
1297
1297
|
@needs_cwl
|
|
1298
1298
|
@needs_docker
|
|
1299
1299
|
@pytest.mark.cwl_small_log_dir
|
|
1300
|
-
def test_filename_conflict_detection(tmp_path: Path):
|
|
1300
|
+
def test_filename_conflict_detection(tmp_path: Path) -> None:
|
|
1301
1301
|
"""
|
|
1302
1302
|
Make sure we don't just stage files over each other when using a container.
|
|
1303
1303
|
"""
|
|
@@ -1319,7 +1319,7 @@ def test_filename_conflict_detection(tmp_path: Path):
|
|
|
1319
1319
|
@needs_cwl
|
|
1320
1320
|
@needs_docker
|
|
1321
1321
|
@pytest.mark.cwl_small_log_dir
|
|
1322
|
-
def test_filename_conflict_detection_at_root(tmp_path: Path):
|
|
1322
|
+
def test_filename_conflict_detection_at_root(tmp_path: Path) -> None:
|
|
1323
1323
|
"""
|
|
1324
1324
|
Make sure we don't just stage files over each other.
|
|
1325
1325
|
|
|
@@ -1343,7 +1343,7 @@ def test_filename_conflict_detection_at_root(tmp_path: Path):
|
|
|
1343
1343
|
|
|
1344
1344
|
@needs_cwl
|
|
1345
1345
|
@pytest.mark.cwl_small
|
|
1346
|
-
def test_pick_value_with_one_null_value(caplog):
|
|
1346
|
+
def test_pick_value_with_one_null_value(caplog: pytest.LogCaptureFixture) -> None:
|
|
1347
1347
|
"""
|
|
1348
1348
|
Make sure toil-cwl-runner does not false log a warning when pickValue is
|
|
1349
1349
|
used but outputSource only contains one null value. See: #3991.
|
|
@@ -1362,7 +1362,7 @@ def test_pick_value_with_one_null_value(caplog):
|
|
|
1362
1362
|
|
|
1363
1363
|
@needs_cwl
|
|
1364
1364
|
@pytest.mark.cwl_small
|
|
1365
|
-
def test_workflow_echo_string():
|
|
1365
|
+
def test_workflow_echo_string() -> None:
|
|
1366
1366
|
toil = "toil-cwl-runner"
|
|
1367
1367
|
jobstore = f"--jobStore=file:explicit-local-jobstore-{uuid.uuid4()}"
|
|
1368
1368
|
option_1 = "--strict-memory-limit"
|
|
@@ -1372,14 +1372,18 @@ def test_workflow_echo_string():
|
|
|
1372
1372
|
cmd = [toil, jobstore, option_1, option_2, option_3, cwl]
|
|
1373
1373
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
1374
1374
|
stdout, stderr = p.communicate()
|
|
1375
|
-
|
|
1376
|
-
|
|
1375
|
+
stdout2 = stdout.decode("utf-8")
|
|
1376
|
+
stderr2 = stderr.decode("utf-8")
|
|
1377
|
+
assert (
|
|
1378
|
+
stdout2.strip() == "{}"
|
|
1379
|
+
), f"Got wrong output: {stdout2}\nWith error: {stderr2}"
|
|
1380
|
+
assert "Finished toil run successfully" in stderr2
|
|
1377
1381
|
assert p.returncode == 0
|
|
1378
1382
|
|
|
1379
1383
|
|
|
1380
1384
|
@needs_cwl
|
|
1381
1385
|
@pytest.mark.cwl_small
|
|
1382
|
-
def test_workflow_echo_string_scatter_capture_stdout():
|
|
1386
|
+
def test_workflow_echo_string_scatter_capture_stdout() -> None:
|
|
1383
1387
|
toil = "toil-cwl-runner"
|
|
1384
1388
|
jobstore = f"--jobStore=file:explicit-local-jobstore-{uuid.uuid4()}"
|
|
1385
1389
|
option_1 = "--strict-memory-limit"
|
|
@@ -1412,7 +1416,7 @@ def test_workflow_echo_string_scatter_capture_stdout():
|
|
|
1412
1416
|
|
|
1413
1417
|
@needs_cwl
|
|
1414
1418
|
@pytest.mark.cwl_small
|
|
1415
|
-
def test_visit_top_cwl_class():
|
|
1419
|
+
def test_visit_top_cwl_class() -> None:
|
|
1416
1420
|
structure = {
|
|
1417
1421
|
"class": "Directory",
|
|
1418
1422
|
"listing": [
|
|
@@ -1438,7 +1442,7 @@ def test_visit_top_cwl_class():
|
|
|
1438
1442
|
|
|
1439
1443
|
counter = 0
|
|
1440
1444
|
|
|
1441
|
-
def increment(thing:
|
|
1445
|
+
def increment(thing: "CWLObjectType") -> None:
|
|
1442
1446
|
"""
|
|
1443
1447
|
Make sure we are at something CWL object like, and count it.
|
|
1444
1448
|
"""
|
|
@@ -1463,7 +1467,7 @@ def test_visit_top_cwl_class():
|
|
|
1463
1467
|
|
|
1464
1468
|
@needs_cwl
|
|
1465
1469
|
@pytest.mark.cwl_small
|
|
1466
|
-
def test_visit_cwl_class_and_reduce():
|
|
1470
|
+
def test_visit_cwl_class_and_reduce() -> None:
|
|
1467
1471
|
structure = {
|
|
1468
1472
|
"class": "Directory",
|
|
1469
1473
|
"listing": [
|
|
@@ -1489,7 +1493,7 @@ def test_visit_cwl_class_and_reduce():
|
|
|
1489
1493
|
|
|
1490
1494
|
down_count = 0
|
|
1491
1495
|
|
|
1492
|
-
def op_down(thing:
|
|
1496
|
+
def op_down(thing: "CWLObjectType") -> int:
|
|
1493
1497
|
"""
|
|
1494
1498
|
Grab the ID of the thing we are at, and count what we visit going
|
|
1495
1499
|
down.
|
|
@@ -1501,7 +1505,7 @@ def test_visit_cwl_class_and_reduce():
|
|
|
1501
1505
|
up_count = 0
|
|
1502
1506
|
up_child_count = 0
|
|
1503
1507
|
|
|
1504
|
-
def op_up(thing:
|
|
1508
|
+
def op_up(thing: "CWLObjectType", down_value: int, child_results: List[str]) -> str:
|
|
1505
1509
|
"""
|
|
1506
1510
|
Check the down return value and the up return values, and count
|
|
1507
1511
|
what we visit going up and what child relationships we have.
|
|
@@ -1524,7 +1528,7 @@ def test_visit_cwl_class_and_reduce():
|
|
|
1524
1528
|
|
|
1525
1529
|
@needs_cwl
|
|
1526
1530
|
@pytest.mark.cwl_small
|
|
1527
|
-
def test_download_structure(tmp_path) -> None:
|
|
1531
|
+
def test_download_structure(tmp_path: Path) -> None:
|
|
1528
1532
|
"""
|
|
1529
1533
|
Make sure that download_structure makes the right calls to what it thinks is the file store.
|
|
1530
1534
|
"""
|
|
@@ -1534,7 +1538,7 @@ def test_download_structure(tmp_path) -> None:
|
|
|
1534
1538
|
fid2 = FileID("adifferentfile", 1000, True)
|
|
1535
1539
|
|
|
1536
1540
|
# And what directory structure it would be in
|
|
1537
|
-
structure = {
|
|
1541
|
+
structure: DirectoryStructure = {
|
|
1538
1542
|
"dir1": {
|
|
1539
1543
|
"dir2": {
|
|
1540
1544
|
"f1": "toilfile:" + fid1.pack(),
|
|
@@ -1555,9 +1559,9 @@ def test_download_structure(tmp_path) -> None:
|
|
|
1555
1559
|
# These will be populated.
|
|
1556
1560
|
# TODO: This cache seems unused. Remove it?
|
|
1557
1561
|
# This maps filesystem path to CWL URI
|
|
1558
|
-
index = {}
|
|
1562
|
+
index: Dict[str, str] = {}
|
|
1559
1563
|
# This maps CWL URI to filesystem path
|
|
1560
|
-
existing = {}
|
|
1564
|
+
existing: Dict[str, str] = {}
|
|
1561
1565
|
|
|
1562
1566
|
# Do the download
|
|
1563
1567
|
download_structure(file_store, index, existing, structure, to_dir)
|
|
@@ -1573,11 +1577,16 @@ def test_download_structure(tmp_path) -> None:
|
|
|
1573
1577
|
assert os.path.join(to_dir, "dir1/dir2/f1again") in index
|
|
1574
1578
|
assert os.path.join(to_dir, "anotherfile") in index
|
|
1575
1579
|
assert (
|
|
1576
|
-
index[os.path.join(to_dir, "dir1/dir2/f1")]
|
|
1580
|
+
index[os.path.join(to_dir, "dir1/dir2/f1")]
|
|
1581
|
+
== cast(
|
|
1582
|
+
DirectoryStructure, cast(DirectoryStructure, structure["dir1"])["dir2"]
|
|
1583
|
+
)["f1"]
|
|
1577
1584
|
)
|
|
1578
1585
|
assert (
|
|
1579
1586
|
index[os.path.join(to_dir, "dir1/dir2/f1again")]
|
|
1580
|
-
==
|
|
1587
|
+
== cast(
|
|
1588
|
+
DirectoryStructure, cast(DirectoryStructure, structure["dir1"])["dir2"]
|
|
1589
|
+
)["f1again"]
|
|
1581
1590
|
)
|
|
1582
1591
|
assert index[os.path.join(to_dir, "anotherfile")] == structure["anotherfile"]
|
|
1583
1592
|
|