toil 8.1.0b1__py3-none-any.whl → 8.2.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 +0 -35
- toil/batchSystems/abstractBatchSystem.py +1 -1
- toil/batchSystems/abstractGridEngineBatchSystem.py +1 -1
- toil/batchSystems/awsBatch.py +1 -1
- toil/batchSystems/cleanup_support.py +1 -1
- toil/batchSystems/kubernetes.py +53 -7
- toil/batchSystems/local_support.py +1 -1
- toil/batchSystems/mesos/batchSystem.py +13 -8
- toil/batchSystems/mesos/test/__init__.py +3 -2
- toil/batchSystems/singleMachine.py +1 -1
- toil/batchSystems/slurm.py +27 -26
- toil/bus.py +5 -3
- toil/common.py +39 -11
- toil/cwl/cwltoil.py +1 -1
- toil/job.py +64 -49
- toil/jobStores/abstractJobStore.py +24 -3
- toil/jobStores/fileJobStore.py +25 -1
- toil/jobStores/googleJobStore.py +104 -30
- toil/leader.py +9 -0
- toil/lib/accelerators.py +3 -1
- toil/lib/aws/utils.py.orig +504 -0
- toil/lib/bioio.py +1 -1
- toil/lib/docker.py +252 -91
- toil/lib/dockstore.py +11 -3
- toil/lib/exceptions.py +5 -3
- toil/lib/history.py +87 -13
- toil/lib/history_submission.py +23 -9
- toil/lib/io.py +34 -22
- toil/lib/misc.py +7 -1
- toil/lib/resources.py +2 -1
- toil/lib/threading.py +11 -10
- toil/options/common.py +8 -0
- toil/options/wdl.py +11 -0
- toil/server/api_spec/LICENSE +201 -0
- toil/server/api_spec/README.rst +5 -0
- toil/server/cli/wes_cwl_runner.py +2 -1
- toil/test/__init__.py +275 -115
- toil/test/batchSystems/batchSystemTest.py +227 -205
- toil/test/batchSystems/test_slurm.py +27 -0
- toil/test/cactus/pestis.tar.gz +0 -0
- toil/test/conftest.py +7 -0
- toil/test/cwl/2.fasta +11 -0
- toil/test/cwl/2.fastq +12 -0
- toil/test/cwl/conftest.py +1 -1
- toil/test/cwl/cwlTest.py +999 -867
- toil/test/cwl/directory/directory/file.txt +15 -0
- toil/test/cwl/download_directory_file.json +4 -0
- toil/test/cwl/download_directory_s3.json +4 -0
- toil/test/cwl/download_file.json +6 -0
- toil/test/cwl/download_http.json +6 -0
- toil/test/cwl/download_https.json +6 -0
- toil/test/cwl/download_s3.json +6 -0
- toil/test/cwl/download_subdirectory_file.json +5 -0
- toil/test/cwl/download_subdirectory_s3.json +5 -0
- toil/test/cwl/empty.json +1 -0
- toil/test/cwl/mock_mpi/fake_mpi.yml +8 -0
- toil/test/cwl/mock_mpi/fake_mpi_run.py +42 -0
- toil/test/cwl/optional-file-exists.json +6 -0
- toil/test/cwl/optional-file-missing.json +6 -0
- toil/test/cwl/preemptible_expression.json +1 -0
- toil/test/cwl/revsort-job-missing.json +6 -0
- toil/test/cwl/revsort-job.json +6 -0
- toil/test/cwl/s3_secondary_file.json +16 -0
- toil/test/cwl/seqtk_seq_job.json +6 -0
- toil/test/cwl/stream.json +6 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.dat +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f1 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f1i +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f2 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f2_TSM0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f3 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f3_TSM0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f4 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f4_TSM0 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.f5 +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.info +0 -0
- toil/test/cwl/test_filename_conflict_resolution.ms/table.lock +0 -0
- toil/test/cwl/whale.txt +16 -0
- toil/test/docs/scripts/example_alwaysfail.py +38 -0
- toil/test/docs/scripts/example_alwaysfail_with_files.wdl +33 -0
- toil/test/docs/scripts/example_cachingbenchmark.py +117 -0
- toil/test/docs/scripts/stagingExampleFiles/in.txt +1 -0
- toil/test/docs/scripts/stagingExampleFiles/out.txt +2 -0
- toil/test/docs/scripts/tutorial_arguments.py +23 -0
- toil/test/docs/scripts/tutorial_debugging.patch +12 -0
- toil/test/docs/scripts/tutorial_debugging_hangs.wdl +126 -0
- toil/test/docs/scripts/tutorial_debugging_works.wdl +129 -0
- toil/test/docs/scripts/tutorial_docker.py +20 -0
- toil/test/docs/scripts/tutorial_dynamic.py +24 -0
- toil/test/docs/scripts/tutorial_encapsulation.py +28 -0
- toil/test/docs/scripts/tutorial_encapsulation2.py +29 -0
- toil/test/docs/scripts/tutorial_helloworld.py +15 -0
- toil/test/docs/scripts/tutorial_invokeworkflow.py +27 -0
- toil/test/docs/scripts/tutorial_invokeworkflow2.py +30 -0
- toil/test/docs/scripts/tutorial_jobfunctions.py +22 -0
- toil/test/docs/scripts/tutorial_managing.py +29 -0
- toil/test/docs/scripts/tutorial_managing2.py +56 -0
- toil/test/docs/scripts/tutorial_multiplejobs.py +25 -0
- toil/test/docs/scripts/tutorial_multiplejobs2.py +21 -0
- toil/test/docs/scripts/tutorial_multiplejobs3.py +22 -0
- toil/test/docs/scripts/tutorial_promises.py +25 -0
- toil/test/docs/scripts/tutorial_promises2.py +30 -0
- toil/test/docs/scripts/tutorial_quickstart.py +22 -0
- toil/test/docs/scripts/tutorial_requirements.py +44 -0
- toil/test/docs/scripts/tutorial_services.py +45 -0
- toil/test/docs/scripts/tutorial_staging.py +45 -0
- toil/test/docs/scripts/tutorial_stats.py +64 -0
- toil/test/lib/aws/test_iam.py +3 -1
- toil/test/lib/dockerTest.py +205 -122
- toil/test/lib/test_history.py +101 -77
- toil/test/provisioners/aws/awsProvisionerTest.py +12 -9
- toil/test/provisioners/clusterTest.py +4 -4
- toil/test/provisioners/gceProvisionerTest.py +16 -14
- toil/test/sort/sort.py +4 -1
- toil/test/src/busTest.py +17 -17
- toil/test/src/deferredFunctionTest.py +145 -132
- toil/test/src/importExportFileTest.py +71 -63
- toil/test/src/jobEncapsulationTest.py +27 -28
- toil/test/src/jobServiceTest.py +149 -133
- toil/test/src/jobTest.py +219 -211
- toil/test/src/miscTests.py +66 -60
- toil/test/src/promisedRequirementTest.py +163 -169
- toil/test/src/regularLogTest.py +24 -24
- toil/test/src/resourceTest.py +82 -76
- toil/test/src/restartDAGTest.py +51 -47
- toil/test/src/resumabilityTest.py +24 -19
- toil/test/src/retainTempDirTest.py +60 -57
- toil/test/src/systemTest.py +17 -13
- toil/test/src/threadingTest.py +29 -32
- toil/test/utils/ABCWorkflowDebug/B_file.txt +1 -0
- toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +204 -0
- toil/test/utils/ABCWorkflowDebug/mkFile.py +16 -0
- toil/test/utils/ABCWorkflowDebug/sleep.cwl +12 -0
- toil/test/utils/ABCWorkflowDebug/sleep.yaml +1 -0
- toil/test/utils/toilDebugTest.py +117 -102
- toil/test/utils/toilKillTest.py +54 -53
- toil/test/utils/utilsTest.py +303 -229
- toil/test/wdl/lint_error.wdl +9 -0
- toil/test/wdl/md5sum/empty_file.json +1 -0
- toil/test/wdl/md5sum/md5sum-gs.json +1 -0
- toil/test/wdl/md5sum/md5sum.1.0.wdl +32 -0
- toil/test/wdl/md5sum/md5sum.input +1 -0
- toil/test/wdl/md5sum/md5sum.json +1 -0
- toil/test/wdl/md5sum/md5sum.wdl +25 -0
- toil/test/wdl/miniwdl_self_test/inputs-namespaced.json +1 -0
- toil/test/wdl/miniwdl_self_test/inputs.json +1 -0
- toil/test/wdl/miniwdl_self_test/self_test.wdl +40 -0
- toil/test/wdl/standard_library/as_map.json +16 -0
- toil/test/wdl/standard_library/as_map_as_input.wdl +23 -0
- toil/test/wdl/standard_library/as_pairs.json +7 -0
- toil/test/wdl/standard_library/as_pairs_as_input.wdl +23 -0
- toil/test/wdl/standard_library/ceil.json +3 -0
- toil/test/wdl/standard_library/ceil_as_command.wdl +16 -0
- toil/test/wdl/standard_library/ceil_as_input.wdl +16 -0
- toil/test/wdl/standard_library/collect_by_key.json +1 -0
- toil/test/wdl/standard_library/collect_by_key_as_input.wdl +23 -0
- toil/test/wdl/standard_library/cross.json +11 -0
- toil/test/wdl/standard_library/cross_as_input.wdl +19 -0
- toil/test/wdl/standard_library/flatten.json +7 -0
- toil/test/wdl/standard_library/flatten_as_input.wdl +18 -0
- toil/test/wdl/standard_library/floor.json +3 -0
- toil/test/wdl/standard_library/floor_as_command.wdl +16 -0
- toil/test/wdl/standard_library/floor_as_input.wdl +16 -0
- toil/test/wdl/standard_library/keys.json +8 -0
- toil/test/wdl/standard_library/keys_as_input.wdl +24 -0
- toil/test/wdl/standard_library/length.json +7 -0
- toil/test/wdl/standard_library/length_as_input.wdl +16 -0
- toil/test/wdl/standard_library/length_as_input_with_map.json +7 -0
- toil/test/wdl/standard_library/length_as_input_with_map.wdl +17 -0
- toil/test/wdl/standard_library/length_invalid.json +3 -0
- toil/test/wdl/standard_library/range.json +3 -0
- toil/test/wdl/standard_library/range_0.json +3 -0
- toil/test/wdl/standard_library/range_as_input.wdl +17 -0
- toil/test/wdl/standard_library/range_invalid.json +3 -0
- toil/test/wdl/standard_library/read_boolean.json +3 -0
- toil/test/wdl/standard_library/read_boolean_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_float.json +3 -0
- toil/test/wdl/standard_library/read_float_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_int.json +3 -0
- toil/test/wdl/standard_library/read_int_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_json.json +3 -0
- toil/test/wdl/standard_library/read_json_as_output.wdl +31 -0
- toil/test/wdl/standard_library/read_lines.json +3 -0
- toil/test/wdl/standard_library/read_lines_as_output.wdl +31 -0
- toil/test/wdl/standard_library/read_map.json +3 -0
- toil/test/wdl/standard_library/read_map_as_output.wdl +31 -0
- toil/test/wdl/standard_library/read_string.json +3 -0
- toil/test/wdl/standard_library/read_string_as_command.wdl +17 -0
- toil/test/wdl/standard_library/read_tsv.json +3 -0
- toil/test/wdl/standard_library/read_tsv_as_output.wdl +31 -0
- toil/test/wdl/standard_library/round.json +3 -0
- toil/test/wdl/standard_library/round_as_command.wdl +16 -0
- toil/test/wdl/standard_library/round_as_input.wdl +16 -0
- toil/test/wdl/standard_library/size.json +3 -0
- toil/test/wdl/standard_library/size_as_command.wdl +17 -0
- toil/test/wdl/standard_library/size_as_output.wdl +36 -0
- toil/test/wdl/standard_library/stderr.json +3 -0
- toil/test/wdl/standard_library/stderr_as_output.wdl +30 -0
- toil/test/wdl/standard_library/stdout.json +3 -0
- toil/test/wdl/standard_library/stdout_as_output.wdl +30 -0
- toil/test/wdl/standard_library/sub.json +3 -0
- toil/test/wdl/standard_library/sub_as_input.wdl +17 -0
- toil/test/wdl/standard_library/sub_as_input_with_file.wdl +17 -0
- toil/test/wdl/standard_library/transpose.json +6 -0
- toil/test/wdl/standard_library/transpose_as_input.wdl +18 -0
- toil/test/wdl/standard_library/write_json.json +6 -0
- toil/test/wdl/standard_library/write_json_as_command.wdl +17 -0
- toil/test/wdl/standard_library/write_lines.json +7 -0
- toil/test/wdl/standard_library/write_lines_as_command.wdl +17 -0
- toil/test/wdl/standard_library/write_map.json +6 -0
- toil/test/wdl/standard_library/write_map_as_command.wdl +17 -0
- toil/test/wdl/standard_library/write_tsv.json +6 -0
- toil/test/wdl/standard_library/write_tsv_as_command.wdl +17 -0
- toil/test/wdl/standard_library/zip.json +12 -0
- toil/test/wdl/standard_library/zip_as_input.wdl +19 -0
- toil/test/wdl/test.csv +3 -0
- toil/test/wdl/test.tsv +3 -0
- toil/test/wdl/testfiles/croo.wdl +38 -0
- toil/test/wdl/testfiles/drop_files.wdl +62 -0
- toil/test/wdl/testfiles/drop_files_subworkflow.wdl +13 -0
- toil/test/wdl/testfiles/empty.txt +0 -0
- toil/test/wdl/testfiles/not_enough_outputs.wdl +33 -0
- toil/test/wdl/testfiles/random.wdl +66 -0
- toil/test/wdl/testfiles/string_file_coercion.json +1 -0
- toil/test/wdl/testfiles/string_file_coercion.wdl +35 -0
- toil/test/wdl/testfiles/test.json +4 -0
- toil/test/wdl/testfiles/test_boolean.txt +1 -0
- toil/test/wdl/testfiles/test_float.txt +1 -0
- toil/test/wdl/testfiles/test_int.txt +1 -0
- toil/test/wdl/testfiles/test_lines.txt +5 -0
- toil/test/wdl/testfiles/test_map.txt +2 -0
- toil/test/wdl/testfiles/test_string.txt +1 -0
- toil/test/wdl/testfiles/url_to_file.wdl +13 -0
- toil/test/wdl/testfiles/url_to_optional_file.wdl +13 -0
- toil/test/wdl/testfiles/vocab.json +1 -0
- toil/test/wdl/testfiles/vocab.wdl +66 -0
- toil/test/wdl/testfiles/wait.wdl +34 -0
- toil/test/wdl/wdl_specification/type_pair.json +23 -0
- toil/test/wdl/wdl_specification/type_pair_basic.wdl +36 -0
- toil/test/wdl/wdl_specification/type_pair_with_files.wdl +36 -0
- toil/test/wdl/wdl_specification/v1_spec.json +1 -0
- toil/test/wdl/wdl_specification/v1_spec_declaration.wdl +39 -0
- toil/test/wdl/wdltoil_test.py +680 -407
- toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
- toil/version.py +9 -9
- toil/wdl/wdltoil.py +336 -123
- {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/METADATA +5 -4
- toil-8.2.0.dist-info/RECORD +439 -0
- {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/WHEEL +1 -1
- toil-8.1.0b1.dist-info/RECORD +0 -259
- {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/entry_points.txt +0 -0
- {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info/licenses}/LICENSE +0 -0
- {toil-8.1.0b1.dist-info → toil-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from toil.common import Toil
|
|
4
|
+
from toil.job import Job
|
|
5
|
+
from toil.lib.io import mkdtemp
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HelloWorld(Job):
|
|
9
|
+
def __init__(self, id):
|
|
10
|
+
Job.__init__(self)
|
|
11
|
+
self.inputFileID = id
|
|
12
|
+
|
|
13
|
+
def run(self, fileStore):
|
|
14
|
+
with fileStore.readGlobalFileStream(self.inputFileID, encoding="utf-8") as fi:
|
|
15
|
+
with fileStore.writeGlobalFileStream(encoding="utf-8") as (
|
|
16
|
+
fo,
|
|
17
|
+
outputFileID,
|
|
18
|
+
):
|
|
19
|
+
fo.write(fi.read() + "World!")
|
|
20
|
+
return outputFileID
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
jobstore: str = mkdtemp("tutorial_staging")
|
|
25
|
+
os.rmdir(jobstore)
|
|
26
|
+
options = Job.Runner.getDefaultOptions(jobstore)
|
|
27
|
+
options.logLevel = "INFO"
|
|
28
|
+
options.clean = "always"
|
|
29
|
+
|
|
30
|
+
with Toil(options) as toil:
|
|
31
|
+
if not toil.options.restart:
|
|
32
|
+
ioFileDirectory = os.path.join(
|
|
33
|
+
os.path.dirname(os.path.abspath(__file__)), "stagingExampleFiles"
|
|
34
|
+
)
|
|
35
|
+
inputFileID = toil.importFile(
|
|
36
|
+
"file://" + os.path.abspath(os.path.join(ioFileDirectory, "in.txt"))
|
|
37
|
+
)
|
|
38
|
+
outputFileID = toil.start(HelloWorld(inputFileID))
|
|
39
|
+
else:
|
|
40
|
+
outputFileID = toil.restart()
|
|
41
|
+
|
|
42
|
+
toil.exportFile(
|
|
43
|
+
outputFileID,
|
|
44
|
+
"file://" + os.path.abspath(os.path.join(ioFileDirectory, "out.txt")),
|
|
45
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import time
|
|
3
|
+
from multiprocessing import Process
|
|
4
|
+
|
|
5
|
+
from toil.common import Toil
|
|
6
|
+
from toil.job import Job
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def think(seconds):
|
|
10
|
+
start = time.time()
|
|
11
|
+
while time.time() - start < seconds:
|
|
12
|
+
# Use CPU
|
|
13
|
+
math.sqrt(123456)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TimeWaster(Job):
|
|
17
|
+
def __init__(self, time_to_think, time_to_waste, space_to_waste, *args, **kwargs):
|
|
18
|
+
self.time_to_think = time_to_think
|
|
19
|
+
self.time_to_waste = time_to_waste
|
|
20
|
+
self.space_to_waste = space_to_waste
|
|
21
|
+
super().__init__(*args, **kwargs)
|
|
22
|
+
|
|
23
|
+
def run(self, fileStore):
|
|
24
|
+
# Waste some space
|
|
25
|
+
file_path = fileStore.getLocalTempFile()
|
|
26
|
+
with open(file_path, "w") as stream:
|
|
27
|
+
for i in range(self.space_to_waste):
|
|
28
|
+
stream.write("X")
|
|
29
|
+
|
|
30
|
+
# Do some "useful" compute
|
|
31
|
+
processes = []
|
|
32
|
+
for core_number in range(max(1, self.cores)):
|
|
33
|
+
# Use all the assigned cores to think
|
|
34
|
+
p = Process(target=think, args=(self.time_to_think,))
|
|
35
|
+
p.start()
|
|
36
|
+
processes.append(p)
|
|
37
|
+
for p in processes:
|
|
38
|
+
p.join()
|
|
39
|
+
|
|
40
|
+
# Also waste some time
|
|
41
|
+
time.sleep(self.time_to_waste)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def main():
|
|
45
|
+
options = Job.Runner.getDefaultArgumentParser().parse_args()
|
|
46
|
+
|
|
47
|
+
job1 = TimeWaster(0, 0, 0, displayName="doNothing")
|
|
48
|
+
job2 = TimeWaster(10, 0, 4096, displayName="efficientJob")
|
|
49
|
+
job3 = TimeWaster(10, 0, 1024, cores=4, displayName="multithreadedJob")
|
|
50
|
+
job4 = TimeWaster(1, 9, 65536, displayName="inefficientJob")
|
|
51
|
+
|
|
52
|
+
job1.addChild(job2)
|
|
53
|
+
job1.addChild(job3)
|
|
54
|
+
job3.addChild(job4)
|
|
55
|
+
|
|
56
|
+
with Toil(options) as toil:
|
|
57
|
+
if not toil.options.restart:
|
|
58
|
+
toil.start(job1)
|
|
59
|
+
else:
|
|
60
|
+
toil.restart()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
main()
|
toil/test/lib/aws/test_iam.py
CHANGED
|
@@ -19,7 +19,7 @@ import boto3
|
|
|
19
19
|
from moto import mock_aws
|
|
20
20
|
|
|
21
21
|
from toil.lib.aws import iam
|
|
22
|
-
from toil.test import ToilTest
|
|
22
|
+
from toil.test import ToilTest, needs_aws_s3
|
|
23
23
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
25
|
logging.basicConfig(level=logging.DEBUG)
|
|
@@ -70,6 +70,7 @@ class IAMTest(ToilTest):
|
|
|
70
70
|
assert iam.permission_matches_any("ec2:*", ["iam:*"]) is False
|
|
71
71
|
|
|
72
72
|
@mock_aws
|
|
73
|
+
@needs_aws_s3 # mock is incomplete, this avoid 'botocore.exceptions.NoCredentialsError: Unable to locate credentials'
|
|
73
74
|
def test_get_policy_permissions(self):
|
|
74
75
|
mock_iam = boto3.client("iam")
|
|
75
76
|
|
|
@@ -165,6 +166,7 @@ class IAMTest(ToilTest):
|
|
|
165
166
|
assert actions_set == expected_actions
|
|
166
167
|
assert notactions_set == set()
|
|
167
168
|
|
|
169
|
+
@needs_aws_s3
|
|
168
170
|
def test_create_delete_iam_role(self):
|
|
169
171
|
region = "us-west-2"
|
|
170
172
|
role_name = f'test{str(uuid4()).replace("-", "")}'
|
toil/test/lib/dockerTest.py
CHANGED
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import logging
|
|
15
15
|
import os
|
|
16
|
+
from pathlib import Path
|
|
16
17
|
import signal
|
|
17
18
|
import time
|
|
19
|
+
from typing import Optional
|
|
18
20
|
import uuid
|
|
19
21
|
from threading import Thread
|
|
20
22
|
|
|
21
|
-
from docker.errors import ContainerError
|
|
23
|
+
from docker.errors import ContainerError # type: ignore[import-not-found]
|
|
22
24
|
from toil.common import Toil
|
|
23
25
|
from toil.exceptions import FailedJobsException
|
|
24
26
|
from toil.job import Job
|
|
@@ -30,31 +32,31 @@ from toil.lib.docker import (
|
|
|
30
32
|
containerIsRunning,
|
|
31
33
|
dockerKill,
|
|
32
34
|
)
|
|
33
|
-
from toil.test import
|
|
35
|
+
from toil.test import pneeds_docker as needs_docker, pslow as slow
|
|
36
|
+
|
|
37
|
+
import pytest
|
|
34
38
|
|
|
35
39
|
logger = logging.getLogger(__name__)
|
|
36
40
|
|
|
37
41
|
|
|
38
42
|
@needs_docker
|
|
39
|
-
|
|
43
|
+
@pytest.mark.docker
|
|
44
|
+
@pytest.mark.online
|
|
45
|
+
class TestDocker:
|
|
40
46
|
"""
|
|
41
47
|
Tests dockerCall and ensures no containers are left around.
|
|
42
|
-
When running tests you may optionally set the TOIL_TEST_TEMP environment
|
|
43
|
-
variable to the path of a directory where you want temporary test files be
|
|
44
|
-
placed. The directory will be created if it doesn't exist. The path may be
|
|
45
|
-
relative in which case it will be assumed to be relative to the project
|
|
46
|
-
root. If TOIL_TEST_TEMP is not defined, temporary files and directories will
|
|
47
|
-
be created in the system's default location for such files and any temporary
|
|
48
|
-
files or directories left over from tests will be removed automatically
|
|
49
|
-
removed during tear down.
|
|
50
|
-
Otherwise, left-over files will not be removed.
|
|
51
48
|
"""
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
self.tempDir = self._createTempDir(purpose="tempDir")
|
|
55
|
-
self.dockerTestLogLevel = "INFO"
|
|
50
|
+
dockerTestLogLevel = "INFO"
|
|
56
51
|
|
|
57
|
-
def testDockerClean(
|
|
52
|
+
def testDockerClean(
|
|
53
|
+
self,
|
|
54
|
+
tmp_path: Path,
|
|
55
|
+
caching: bool = False,
|
|
56
|
+
detached: bool = True,
|
|
57
|
+
rm: bool = True,
|
|
58
|
+
deferParam: Optional[int] = None,
|
|
59
|
+
) -> None:
|
|
58
60
|
"""
|
|
59
61
|
Run the test container that creates a file in the work dir, and sleeps
|
|
60
62
|
for 5 minutes.
|
|
@@ -72,16 +74,15 @@ class DockerTest(ToilTest):
|
|
|
72
74
|
# detached X R E X
|
|
73
75
|
# Neither X R E X
|
|
74
76
|
|
|
75
|
-
data_dir =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
os.makedirs(working_dir, exist_ok=True)
|
|
77
|
+
data_dir = tmp_path / "data"
|
|
78
|
+
data_dir.mkdir()
|
|
79
|
+
working_dir = tmp_path / "working"
|
|
80
|
+
working_dir.mkdir()
|
|
81
|
+
test_file = working_dir / "test.txt"
|
|
81
82
|
|
|
82
|
-
options = Job.Runner.getDefaultOptions(
|
|
83
|
+
options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
|
|
83
84
|
options.logLevel = self.dockerTestLogLevel
|
|
84
|
-
options.workDir = working_dir
|
|
85
|
+
options.workDir = str(working_dir)
|
|
85
86
|
options.clean = "always"
|
|
86
87
|
options.retryCount = 0 # we're expecting the job to fail so don't retry!
|
|
87
88
|
options.caching = caching
|
|
@@ -99,7 +100,7 @@ class DockerTest(ToilTest):
|
|
|
99
100
|
# and since it was created inside the container, it would have had
|
|
100
101
|
# uid and gid == 0 (root) which may cause problems when docker
|
|
101
102
|
# attempts to clean up the jobstore.
|
|
102
|
-
file_stats =
|
|
103
|
+
file_stats = test_file.stat()
|
|
103
104
|
assert file_stats.st_gid != 0
|
|
104
105
|
assert file_stats.st_uid != 0
|
|
105
106
|
|
|
@@ -124,104 +125,173 @@ class DockerTest(ToilTest):
|
|
|
124
125
|
# Clean up
|
|
125
126
|
try:
|
|
126
127
|
dockerKill(container_name, remove=True)
|
|
127
|
-
|
|
128
|
+
test_file.unlink()
|
|
128
129
|
except:
|
|
129
130
|
pass
|
|
130
131
|
|
|
131
|
-
def testDockerClean_CRx_FORGO(self):
|
|
132
|
-
self.testDockerClean(
|
|
132
|
+
def testDockerClean_CRx_FORGO(self, tmp_path: Path) -> None:
|
|
133
|
+
self.testDockerClean(
|
|
134
|
+
tmp_path, caching=False, detached=False, rm=True, deferParam=FORGO
|
|
135
|
+
)
|
|
133
136
|
|
|
134
|
-
def testDockerClean_CRx_STOP(self):
|
|
135
|
-
self.testDockerClean(
|
|
137
|
+
def testDockerClean_CRx_STOP(self, tmp_path: Path) -> None:
|
|
138
|
+
self.testDockerClean(
|
|
139
|
+
tmp_path, caching=False, detached=False, rm=True, deferParam=STOP
|
|
140
|
+
)
|
|
136
141
|
|
|
137
|
-
def testDockerClean_CRx_RM(self):
|
|
138
|
-
self.testDockerClean(
|
|
142
|
+
def testDockerClean_CRx_RM(self, tmp_path: Path) -> None:
|
|
143
|
+
self.testDockerClean(
|
|
144
|
+
tmp_path, caching=False, detached=False, rm=True, deferParam=RM
|
|
145
|
+
)
|
|
139
146
|
|
|
140
147
|
@slow
|
|
141
|
-
|
|
142
|
-
|
|
148
|
+
@pytest.mark.slow
|
|
149
|
+
def testDockerClean_CRx_None(self, tmp_path: Path) -> None:
|
|
150
|
+
self.testDockerClean(
|
|
151
|
+
tmp_path, caching=False, detached=False, rm=True, deferParam=None
|
|
152
|
+
)
|
|
143
153
|
|
|
144
154
|
@slow
|
|
145
|
-
|
|
146
|
-
|
|
155
|
+
@pytest.mark.slow
|
|
156
|
+
def testDockerClean_CxD_FORGO(self, tmp_path: Path) -> None:
|
|
157
|
+
self.testDockerClean(
|
|
158
|
+
tmp_path, caching=False, detached=True, rm=False, deferParam=FORGO
|
|
159
|
+
)
|
|
147
160
|
|
|
148
161
|
@slow
|
|
149
|
-
|
|
150
|
-
|
|
162
|
+
@pytest.mark.slow
|
|
163
|
+
def testDockerClean_CxD_STOP(self, tmp_path: Path) -> None:
|
|
164
|
+
self.testDockerClean(
|
|
165
|
+
tmp_path, caching=False, detached=True, rm=False, deferParam=STOP
|
|
166
|
+
)
|
|
151
167
|
|
|
152
168
|
@slow
|
|
153
|
-
|
|
154
|
-
|
|
169
|
+
@pytest.mark.slow
|
|
170
|
+
def testDockerClean_CxD_RM(self, tmp_path: Path) -> None:
|
|
171
|
+
self.testDockerClean(
|
|
172
|
+
tmp_path, caching=False, detached=True, rm=False, deferParam=RM
|
|
173
|
+
)
|
|
155
174
|
|
|
156
175
|
@slow
|
|
157
|
-
|
|
158
|
-
|
|
176
|
+
@pytest.mark.slow
|
|
177
|
+
def testDockerClean_CxD_None(self, tmp_path: Path) -> None:
|
|
178
|
+
self.testDockerClean(
|
|
179
|
+
tmp_path, caching=False, detached=True, rm=False, deferParam=None
|
|
180
|
+
)
|
|
159
181
|
|
|
160
182
|
@slow
|
|
161
|
-
|
|
162
|
-
|
|
183
|
+
@pytest.mark.slow
|
|
184
|
+
def testDockerClean_Cxx_FORGO(self, tmp_path: Path) -> None:
|
|
185
|
+
self.testDockerClean(
|
|
186
|
+
tmp_path, caching=False, detached=False, rm=False, deferParam=FORGO
|
|
187
|
+
)
|
|
163
188
|
|
|
164
189
|
@slow
|
|
165
|
-
|
|
166
|
-
|
|
190
|
+
@pytest.mark.slow
|
|
191
|
+
def testDockerClean_Cxx_STOP(self, tmp_path: Path) -> None:
|
|
192
|
+
self.testDockerClean(
|
|
193
|
+
tmp_path, caching=False, detached=False, rm=False, deferParam=STOP
|
|
194
|
+
)
|
|
167
195
|
|
|
168
196
|
@slow
|
|
169
|
-
|
|
170
|
-
|
|
197
|
+
@pytest.mark.slow
|
|
198
|
+
def testDockerClean_Cxx_RM(self, tmp_path: Path) -> None:
|
|
199
|
+
self.testDockerClean(
|
|
200
|
+
tmp_path, caching=False, detached=False, rm=False, deferParam=RM
|
|
201
|
+
)
|
|
171
202
|
|
|
172
203
|
@slow
|
|
173
|
-
|
|
174
|
-
|
|
204
|
+
@pytest.mark.slow
|
|
205
|
+
def testDockerClean_Cxx_None(self, tmp_path: Path) -> None:
|
|
206
|
+
self.testDockerClean(
|
|
207
|
+
tmp_path, caching=False, detached=False, rm=False, deferParam=None
|
|
208
|
+
)
|
|
175
209
|
|
|
176
210
|
@slow
|
|
177
|
-
|
|
178
|
-
|
|
211
|
+
@pytest.mark.slow
|
|
212
|
+
def testDockerClean_xRx_FORGO(self, tmp_path: Path) -> None:
|
|
213
|
+
self.testDockerClean(
|
|
214
|
+
tmp_path, caching=True, detached=False, rm=True, deferParam=FORGO
|
|
215
|
+
)
|
|
179
216
|
|
|
180
217
|
@slow
|
|
181
|
-
|
|
182
|
-
|
|
218
|
+
@pytest.mark.slow
|
|
219
|
+
def testDockerClean_xRx_STOP(self, tmp_path: Path) -> None:
|
|
220
|
+
self.testDockerClean(
|
|
221
|
+
tmp_path, caching=True, detached=False, rm=True, deferParam=STOP
|
|
222
|
+
)
|
|
183
223
|
|
|
184
224
|
@slow
|
|
185
|
-
|
|
186
|
-
|
|
225
|
+
@pytest.mark.slow
|
|
226
|
+
def testDockerClean_xRx_RM(self, tmp_path: Path) -> None:
|
|
227
|
+
self.testDockerClean(
|
|
228
|
+
tmp_path, caching=True, detached=False, rm=True, deferParam=RM
|
|
229
|
+
)
|
|
187
230
|
|
|
188
231
|
@slow
|
|
189
|
-
|
|
190
|
-
|
|
232
|
+
@pytest.mark.slow
|
|
233
|
+
def testDockerClean_xRx_None(self, tmp_path: Path) -> None:
|
|
234
|
+
self.testDockerClean(
|
|
235
|
+
tmp_path, caching=True, detached=False, rm=True, deferParam=None
|
|
236
|
+
)
|
|
191
237
|
|
|
192
238
|
@slow
|
|
193
|
-
|
|
194
|
-
|
|
239
|
+
@pytest.mark.slow
|
|
240
|
+
def testDockerClean_xxD_FORGO(self, tmp_path: Path) -> None:
|
|
241
|
+
self.testDockerClean(
|
|
242
|
+
tmp_path, caching=True, detached=True, rm=False, deferParam=FORGO
|
|
243
|
+
)
|
|
195
244
|
|
|
196
245
|
@slow
|
|
197
|
-
|
|
198
|
-
|
|
246
|
+
@pytest.mark.slow
|
|
247
|
+
def testDockerClean_xxD_STOP(self, tmp_path: Path) -> None:
|
|
248
|
+
self.testDockerClean(
|
|
249
|
+
tmp_path, caching=True, detached=True, rm=False, deferParam=STOP
|
|
250
|
+
)
|
|
199
251
|
|
|
200
252
|
@slow
|
|
201
|
-
|
|
202
|
-
|
|
253
|
+
@pytest.mark.slow
|
|
254
|
+
def testDockerClean_xxD_RM(self, tmp_path: Path) -> None:
|
|
255
|
+
self.testDockerClean(
|
|
256
|
+
tmp_path, caching=True, detached=True, rm=False, deferParam=RM
|
|
257
|
+
)
|
|
203
258
|
|
|
204
259
|
@slow
|
|
205
|
-
|
|
206
|
-
|
|
260
|
+
@pytest.mark.slow
|
|
261
|
+
def testDockerClean_xxD_None(self, tmp_path: Path) -> None:
|
|
262
|
+
self.testDockerClean(
|
|
263
|
+
tmp_path, caching=True, detached=True, rm=False, deferParam=None
|
|
264
|
+
)
|
|
207
265
|
|
|
208
266
|
@slow
|
|
209
|
-
|
|
210
|
-
|
|
267
|
+
@pytest.mark.slow
|
|
268
|
+
def testDockerClean_xxx_FORGO(self, tmp_path: Path) -> None:
|
|
269
|
+
self.testDockerClean(
|
|
270
|
+
tmp_path, caching=True, detached=False, rm=False, deferParam=FORGO
|
|
271
|
+
)
|
|
211
272
|
|
|
212
273
|
@slow
|
|
213
|
-
|
|
214
|
-
|
|
274
|
+
@pytest.mark.slow
|
|
275
|
+
def testDockerClean_xxx_STOP(self, tmp_path: Path) -> None:
|
|
276
|
+
self.testDockerClean(
|
|
277
|
+
tmp_path, caching=True, detached=False, rm=False, deferParam=STOP
|
|
278
|
+
)
|
|
215
279
|
|
|
216
280
|
@slow
|
|
217
|
-
|
|
218
|
-
|
|
281
|
+
@pytest.mark.slow
|
|
282
|
+
def testDockerClean_xxx_RM(self, tmp_path: Path) -> None:
|
|
283
|
+
self.testDockerClean(
|
|
284
|
+
tmp_path, caching=True, detached=False, rm=False, deferParam=RM
|
|
285
|
+
)
|
|
219
286
|
|
|
220
287
|
@slow
|
|
221
|
-
|
|
222
|
-
|
|
288
|
+
@pytest.mark.slow
|
|
289
|
+
def testDockerClean_xxx_None(self, tmp_path: Path) -> None:
|
|
290
|
+
self.testDockerClean(
|
|
291
|
+
tmp_path, caching=True, detached=False, rm=False, deferParam=None
|
|
292
|
+
)
|
|
223
293
|
|
|
224
|
-
def testDockerPipeChain(self, caching=False):
|
|
294
|
+
def testDockerPipeChain(self, tmp_path: Path, caching: bool = False) -> None:
|
|
225
295
|
r"""
|
|
226
296
|
Test for piping API for dockerCall(). Using this API (activated when
|
|
227
297
|
list of argument lists is given as parameters), commands a piped
|
|
@@ -229,9 +299,11 @@ class DockerTest(ToilTest):
|
|
|
229
299
|
ex: ``parameters=[ ['printf', 'x\n y\n'], ['wc', '-l'] ]`` should execute:
|
|
230
300
|
``printf 'x\n y\n' | wc -l``
|
|
231
301
|
"""
|
|
232
|
-
|
|
302
|
+
workdir = tmp_path / "workdir"
|
|
303
|
+
workdir.mkdir()
|
|
304
|
+
options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
|
|
233
305
|
options.logLevel = self.dockerTestLogLevel
|
|
234
|
-
options.workDir =
|
|
306
|
+
options.workDir = str(workdir)
|
|
235
307
|
options.clean = "always"
|
|
236
308
|
options.caching = caching
|
|
237
309
|
A = Job.wrapJobFn(_testDockerPipeChainFn)
|
|
@@ -240,38 +312,44 @@ class DockerTest(ToilTest):
|
|
|
240
312
|
rv = rv.decode("utf-8")
|
|
241
313
|
assert rv.strip() == "2"
|
|
242
314
|
|
|
243
|
-
def testDockerPipeChainErrorDetection(
|
|
315
|
+
def testDockerPipeChainErrorDetection(
|
|
316
|
+
self, tmp_path: Path, caching: bool = False
|
|
317
|
+
) -> None:
|
|
244
318
|
"""
|
|
245
319
|
By default, executing cmd1 | cmd2 | ... | cmdN, will only return an
|
|
246
320
|
error if cmdN fails. This can lead to all manor of errors being
|
|
247
321
|
silently missed. This tests to make sure that the piping API for
|
|
248
322
|
dockerCall() throws an exception if non-last commands in the chain fail.
|
|
249
323
|
"""
|
|
250
|
-
|
|
324
|
+
workdir = tmp_path / "workdir"
|
|
325
|
+
workdir.mkdir()
|
|
326
|
+
options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
|
|
251
327
|
options.logLevel = self.dockerTestLogLevel
|
|
252
|
-
options.workDir =
|
|
328
|
+
options.workDir = str(workdir)
|
|
253
329
|
options.clean = "always"
|
|
254
330
|
options.caching = caching
|
|
255
331
|
A = Job.wrapJobFn(_testDockerPipeChainErrorFn)
|
|
256
332
|
rv = Job.Runner.startToil(A, options)
|
|
257
333
|
assert rv is True
|
|
258
334
|
|
|
259
|
-
def testNonCachingDockerChain(self):
|
|
260
|
-
self.testDockerPipeChain(caching=True)
|
|
335
|
+
def testNonCachingDockerChain(self, tmp_path: Path) -> None:
|
|
336
|
+
self.testDockerPipeChain(tmp_path, caching=True)
|
|
261
337
|
|
|
262
|
-
def testNonCachingDockerChainErrorDetection(self):
|
|
263
|
-
self.testDockerPipeChainErrorDetection(caching=True)
|
|
338
|
+
def testNonCachingDockerChainErrorDetection(self, tmp_path: Path) -> None:
|
|
339
|
+
self.testDockerPipeChainErrorDetection(tmp_path, caching=True)
|
|
264
340
|
|
|
265
|
-
def testDockerLogs(
|
|
341
|
+
def testDockerLogs(
|
|
342
|
+
self, tmp_path: Path, stream: bool = False, demux: bool = False
|
|
343
|
+
) -> None:
|
|
266
344
|
"""Test for the different log outputs when deatch=False."""
|
|
267
345
|
|
|
268
|
-
working_dir =
|
|
269
|
-
|
|
270
|
-
|
|
346
|
+
working_dir = tmp_path / "working"
|
|
347
|
+
working_dir.mkdir()
|
|
348
|
+
script_file = working_dir / "script.sh"
|
|
271
349
|
|
|
272
|
-
options = Job.Runner.getDefaultOptions(
|
|
350
|
+
options = Job.Runner.getDefaultOptions(tmp_path / "jobstore")
|
|
273
351
|
options.logLevel = self.dockerTestLogLevel
|
|
274
|
-
options.workDir = working_dir
|
|
352
|
+
options.workDir = str(working_dir)
|
|
275
353
|
options.clean = "always"
|
|
276
354
|
A = Job.wrapJobFn(
|
|
277
355
|
_testDockerLogsFn,
|
|
@@ -281,43 +359,42 @@ class DockerTest(ToilTest):
|
|
|
281
359
|
demux=demux,
|
|
282
360
|
)
|
|
283
361
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
assert rv is True
|
|
287
|
-
finally:
|
|
288
|
-
try:
|
|
289
|
-
os.remove(script_file)
|
|
290
|
-
except:
|
|
291
|
-
pass
|
|
362
|
+
rv = Job.Runner.startToil(A, options)
|
|
363
|
+
assert rv is True
|
|
292
364
|
|
|
293
|
-
def testDockerLogs_Stream(self):
|
|
294
|
-
self.testDockerLogs(stream=True, demux=False)
|
|
365
|
+
def testDockerLogs_Stream(self, tmp_path: Path) -> None:
|
|
366
|
+
self.testDockerLogs(tmp_path, stream=True, demux=False)
|
|
295
367
|
|
|
296
|
-
def testDockerLogs_Demux(self):
|
|
297
|
-
self.testDockerLogs(stream=False, demux=True)
|
|
368
|
+
def testDockerLogs_Demux(self, tmp_path: Path) -> None:
|
|
369
|
+
self.testDockerLogs(tmp_path, stream=False, demux=True)
|
|
298
370
|
|
|
299
|
-
def testDockerLogs_Demux_Stream(self):
|
|
300
|
-
self.testDockerLogs(stream=True, demux=True)
|
|
371
|
+
def testDockerLogs_Demux_Stream(self, tmp_path: Path) -> None:
|
|
372
|
+
self.testDockerLogs(tmp_path, stream=True, demux=True)
|
|
301
373
|
|
|
302
374
|
|
|
303
375
|
def _testDockerCleanFn(
|
|
304
|
-
job
|
|
305
|
-
|
|
376
|
+
job: Job,
|
|
377
|
+
working_dir: Path,
|
|
378
|
+
detached: bool = True,
|
|
379
|
+
rm: Optional[bool] = None,
|
|
380
|
+
deferParam: Optional[int] = None,
|
|
381
|
+
containerName: Optional[str] = None,
|
|
382
|
+
) -> None:
|
|
306
383
|
"""
|
|
307
384
|
Test function for test docker_clean. Runs a container with given flags and
|
|
308
385
|
then dies leaving behind a zombie container.
|
|
309
|
-
:param
|
|
386
|
+
:param job: job
|
|
310
387
|
:param working_dir: See `work_dir=` in :func:`dockerCall`
|
|
311
|
-
:param
|
|
312
|
-
:param
|
|
313
|
-
:param
|
|
314
|
-
:param
|
|
388
|
+
:param detached: See `detached=` in :func:`dockerCall`
|
|
389
|
+
:param rm: See `rm=` in :func:`dockerCall`
|
|
390
|
+
:param deferParam: See `deferParam=` in :func:`dockerCall`
|
|
391
|
+
:param containerName: See `container_name=` in :func:`dockerCall`
|
|
315
392
|
"""
|
|
316
393
|
|
|
317
|
-
def killSelf():
|
|
318
|
-
test_file =
|
|
394
|
+
def killSelf() -> None:
|
|
395
|
+
test_file = working_dir / "test.txt"
|
|
319
396
|
# Kill the worker once we are sure the docker container is started
|
|
320
|
-
while not
|
|
397
|
+
while not test_file.exists():
|
|
321
398
|
logger.debug("Waiting on the file created by spooky_container.")
|
|
322
399
|
time.sleep(1)
|
|
323
400
|
# By the time we reach here, we are sure the container is running.
|
|
@@ -331,8 +408,8 @@ def _testDockerCleanFn(
|
|
|
331
408
|
apiDockerCall(
|
|
332
409
|
job,
|
|
333
410
|
image="quay.io/ucsc_cgl/spooky_test",
|
|
334
|
-
working_dir=working_dir,
|
|
335
411
|
deferParam=deferParam,
|
|
412
|
+
working_dir=str(working_dir),
|
|
336
413
|
containerName=containerName,
|
|
337
414
|
detach=detached,
|
|
338
415
|
remove=rm,
|
|
@@ -340,7 +417,7 @@ def _testDockerCleanFn(
|
|
|
340
417
|
)
|
|
341
418
|
|
|
342
419
|
|
|
343
|
-
def _testDockerPipeChainFn(job):
|
|
420
|
+
def _testDockerPipeChainFn(job: Job) -> str:
|
|
344
421
|
"""Return the result of a simple pipe chain. Should be 2."""
|
|
345
422
|
parameters = [["printf", "x\n y\n"], ["wc", "-l"]]
|
|
346
423
|
return apiDockerCall(
|
|
@@ -351,7 +428,7 @@ def _testDockerPipeChainFn(job):
|
|
|
351
428
|
)
|
|
352
429
|
|
|
353
430
|
|
|
354
|
-
def _testDockerPipeChainErrorFn(job):
|
|
431
|
+
def _testDockerPipeChainErrorFn(job: Job) -> bool:
|
|
355
432
|
"""Return True if the command exit 1 | wc -l raises a ContainerError."""
|
|
356
433
|
parameters = [["exit", "1"], ["wc", "-l"]]
|
|
357
434
|
try:
|
|
@@ -361,7 +438,13 @@ def _testDockerPipeChainErrorFn(job):
|
|
|
361
438
|
return False
|
|
362
439
|
|
|
363
440
|
|
|
364
|
-
def _testDockerLogsFn(
|
|
441
|
+
def _testDockerLogsFn(
|
|
442
|
+
job: Job,
|
|
443
|
+
working_dir: Path,
|
|
444
|
+
script_file: Path,
|
|
445
|
+
stream: bool = False,
|
|
446
|
+
demux: bool = False,
|
|
447
|
+
) -> bool:
|
|
365
448
|
"""Return True if the test succeeds. Otherwise Exception is raised."""
|
|
366
449
|
|
|
367
450
|
# we write a script file because the redirection operator, '>&2', is wrapped
|
|
@@ -380,15 +463,15 @@ def _testDockerLogsFn(job, working_dir, script_file, stream=False, demux=False):
|
|
|
380
463
|
"""
|
|
381
464
|
)
|
|
382
465
|
|
|
383
|
-
with open(
|
|
466
|
+
with script_file.open("w") as file:
|
|
384
467
|
file.write(bash_script)
|
|
385
468
|
|
|
386
469
|
out = apiDockerCall(
|
|
387
470
|
job,
|
|
388
471
|
image="quay.io/ucsc_cgl/ubuntu:20.04",
|
|
389
|
-
working_dir=working_dir,
|
|
390
|
-
parameters=[script_file],
|
|
391
|
-
volumes={working_dir: {"bind": working_dir, "mode": "rw"}},
|
|
472
|
+
working_dir=str(working_dir),
|
|
473
|
+
parameters=[str(script_file)],
|
|
474
|
+
volumes={str(working_dir): {"bind": str(working_dir), "mode": "rw"}},
|
|
392
475
|
entrypoint="/bin/bash",
|
|
393
476
|
stdout=True,
|
|
394
477
|
stderr=True,
|