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
toil/test/lib/test_history.py
CHANGED
|
@@ -12,44 +12,42 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
from collections.abc import Generator
|
|
16
|
+
from pathlib import Path
|
|
16
17
|
import logging
|
|
17
|
-
import pytest
|
|
18
18
|
import time
|
|
19
|
-
from toil.test import ToilTest
|
|
20
19
|
|
|
21
20
|
from toil.lib.history import HistoryManager
|
|
22
21
|
|
|
22
|
+
import pytest
|
|
23
|
+
|
|
23
24
|
logger = logging.getLogger(__name__)
|
|
24
25
|
logging.basicConfig(level=logging.DEBUG)
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
|
|
28
|
+
class TestHistory:
|
|
27
29
|
"""
|
|
28
30
|
Tests for Toil history tracking.
|
|
29
31
|
|
|
30
32
|
Each test gets its own history database.
|
|
31
33
|
"""
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# Restore job history tracking flag
|
|
50
|
-
HistoryManager.JOB_HISTORY_ENABLED = self.original_flag
|
|
51
|
-
|
|
52
|
-
super().tearDown()
|
|
35
|
+
@pytest.fixture(autouse=True, scope="function")
|
|
36
|
+
def private_history_manager(
|
|
37
|
+
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
38
|
+
) -> Generator[None]:
|
|
39
|
+
try:
|
|
40
|
+
with monkeypatch.context() as m:
|
|
41
|
+
m.setattr(
|
|
42
|
+
HistoryManager,
|
|
43
|
+
"database_path_override",
|
|
44
|
+
str(tmp_path / "test-db.sqlite"),
|
|
45
|
+
)
|
|
46
|
+
m.setattr(HistoryManager, "enabled", lambda: True)
|
|
47
|
+
m.setattr(HistoryManager, "enabled_job", lambda: True)
|
|
48
|
+
yield
|
|
49
|
+
finally:
|
|
50
|
+
pass # no cleanup needed
|
|
53
51
|
|
|
54
52
|
def make_fake_workflow(self, workflow_id: str) -> None:
|
|
55
53
|
# Make a fake workflow
|
|
@@ -57,15 +55,17 @@ class HistoryTest(ToilTest):
|
|
|
57
55
|
HistoryManager.record_workflow_creation(workflow_id, workflow_jobstore_spec)
|
|
58
56
|
workflow_name = "SuperCoolWF"
|
|
59
57
|
workflow_trs_spec = "#wf:v1"
|
|
60
|
-
HistoryManager.record_workflow_metadata(
|
|
61
|
-
|
|
58
|
+
HistoryManager.record_workflow_metadata(
|
|
59
|
+
workflow_id, workflow_name, workflow_trs_spec
|
|
60
|
+
)
|
|
61
|
+
|
|
62
62
|
# Give it a job
|
|
63
63
|
workflow_attempt_number = 1
|
|
64
64
|
job_name = "DoThing"
|
|
65
65
|
succeeded = True
|
|
66
66
|
start_time = time.time()
|
|
67
67
|
runtime = 0.1
|
|
68
|
-
HistoryManager.record_job_attempt(
|
|
68
|
+
HistoryManager.record_job_attempt(
|
|
69
69
|
workflow_id,
|
|
70
70
|
workflow_attempt_number,
|
|
71
71
|
job_name,
|
|
@@ -93,92 +93,126 @@ class HistoryTest(ToilTest):
|
|
|
93
93
|
workflow_attempt_number = 1
|
|
94
94
|
|
|
95
95
|
# Make sure we have data
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
assert HistoryManager.count_workflows() == 1
|
|
97
|
+
assert HistoryManager.count_workflow_attempts() == 1
|
|
98
|
+
assert HistoryManager.count_job_attempts() == 1
|
|
99
99
|
|
|
100
100
|
# Make sure we see it as submittable
|
|
101
|
-
submittable_workflow_attempts =
|
|
102
|
-
|
|
101
|
+
submittable_workflow_attempts = (
|
|
102
|
+
HistoryManager.get_submittable_workflow_attempts()
|
|
103
|
+
)
|
|
104
|
+
assert len(submittable_workflow_attempts) == 1
|
|
103
105
|
|
|
104
106
|
# Make sure we see its jobs as submittable
|
|
105
|
-
with_submittable_job_attempts =
|
|
106
|
-
|
|
107
|
+
with_submittable_job_attempts = (
|
|
108
|
+
HistoryManager.get_workflow_attempts_with_submittable_job_attempts()
|
|
109
|
+
)
|
|
110
|
+
assert len(with_submittable_job_attempts) == 1
|
|
107
111
|
|
|
108
112
|
# Make sure we actually see the job
|
|
109
|
-
submittable_job_attempts = HistoryManager.get_unsubmitted_job_attempts(
|
|
110
|
-
|
|
113
|
+
submittable_job_attempts = HistoryManager.get_unsubmitted_job_attempts(
|
|
114
|
+
workflow_id, workflow_attempt_number
|
|
115
|
+
)
|
|
116
|
+
assert len(submittable_job_attempts) == 1
|
|
111
117
|
|
|
112
118
|
# Pretend we submitted them.
|
|
113
|
-
HistoryManager.mark_job_attempts_submitted(
|
|
114
|
-
|
|
119
|
+
HistoryManager.mark_job_attempts_submitted(
|
|
120
|
+
[j.id for j in submittable_job_attempts]
|
|
121
|
+
)
|
|
122
|
+
HistoryManager.mark_workflow_attempt_submitted(
|
|
123
|
+
workflow_id, workflow_attempt_number
|
|
124
|
+
)
|
|
115
125
|
|
|
116
126
|
# Make sure they are no longer matching
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
127
|
+
assert len(HistoryManager.get_submittable_workflow_attempts()) == 0
|
|
128
|
+
assert (
|
|
129
|
+
len(HistoryManager.get_workflow_attempts_with_submittable_job_attempts())
|
|
130
|
+
== 0
|
|
131
|
+
)
|
|
132
|
+
assert (
|
|
133
|
+
len(
|
|
134
|
+
HistoryManager.get_unsubmitted_job_attempts(
|
|
135
|
+
workflow_id, workflow_attempt_number
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
== 0
|
|
139
|
+
)
|
|
120
140
|
|
|
121
141
|
# Make sure we still have data
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
142
|
+
assert HistoryManager.count_workflows() == 1
|
|
143
|
+
assert HistoryManager.count_workflow_attempts() == 1
|
|
144
|
+
assert HistoryManager.count_job_attempts() == 1
|
|
125
145
|
|
|
126
146
|
def test_history_deletion(self) -> None:
|
|
127
147
|
workflow_id = "123"
|
|
128
148
|
self.make_fake_workflow(workflow_id)
|
|
129
149
|
workflow_attempt_number = 1
|
|
130
|
-
|
|
150
|
+
|
|
131
151
|
# Make sure we can see the workflow for deletion by age but not by done-ness
|
|
132
|
-
|
|
133
|
-
|
|
152
|
+
assert len(HistoryManager.get_oldest_workflow_ids()) == 1
|
|
153
|
+
assert len(HistoryManager.get_fully_submitted_workflow_ids()) == 0
|
|
134
154
|
|
|
135
155
|
# Pretend we submitted the workflow.
|
|
136
|
-
HistoryManager.mark_job_attempts_submitted(
|
|
137
|
-
|
|
156
|
+
HistoryManager.mark_job_attempts_submitted(
|
|
157
|
+
[
|
|
158
|
+
j.id
|
|
159
|
+
for j in HistoryManager.get_unsubmitted_job_attempts(
|
|
160
|
+
workflow_id, workflow_attempt_number
|
|
161
|
+
)
|
|
162
|
+
]
|
|
163
|
+
)
|
|
164
|
+
HistoryManager.mark_workflow_attempt_submitted(
|
|
165
|
+
workflow_id, workflow_attempt_number
|
|
166
|
+
)
|
|
138
167
|
|
|
139
168
|
# Make sure we can see the workflow for deletion by done-ness
|
|
140
|
-
|
|
169
|
+
assert len(HistoryManager.get_fully_submitted_workflow_ids()) == 1
|
|
141
170
|
|
|
142
171
|
# Add a new workflow
|
|
143
172
|
other_workflow_id = "456"
|
|
144
173
|
self.make_fake_workflow(other_workflow_id)
|
|
145
174
|
|
|
146
175
|
# Make sure we can see the both for deletion by age but only one by done-ness
|
|
147
|
-
|
|
148
|
-
|
|
176
|
+
assert len(HistoryManager.get_oldest_workflow_ids()) == 2
|
|
177
|
+
assert len(HistoryManager.get_fully_submitted_workflow_ids()) == 1
|
|
149
178
|
|
|
150
179
|
# Make sure the older workflow is first.
|
|
151
|
-
|
|
180
|
+
assert HistoryManager.get_oldest_workflow_ids() == [
|
|
181
|
+
workflow_id,
|
|
182
|
+
other_workflow_id,
|
|
183
|
+
]
|
|
152
184
|
|
|
153
185
|
# Delete the new workflow
|
|
154
186
|
HistoryManager.delete_workflow(other_workflow_id)
|
|
155
187
|
|
|
156
188
|
# Make sure we can see the old one
|
|
157
|
-
|
|
158
|
-
|
|
189
|
+
assert HistoryManager.get_oldest_workflow_ids() == [workflow_id]
|
|
190
|
+
assert HistoryManager.get_fully_submitted_workflow_ids() == [workflow_id]
|
|
159
191
|
|
|
160
192
|
# Delete the old workflow
|
|
161
193
|
HistoryManager.delete_workflow(workflow_id)
|
|
162
194
|
|
|
163
195
|
# Make sure we have no data
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
196
|
+
assert HistoryManager.count_workflows() == 0
|
|
197
|
+
assert HistoryManager.count_workflow_attempts() == 0
|
|
198
|
+
assert HistoryManager.count_job_attempts() == 0
|
|
168
199
|
|
|
169
200
|
def test_history_size_limit(self) -> None:
|
|
170
201
|
"""
|
|
171
202
|
Make sure the database size can be controlled.
|
|
172
203
|
"""
|
|
173
204
|
|
|
174
|
-
for workflow_id in (
|
|
205
|
+
for workflow_id in (
|
|
206
|
+
"WorkflowThatTakesUpSomeSpace,ActuallyMoreThanTheLaterOnesTake" + str(i)
|
|
207
|
+
for i in range(10)
|
|
208
|
+
):
|
|
175
209
|
self.make_fake_workflow(workflow_id)
|
|
176
210
|
|
|
177
211
|
# We should see the workflows.
|
|
178
|
-
|
|
212
|
+
assert HistoryManager.count_workflows() == 10
|
|
179
213
|
# And they take up space.
|
|
180
214
|
small_size = HistoryManager.get_database_byte_size()
|
|
181
|
-
|
|
215
|
+
assert small_size > 0
|
|
182
216
|
|
|
183
217
|
# Add a bunch more
|
|
184
218
|
for workflow_id in ("WorkflowThatTakesUpSpace" + str(i) for i in range(50)):
|
|
@@ -187,26 +221,16 @@ class HistoryTest(ToilTest):
|
|
|
187
221
|
# We should see that this is now a much larger database
|
|
188
222
|
large_size = HistoryManager.get_database_byte_size()
|
|
189
223
|
logger.info("Increased database size from %s to %s", small_size, large_size)
|
|
190
|
-
|
|
191
|
-
|
|
224
|
+
large_size > small_size
|
|
225
|
+
|
|
192
226
|
# We should be able to shrink it back down
|
|
193
227
|
HistoryManager.enforce_byte_size_limit(small_size)
|
|
194
|
-
|
|
228
|
+
|
|
195
229
|
reduced_size = HistoryManager.get_database_byte_size()
|
|
196
230
|
logger.info("Decreased database size from %s to %s", large_size, reduced_size)
|
|
197
231
|
# The database should be small enough
|
|
198
|
-
|
|
232
|
+
reduced_size <= small_size
|
|
199
233
|
# There should still be some workflow attempts left in the smaller database (though probably not the first ones)
|
|
200
234
|
remaining_workflows = HistoryManager.count_workflows()
|
|
201
235
|
logger.info("Still have %s workflows", remaining_workflows)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
236
|
+
assert remaining_workflows > 0
|
|
@@ -28,6 +28,7 @@ from toil.provisioners import cluster_factory
|
|
|
28
28
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
29
29
|
from toil.test import (
|
|
30
30
|
ToilTest,
|
|
31
|
+
get_data,
|
|
31
32
|
integrative,
|
|
32
33
|
needs_aws_ec2,
|
|
33
34
|
needs_fetchable_appliance,
|
|
@@ -135,7 +136,7 @@ class AbstractAWSAutoscaleTest(AbstractClusterTest):
|
|
|
135
136
|
"""
|
|
136
137
|
return os.path.join(self.dataDir, filename)
|
|
137
138
|
|
|
138
|
-
def rsyncUtil(self, src, dest):
|
|
139
|
+
def rsyncUtil(self, src: str, dest: str) -> None:
|
|
139
140
|
subprocess.check_call(
|
|
140
141
|
[
|
|
141
142
|
"toil",
|
|
@@ -285,10 +286,11 @@ class AWSAutoscaleTest(AbstractAWSAutoscaleTest):
|
|
|
285
286
|
with open(fileToSort, "w") as f:
|
|
286
287
|
# Fixme: making this file larger causes the test to hang
|
|
287
288
|
f.write("01234567890123456789012345678901")
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
with get_data("test/sort/sort.py") as sort_py:
|
|
290
|
+
self.rsyncUtil(
|
|
291
|
+
sort_py,
|
|
292
|
+
":" + self.script(),
|
|
293
|
+
)
|
|
292
294
|
self.rsyncUtil(fileToSort, ":" + self.data("sortFile"))
|
|
293
295
|
os.unlink(fileToSort)
|
|
294
296
|
|
|
@@ -501,10 +503,11 @@ class AWSAutoscaleTestMultipleNodeTypes(AbstractAWSAutoscaleTest):
|
|
|
501
503
|
sseKeyFile = os.path.join(os.getcwd(), "keyFile")
|
|
502
504
|
with open(sseKeyFile, "w") as f:
|
|
503
505
|
f.write("01234567890123456789012345678901")
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
506
|
+
with get_data("test/sort/sort.py") as sort_py:
|
|
507
|
+
self.rsyncUtil(
|
|
508
|
+
sort_py,
|
|
509
|
+
":" + self.script(),
|
|
510
|
+
)
|
|
508
511
|
self.rsyncUtil(sseKeyFile, ":" + self.data("keyFile"))
|
|
509
512
|
os.unlink(sseKeyFile)
|
|
510
513
|
|
|
@@ -39,7 +39,7 @@ log = logging.getLogger(__name__)
|
|
|
39
39
|
class AbstractClusterTest(ToilTest):
|
|
40
40
|
def __init__(self, methodName: str) -> None:
|
|
41
41
|
super().__init__(methodName=methodName)
|
|
42
|
-
self.keyName = os.getenv("TOIL_AWS_KEYNAME").strip()
|
|
42
|
+
self.keyName = os.getenv("TOIL_AWS_KEYNAME", "id_rsa").strip()
|
|
43
43
|
self.clusterName = f"aws-provisioner-test-{uuid4()}"
|
|
44
44
|
self.leaderNodeType = "t2.medium"
|
|
45
45
|
self.clusterType = "mesos"
|
|
@@ -276,12 +276,12 @@ class CWLOnARMTest(AbstractClusterTest):
|
|
|
276
276
|
]
|
|
277
277
|
)
|
|
278
278
|
|
|
279
|
-
# Runs the
|
|
279
|
+
# Runs the TestCWLv12 on an ARM instance
|
|
280
280
|
self.sshUtil(
|
|
281
281
|
[
|
|
282
282
|
"bash",
|
|
283
283
|
"-c",
|
|
284
|
-
f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && pytest --log-cli-level DEBUG -r s src/toil/test/cwl/cwlTest.py::
|
|
284
|
+
f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && pytest --log-cli-level DEBUG -r s src/toil/test/cwl/cwlTest.py::TestCWLv12::test_run_conformance",
|
|
285
285
|
]
|
|
286
286
|
)
|
|
287
287
|
|
|
@@ -289,5 +289,5 @@ class CWLOnARMTest(AbstractClusterTest):
|
|
|
289
289
|
# Bring it back to be an artifact.
|
|
290
290
|
self.rsync_util(
|
|
291
291
|
f":{self.cwl_test_dir}/toil/conformance-1.2.junit.xml",
|
|
292
|
-
|
|
292
|
+
str(self._rootpath / "arm-conformance-1.2.junit.xml"),
|
|
293
293
|
)
|
|
@@ -21,6 +21,7 @@ import pytest
|
|
|
21
21
|
|
|
22
22
|
from toil.test import (
|
|
23
23
|
ToilTest,
|
|
24
|
+
get_data,
|
|
24
25
|
integrative,
|
|
25
26
|
needs_fetchable_appliance,
|
|
26
27
|
needs_google_project,
|
|
@@ -214,10 +215,11 @@ class GCEAutoscaleTest(AbstractGCEAutoscaleTest):
|
|
|
214
215
|
with open(fileToSort, "w") as f:
|
|
215
216
|
# Fixme: making this file larger causes the test to hang
|
|
216
217
|
f.write("01234567890123456789012345678901")
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
218
|
+
with get_data("test/sort/sort.py") as sort_py:
|
|
219
|
+
self.rsyncUtil(
|
|
220
|
+
sort_py,
|
|
221
|
+
":/home/sort.py",
|
|
222
|
+
)
|
|
221
223
|
self.rsyncUtil(fileToSort, ":/home/sortFile")
|
|
222
224
|
os.unlink(fileToSort)
|
|
223
225
|
|
|
@@ -324,10 +326,11 @@ class GCEAutoscaleTestMultipleNodeTypes(AbstractGCEAutoscaleTest):
|
|
|
324
326
|
sseKeyFile = os.path.join(os.getcwd(), "keyFile")
|
|
325
327
|
with open(sseKeyFile, "w") as f:
|
|
326
328
|
f.write("01234567890123456789012345678901")
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
with get_data("test/sort/sort.py") as sort_py:
|
|
330
|
+
self.rsyncUtil(
|
|
331
|
+
sort_py,
|
|
332
|
+
":/home/sort.py",
|
|
333
|
+
)
|
|
331
334
|
self.rsyncUtil(sseKeyFile, ":/home/keyFile")
|
|
332
335
|
os.unlink(sseKeyFile)
|
|
333
336
|
|
|
@@ -376,12 +379,11 @@ class GCERestartTest(AbstractGCEAutoscaleTest):
|
|
|
376
379
|
self.jobStore = f"google:{self.projectID}:restart-{uuid4()}"
|
|
377
380
|
|
|
378
381
|
def _getScript(self):
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
)
|
|
382
|
+
with get_data("test/provisioners/restartScript.py") as restartScript:
|
|
383
|
+
self.rsyncUtil(
|
|
384
|
+
restartScript,
|
|
385
|
+
":" + self.scriptName,
|
|
386
|
+
)
|
|
385
387
|
|
|
386
388
|
def _runScript(self, toilOptions):
|
|
387
389
|
# clean = onSuccess
|
toil/test/sort/sort.py
CHANGED
|
@@ -23,6 +23,7 @@ from configargparse import ArgumentParser
|
|
|
23
23
|
|
|
24
24
|
from toil.common import Toil
|
|
25
25
|
from toil.job import Job
|
|
26
|
+
from toil.lib.misc import StrPath
|
|
26
27
|
from toil.realtimeLogger import RealtimeLogger
|
|
27
28
|
|
|
28
29
|
defaultLines = 1000
|
|
@@ -207,7 +208,9 @@ def getMidPoint(file, fileStart, fileEnd):
|
|
|
207
208
|
return len(line) + fileStart - 1
|
|
208
209
|
|
|
209
210
|
|
|
210
|
-
def makeFileToSort(
|
|
211
|
+
def makeFileToSort(
|
|
212
|
+
fileName: StrPath, lines: int = defaultLines, lineLen: int = defaultLineLen
|
|
213
|
+
) -> None:
|
|
211
214
|
with open(fileName, "w") as f:
|
|
212
215
|
for _ in range(lines):
|
|
213
216
|
line = (
|
toil/test/src/busTest.py
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
import logging
|
|
16
16
|
import os
|
|
17
|
+
from pathlib import Path
|
|
17
18
|
from threading import Thread, current_thread
|
|
19
|
+
from typing import NoReturn
|
|
18
20
|
|
|
19
21
|
from toil.batchSystems.abstractBatchSystem import BatchJobExitReason
|
|
20
22
|
from toil.bus import (
|
|
@@ -26,18 +28,17 @@ from toil.bus import (
|
|
|
26
28
|
from toil.common import Toil
|
|
27
29
|
from toil.exceptions import FailedJobsException
|
|
28
30
|
from toil.job import Job
|
|
29
|
-
from toil.test import ToilTest, get_temp_file
|
|
30
31
|
|
|
31
32
|
logger = logging.getLogger(__name__)
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
class
|
|
35
|
+
class TestMessageBus:
|
|
35
36
|
|
|
36
|
-
def test_enum_ints_in_file(self) -> None:
|
|
37
|
+
def test_enum_ints_in_file(self, tmp_path: Path) -> None:
|
|
37
38
|
"""
|
|
38
39
|
Make sure writing bus messages to files works with enums.
|
|
39
40
|
"""
|
|
40
|
-
bus_file =
|
|
41
|
+
bus_file = tmp_path / "bus"
|
|
41
42
|
|
|
42
43
|
bus = MessageBus()
|
|
43
44
|
# Connect the handler and hold the result to protect it from GC
|
|
@@ -73,7 +74,7 @@ class MessageBusTest(ToilTest):
|
|
|
73
74
|
# Message should always arrive in the main thread.
|
|
74
75
|
nonlocal message_count
|
|
75
76
|
logger.debug("Got message: %s", received)
|
|
76
|
-
|
|
77
|
+
assert current_thread() == main_thread
|
|
77
78
|
message_count += 1
|
|
78
79
|
|
|
79
80
|
bus.subscribe(JobIssuedMessage, handler)
|
|
@@ -101,28 +102,27 @@ class MessageBusTest(ToilTest):
|
|
|
101
102
|
t.join()
|
|
102
103
|
|
|
103
104
|
# We should ge tone message per thread, plus our own
|
|
104
|
-
|
|
105
|
+
assert box.count(JobIssuedMessage) == 11
|
|
105
106
|
# And having polled for those, our handler should have run
|
|
106
|
-
|
|
107
|
+
assert message_count == 11
|
|
107
108
|
|
|
108
|
-
def test_restart_without_bus_path(self) -> None:
|
|
109
|
+
def test_restart_without_bus_path(self, tmp_path: Path) -> None:
|
|
109
110
|
"""
|
|
110
111
|
Test the ability to restart a workflow when the message bus path used
|
|
111
112
|
by the previous attempt is gone.
|
|
112
113
|
"""
|
|
113
|
-
temp_dir =
|
|
114
|
-
|
|
114
|
+
temp_dir = tmp_path / "tempDir"
|
|
115
|
+
temp_dir.mkdir()
|
|
116
|
+
job_store = tmp_path / "jobstore"
|
|
115
117
|
|
|
116
|
-
bus_holder_dir =
|
|
117
|
-
|
|
118
|
+
bus_holder_dir = temp_dir / "bus_holder"
|
|
119
|
+
bus_holder_dir.mkdir()
|
|
118
120
|
|
|
119
121
|
start_options = Job.Runner.getDefaultOptions(job_store)
|
|
120
122
|
start_options.logLevel = "DEBUG"
|
|
121
123
|
start_options.retryCount = 0
|
|
122
124
|
start_options.clean = "never"
|
|
123
|
-
start_options.write_messages =
|
|
124
|
-
os.path.join(bus_holder_dir, "messagebus.txt")
|
|
125
|
-
)
|
|
125
|
+
start_options.write_messages = str(bus_holder_dir / "messagebus.txt")
|
|
126
126
|
|
|
127
127
|
root = Job.wrapJobFn(failing_job_fn)
|
|
128
128
|
|
|
@@ -137,7 +137,7 @@ class MessageBusTest(ToilTest):
|
|
|
137
137
|
|
|
138
138
|
# Get rid of the bus
|
|
139
139
|
os.unlink(start_options.write_messages)
|
|
140
|
-
|
|
140
|
+
bus_holder_dir.rmdir()
|
|
141
141
|
|
|
142
142
|
logger.info("Making second attempt")
|
|
143
143
|
|
|
@@ -158,7 +158,7 @@ class MessageBusTest(ToilTest):
|
|
|
158
158
|
logger.info("Second attempt successfully failed")
|
|
159
159
|
|
|
160
160
|
|
|
161
|
-
def failing_job_fn(job: Job) ->
|
|
161
|
+
def failing_job_fn(job: Job) -> NoReturn:
|
|
162
162
|
"""
|
|
163
163
|
This function is guaranteed to fail.
|
|
164
164
|
"""
|