toil 7.0.0__py3-none-any.whl → 8.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 +121 -83
- toil/batchSystems/__init__.py +1 -0
- toil/batchSystems/abstractBatchSystem.py +137 -77
- toil/batchSystems/abstractGridEngineBatchSystem.py +211 -101
- toil/batchSystems/awsBatch.py +237 -128
- toil/batchSystems/cleanup_support.py +22 -16
- toil/batchSystems/contained_executor.py +30 -26
- toil/batchSystems/gridengine.py +85 -49
- toil/batchSystems/htcondor.py +164 -87
- toil/batchSystems/kubernetes.py +622 -386
- toil/batchSystems/local_support.py +17 -12
- toil/batchSystems/lsf.py +132 -79
- toil/batchSystems/lsfHelper.py +13 -11
- toil/batchSystems/mesos/__init__.py +41 -29
- toil/batchSystems/mesos/batchSystem.py +288 -149
- toil/batchSystems/mesos/executor.py +77 -49
- toil/batchSystems/mesos/test/__init__.py +31 -23
- toil/batchSystems/options.py +38 -29
- toil/batchSystems/registry.py +53 -19
- toil/batchSystems/singleMachine.py +293 -123
- toil/batchSystems/slurm.py +489 -137
- toil/batchSystems/torque.py +46 -32
- toil/bus.py +141 -73
- toil/common.py +630 -359
- toil/cwl/__init__.py +1 -1
- toil/cwl/cwltoil.py +1114 -532
- toil/cwl/utils.py +17 -22
- toil/deferred.py +62 -41
- toil/exceptions.py +5 -3
- toil/fileStores/__init__.py +5 -5
- toil/fileStores/abstractFileStore.py +88 -57
- toil/fileStores/cachingFileStore.py +711 -247
- toil/fileStores/nonCachingFileStore.py +113 -75
- toil/job.py +988 -315
- toil/jobStores/abstractJobStore.py +387 -243
- toil/jobStores/aws/jobStore.py +727 -403
- toil/jobStores/aws/utils.py +161 -109
- toil/jobStores/conftest.py +1 -0
- toil/jobStores/fileJobStore.py +289 -151
- toil/jobStores/googleJobStore.py +137 -70
- toil/jobStores/utils.py +36 -15
- toil/leader.py +614 -269
- toil/lib/accelerators.py +115 -18
- toil/lib/aws/__init__.py +55 -28
- toil/lib/aws/ami.py +122 -87
- toil/lib/aws/iam.py +284 -108
- toil/lib/aws/s3.py +31 -0
- toil/lib/aws/session.py +193 -58
- toil/lib/aws/utils.py +238 -218
- toil/lib/bioio.py +13 -5
- toil/lib/compatibility.py +11 -6
- toil/lib/conversions.py +83 -49
- toil/lib/docker.py +131 -103
- toil/lib/ec2.py +322 -209
- toil/lib/ec2nodes.py +174 -106
- toil/lib/encryption/_dummy.py +5 -3
- toil/lib/encryption/_nacl.py +10 -6
- toil/lib/encryption/conftest.py +1 -0
- toil/lib/exceptions.py +26 -7
- toil/lib/expando.py +4 -2
- toil/lib/ftp_utils.py +217 -0
- toil/lib/generatedEC2Lists.py +127 -19
- toil/lib/humanize.py +6 -2
- toil/lib/integration.py +341 -0
- toil/lib/io.py +99 -11
- toil/lib/iterables.py +4 -2
- toil/lib/memoize.py +12 -8
- toil/lib/misc.py +65 -18
- toil/lib/objects.py +2 -2
- toil/lib/resources.py +19 -7
- toil/lib/retry.py +115 -77
- toil/lib/threading.py +282 -80
- toil/lib/throttle.py +15 -14
- toil/options/common.py +834 -401
- toil/options/cwl.py +175 -90
- toil/options/runner.py +50 -0
- toil/options/wdl.py +70 -19
- toil/provisioners/__init__.py +111 -46
- toil/provisioners/abstractProvisioner.py +322 -157
- toil/provisioners/aws/__init__.py +62 -30
- toil/provisioners/aws/awsProvisioner.py +980 -627
- toil/provisioners/clusterScaler.py +541 -279
- toil/provisioners/gceProvisioner.py +282 -179
- toil/provisioners/node.py +147 -79
- toil/realtimeLogger.py +34 -22
- toil/resource.py +137 -75
- toil/server/app.py +127 -61
- toil/server/celery_app.py +3 -1
- toil/server/cli/wes_cwl_runner.py +82 -53
- toil/server/utils.py +54 -28
- toil/server/wes/abstract_backend.py +64 -26
- toil/server/wes/amazon_wes_utils.py +21 -15
- toil/server/wes/tasks.py +121 -63
- toil/server/wes/toil_backend.py +142 -107
- toil/server/wsgi_app.py +4 -3
- toil/serviceManager.py +58 -22
- toil/statsAndLogging.py +148 -64
- toil/test/__init__.py +263 -179
- toil/test/batchSystems/batchSystemTest.py +438 -195
- toil/test/batchSystems/batch_system_plugin_test.py +18 -7
- toil/test/batchSystems/test_gridengine.py +173 -0
- toil/test/batchSystems/test_lsf_helper.py +67 -58
- toil/test/batchSystems/test_slurm.py +93 -47
- toil/test/cactus/test_cactus_integration.py +20 -22
- toil/test/cwl/cwlTest.py +271 -71
- toil/test/cwl/measure_default_memory.cwl +12 -0
- toil/test/cwl/not_run_required_input.cwl +29 -0
- toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
- toil/test/docs/scriptsTest.py +60 -34
- toil/test/jobStores/jobStoreTest.py +412 -235
- toil/test/lib/aws/test_iam.py +116 -48
- toil/test/lib/aws/test_s3.py +16 -9
- toil/test/lib/aws/test_utils.py +5 -6
- toil/test/lib/dockerTest.py +118 -141
- toil/test/lib/test_conversions.py +113 -115
- toil/test/lib/test_ec2.py +57 -49
- toil/test/lib/test_integration.py +104 -0
- toil/test/lib/test_misc.py +12 -5
- toil/test/mesos/MesosDataStructuresTest.py +23 -10
- toil/test/mesos/helloWorld.py +7 -6
- toil/test/mesos/stress.py +25 -20
- toil/test/options/options.py +7 -2
- toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
- toil/test/provisioners/clusterScalerTest.py +440 -250
- toil/test/provisioners/clusterTest.py +81 -42
- toil/test/provisioners/gceProvisionerTest.py +174 -100
- toil/test/provisioners/provisionerTest.py +25 -13
- toil/test/provisioners/restartScript.py +5 -4
- toil/test/server/serverTest.py +188 -141
- toil/test/sort/restart_sort.py +137 -68
- toil/test/sort/sort.py +134 -66
- toil/test/sort/sortTest.py +91 -49
- toil/test/src/autoDeploymentTest.py +140 -100
- toil/test/src/busTest.py +20 -18
- toil/test/src/checkpointTest.py +8 -2
- toil/test/src/deferredFunctionTest.py +49 -35
- toil/test/src/dockerCheckTest.py +33 -26
- toil/test/src/environmentTest.py +20 -10
- toil/test/src/fileStoreTest.py +538 -271
- toil/test/src/helloWorldTest.py +7 -4
- toil/test/src/importExportFileTest.py +61 -31
- toil/test/src/jobDescriptionTest.py +32 -17
- toil/test/src/jobEncapsulationTest.py +2 -0
- toil/test/src/jobFileStoreTest.py +74 -50
- toil/test/src/jobServiceTest.py +187 -73
- toil/test/src/jobTest.py +120 -70
- toil/test/src/miscTests.py +19 -18
- toil/test/src/promisedRequirementTest.py +82 -36
- toil/test/src/promisesTest.py +7 -6
- toil/test/src/realtimeLoggerTest.py +6 -6
- toil/test/src/regularLogTest.py +71 -37
- toil/test/src/resourceTest.py +80 -49
- toil/test/src/restartDAGTest.py +36 -22
- toil/test/src/resumabilityTest.py +9 -2
- toil/test/src/retainTempDirTest.py +45 -14
- toil/test/src/systemTest.py +12 -8
- toil/test/src/threadingTest.py +44 -25
- toil/test/src/toilContextManagerTest.py +10 -7
- toil/test/src/userDefinedJobArgTypeTest.py +8 -5
- toil/test/src/workerTest.py +33 -16
- toil/test/utils/toilDebugTest.py +70 -58
- toil/test/utils/toilKillTest.py +4 -5
- toil/test/utils/utilsTest.py +239 -102
- toil/test/wdl/wdltoil_test.py +789 -148
- toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
- toil/toilState.py +52 -26
- toil/utils/toilConfig.py +13 -4
- toil/utils/toilDebugFile.py +44 -27
- toil/utils/toilDebugJob.py +85 -25
- toil/utils/toilDestroyCluster.py +11 -6
- toil/utils/toilKill.py +8 -3
- toil/utils/toilLaunchCluster.py +251 -145
- toil/utils/toilMain.py +37 -16
- toil/utils/toilRsyncCluster.py +27 -14
- toil/utils/toilSshCluster.py +45 -22
- toil/utils/toilStats.py +75 -36
- toil/utils/toilStatus.py +226 -119
- toil/utils/toilUpdateEC2Instances.py +3 -1
- toil/version.py +11 -11
- toil/wdl/utils.py +5 -5
- toil/wdl/wdltoil.py +3513 -1052
- toil/worker.py +269 -128
- toil-8.0.0.dist-info/METADATA +173 -0
- toil-8.0.0.dist-info/RECORD +253 -0
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
- toil-7.0.0.dist-info/METADATA +0 -158
- toil-7.0.0.dist-info/RECORD +0 -244
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/LICENSE +0 -0
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
toil/test/utils/utilsTest.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import logging
|
|
15
15
|
import os
|
|
16
|
+
import re
|
|
16
17
|
import shutil
|
|
17
18
|
import subprocess
|
|
18
19
|
import sys
|
|
@@ -22,7 +23,7 @@ from unittest.mock import patch
|
|
|
22
23
|
|
|
23
24
|
import pytest
|
|
24
25
|
|
|
25
|
-
pkg_root = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
|
26
|
+
pkg_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) # noqa
|
|
26
27
|
sys.path.insert(0, pkg_root) # noqa
|
|
27
28
|
|
|
28
29
|
import toil
|
|
@@ -30,14 +31,16 @@ from toil import resolveEntryPoint
|
|
|
30
31
|
from toil.common import Config, Toil
|
|
31
32
|
from toil.job import Job
|
|
32
33
|
from toil.lib.bioio import system
|
|
33
|
-
from toil.test import (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
from toil.test import (
|
|
35
|
+
ToilTest,
|
|
36
|
+
get_temp_file,
|
|
37
|
+
integrative,
|
|
38
|
+
needs_aws_ec2,
|
|
39
|
+
needs_cwl,
|
|
40
|
+
needs_docker,
|
|
41
|
+
needs_rsync3,
|
|
42
|
+
slow,
|
|
43
|
+
)
|
|
41
44
|
from toil.test.sort.sortTest import makeFileToSort
|
|
42
45
|
from toil.utils.toilStats import get_stats, process_data
|
|
43
46
|
from toil.utils.toilStatus import ToilStatus
|
|
@@ -57,7 +60,7 @@ class UtilsTest(ToilTest):
|
|
|
57
60
|
self.tempDir = self._createTempDir()
|
|
58
61
|
self.tempFile = get_temp_file(rootDir=self.tempDir)
|
|
59
62
|
self.outputFile = get_temp_file(rootDir=self.tempDir)
|
|
60
|
-
self.outputFile =
|
|
63
|
+
self.outputFile = "someSortedStuff.txt"
|
|
61
64
|
self.toilDir = os.path.join(self.tempDir, "jobstore")
|
|
62
65
|
self.assertFalse(os.path.exists(self.toilDir))
|
|
63
66
|
self.lines = 1000
|
|
@@ -71,19 +74,19 @@ class UtilsTest(ToilTest):
|
|
|
71
74
|
|
|
72
75
|
self.sort_workflow_cmd = [
|
|
73
76
|
python,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
f
|
|
77
|
-
f
|
|
78
|
-
f
|
|
79
|
-
|
|
77
|
+
"-m",
|
|
78
|
+
"toil.test.sort.sort",
|
|
79
|
+
f"file:{self.toilDir}",
|
|
80
|
+
f"--fileToSort={self.tempFile}",
|
|
81
|
+
f"--outputFile={self.outputFile}",
|
|
82
|
+
"--clean=never",
|
|
80
83
|
]
|
|
81
84
|
|
|
82
85
|
self.restart_sort_workflow_cmd = [
|
|
83
86
|
python,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
f
|
|
87
|
+
"-m",
|
|
88
|
+
"toil.test.sort.restart_sort",
|
|
89
|
+
f"file:{self.toilDir}",
|
|
87
90
|
]
|
|
88
91
|
|
|
89
92
|
def tearDown(self):
|
|
@@ -92,7 +95,11 @@ class UtilsTest(ToilTest):
|
|
|
92
95
|
if os.path.exists(self.toilDir):
|
|
93
96
|
shutil.rmtree(self.toilDir)
|
|
94
97
|
|
|
95
|
-
for f in [
|
|
98
|
+
for f in [
|
|
99
|
+
self.tempFile,
|
|
100
|
+
self.outputFile,
|
|
101
|
+
os.path.join(self.tempDir, "output.txt"),
|
|
102
|
+
]:
|
|
96
103
|
if os.path.exists(f):
|
|
97
104
|
os.remove(f)
|
|
98
105
|
|
|
@@ -100,26 +107,26 @@ class UtilsTest(ToilTest):
|
|
|
100
107
|
|
|
101
108
|
@property
|
|
102
109
|
def toilMain(self):
|
|
103
|
-
return resolveEntryPoint(
|
|
110
|
+
return resolveEntryPoint("toil")
|
|
104
111
|
|
|
105
112
|
@property
|
|
106
113
|
def cleanCommand(self):
|
|
107
|
-
return [self.toilMain,
|
|
114
|
+
return [self.toilMain, "clean", self.toilDir]
|
|
108
115
|
|
|
109
116
|
@property
|
|
110
117
|
def statsCommand(self):
|
|
111
|
-
return [self.toilMain,
|
|
118
|
+
return [self.toilMain, "stats", self.toilDir, "--pretty"]
|
|
112
119
|
|
|
113
120
|
def statusCommand(self, failIfNotComplete=False):
|
|
114
|
-
commandTokens = [self.toilMain,
|
|
121
|
+
commandTokens = [self.toilMain, "status", self.toilDir]
|
|
115
122
|
if failIfNotComplete:
|
|
116
|
-
commandTokens.append(
|
|
123
|
+
commandTokens.append("--failIfNotComplete")
|
|
117
124
|
return commandTokens
|
|
118
125
|
|
|
119
126
|
def test_config_functionality(self):
|
|
120
127
|
"""Ensure that creating and reading back the config file works"""
|
|
121
128
|
config_file = os.path.abspath("config.yaml")
|
|
122
|
-
config_command = [self.toilMain,
|
|
129
|
+
config_command = [self.toilMain, "config", config_file]
|
|
123
130
|
# make sure the command `toil config file_path` works
|
|
124
131
|
try:
|
|
125
132
|
subprocess.check_call(config_command)
|
|
@@ -130,12 +137,18 @@ class UtilsTest(ToilTest):
|
|
|
130
137
|
# make sure that toil can read from the generated config file
|
|
131
138
|
try:
|
|
132
139
|
parser.parse_args(["random_jobstore", "--config", config_file])
|
|
140
|
+
with open(config_file) as cm:
|
|
141
|
+
payload = cm.read()
|
|
142
|
+
expected = "workDir batchSystem symlinkImports defaultMemory retryCount"
|
|
143
|
+
assert all(
|
|
144
|
+
re.search(rf"^#*{ param }:", payload, re.MULTILINE)
|
|
145
|
+
for param in expected.split(" ")
|
|
146
|
+
), f"Generated config contains { expected }"
|
|
133
147
|
except SystemExit:
|
|
134
148
|
self.fail("Failed to parse the default generated config file!")
|
|
135
149
|
finally:
|
|
136
150
|
os.remove(config_file)
|
|
137
151
|
|
|
138
|
-
|
|
139
152
|
@needs_rsync3
|
|
140
153
|
@pytest.mark.timeout(1200)
|
|
141
154
|
@needs_aws_ec2
|
|
@@ -156,30 +169,63 @@ class UtilsTest(ToilTest):
|
|
|
156
169
|
:return:
|
|
157
170
|
"""
|
|
158
171
|
# TODO: Run these for the other clouds.
|
|
159
|
-
clusterName = f
|
|
160
|
-
keyName = os.getenv(
|
|
161
|
-
expected_owner = os.getenv(
|
|
172
|
+
clusterName = f"cluster-utils-test{uuid.uuid4()}"
|
|
173
|
+
keyName = os.getenv("TOIL_AWS_KEYNAME").strip() or "id_rsa"
|
|
174
|
+
expected_owner = os.getenv("TOIL_OWNER_TAG") or keyName
|
|
162
175
|
|
|
163
176
|
try:
|
|
164
177
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
178
|
+
|
|
165
179
|
aws_provisioner = AWSProvisioner.__module__
|
|
166
180
|
logger.debug(f"Found AWSProvisioner: {aws_provisioner}.")
|
|
167
181
|
|
|
168
182
|
# launch master with an assortment of custom tags
|
|
169
|
-
system(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
183
|
+
system(
|
|
184
|
+
[
|
|
185
|
+
self.toilMain,
|
|
186
|
+
"launch-cluster",
|
|
187
|
+
"--clusterType",
|
|
188
|
+
"mesos",
|
|
189
|
+
"-t",
|
|
190
|
+
"key1=value1",
|
|
191
|
+
"-t",
|
|
192
|
+
"key2=value2",
|
|
193
|
+
"--tag",
|
|
194
|
+
"key3=value3",
|
|
195
|
+
"--leaderNodeType=t2.medium",
|
|
196
|
+
"--keyPairName=" + keyName,
|
|
197
|
+
clusterName,
|
|
198
|
+
"--provisioner=aws",
|
|
199
|
+
"--zone=us-west-2a",
|
|
200
|
+
"--logLevel=DEBUG",
|
|
201
|
+
]
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
cluster = toil.provisioners.cluster_factory(
|
|
205
|
+
provisioner="aws", zone="us-west-2a", clusterName=clusterName
|
|
206
|
+
)
|
|
175
207
|
leader = cluster.getLeader()
|
|
176
208
|
|
|
177
209
|
# check that the leader carries the appropriate tags
|
|
178
|
-
tags = {
|
|
210
|
+
tags = {
|
|
211
|
+
"key1": "value1",
|
|
212
|
+
"key2": "value2",
|
|
213
|
+
"key3": "value3",
|
|
214
|
+
"Name": clusterName,
|
|
215
|
+
"Owner": expected_owner,
|
|
216
|
+
}
|
|
179
217
|
for key in tags:
|
|
180
218
|
self.assertEqual(leader.tags.get(key), tags[key])
|
|
181
219
|
finally:
|
|
182
|
-
system(
|
|
220
|
+
system(
|
|
221
|
+
[
|
|
222
|
+
self.toilMain,
|
|
223
|
+
"destroy-cluster",
|
|
224
|
+
"--zone=us-west-2a",
|
|
225
|
+
"--provisioner=aws",
|
|
226
|
+
clusterName,
|
|
227
|
+
]
|
|
228
|
+
)
|
|
183
229
|
|
|
184
230
|
@slow
|
|
185
231
|
def testUtilsSort(self):
|
|
@@ -188,19 +234,27 @@ class UtilsTest(ToilTest):
|
|
|
188
234
|
sort example with the --restart flag.
|
|
189
235
|
"""
|
|
190
236
|
# Get the sort command to run
|
|
191
|
-
toilCommand = [
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
237
|
+
toilCommand = [
|
|
238
|
+
sys.executable,
|
|
239
|
+
"-m",
|
|
240
|
+
toil.test.sort.sort.__name__,
|
|
241
|
+
self.toilDir,
|
|
242
|
+
"--logLevel=DEBUG",
|
|
243
|
+
"--fileToSort",
|
|
244
|
+
self.tempFile,
|
|
245
|
+
"--outputFile",
|
|
246
|
+
self.outputFile,
|
|
247
|
+
"--N",
|
|
248
|
+
str(self.N),
|
|
249
|
+
"--stats",
|
|
250
|
+
"--retryCount=2",
|
|
251
|
+
"--badWorker=0.5",
|
|
252
|
+
"--badWorkerFailInterval=0.05",
|
|
253
|
+
]
|
|
202
254
|
# Try restarting it to check that a JobStoreException is thrown
|
|
203
|
-
self.assertRaises(
|
|
255
|
+
self.assertRaises(
|
|
256
|
+
subprocess.CalledProcessError, system, toilCommand + ["--restart"]
|
|
257
|
+
)
|
|
204
258
|
# Check that trying to run it in restart mode does not create the jobStore
|
|
205
259
|
self.assertFalse(os.path.exists(self.toilDir))
|
|
206
260
|
|
|
@@ -209,9 +263,15 @@ class UtilsTest(ToilTest):
|
|
|
209
263
|
try:
|
|
210
264
|
system(toilCommand)
|
|
211
265
|
finished = True
|
|
212
|
-
except
|
|
266
|
+
except (
|
|
267
|
+
subprocess.CalledProcessError
|
|
268
|
+
): # This happens when the script fails due to having unfinished jobs
|
|
213
269
|
system(self.statusCommand())
|
|
214
|
-
self.assertRaises(
|
|
270
|
+
self.assertRaises(
|
|
271
|
+
subprocess.CalledProcessError,
|
|
272
|
+
system,
|
|
273
|
+
self.statusCommand(failIfNotComplete=True),
|
|
274
|
+
)
|
|
215
275
|
finished = False
|
|
216
276
|
self.assertTrue(os.path.exists(self.toilDir))
|
|
217
277
|
|
|
@@ -222,11 +282,17 @@ class UtilsTest(ToilTest):
|
|
|
222
282
|
totalTrys = 1
|
|
223
283
|
while not finished:
|
|
224
284
|
try:
|
|
225
|
-
system(toilCommand + [
|
|
285
|
+
system(toilCommand + ["--restart"])
|
|
226
286
|
finished = True
|
|
227
|
-
except
|
|
287
|
+
except (
|
|
288
|
+
subprocess.CalledProcessError
|
|
289
|
+
): # This happens when the script fails due to having unfinished jobs
|
|
228
290
|
system(self.statusCommand())
|
|
229
|
-
self.assertRaises(
|
|
291
|
+
self.assertRaises(
|
|
292
|
+
subprocess.CalledProcessError,
|
|
293
|
+
system,
|
|
294
|
+
self.statusCommand(failIfNotComplete=True),
|
|
295
|
+
)
|
|
230
296
|
if totalTrys > 16:
|
|
231
297
|
self.fail() # Exceeded a reasonable number of restarts
|
|
232
298
|
totalTrys += 1
|
|
@@ -254,17 +320,23 @@ class UtilsTest(ToilTest):
|
|
|
254
320
|
Tests the stats commands on a complete run of the stats test.
|
|
255
321
|
"""
|
|
256
322
|
# Get the sort command to run
|
|
257
|
-
toilCommand = [
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
323
|
+
toilCommand = [
|
|
324
|
+
sys.executable,
|
|
325
|
+
"-m",
|
|
326
|
+
toil.test.sort.sort.__name__,
|
|
327
|
+
self.toilDir,
|
|
328
|
+
"--logLevel=DEBUG",
|
|
329
|
+
"--fileToSort",
|
|
330
|
+
self.tempFile,
|
|
331
|
+
"--outputFile",
|
|
332
|
+
self.outputFile,
|
|
333
|
+
"--N",
|
|
334
|
+
str(self.N),
|
|
335
|
+
"--stats",
|
|
336
|
+
"--retryCount=99",
|
|
337
|
+
"--badWorker=0.5",
|
|
338
|
+
"--badWorkerFailInterval=0.01",
|
|
339
|
+
]
|
|
268
340
|
|
|
269
341
|
# Run the script for the first time
|
|
270
342
|
system(toilCommand)
|
|
@@ -283,8 +355,8 @@ class UtilsTest(ToilTest):
|
|
|
283
355
|
|
|
284
356
|
def testUnicodeSupport(self):
|
|
285
357
|
options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
|
|
286
|
-
options.clean =
|
|
287
|
-
options.logLevel =
|
|
358
|
+
options.clean = "always"
|
|
359
|
+
options.logLevel = "debug"
|
|
288
360
|
Job.Runner.startToil(Job.wrapFn(printUnicodeCharacter), options)
|
|
289
361
|
|
|
290
362
|
@slow
|
|
@@ -293,7 +365,7 @@ class UtilsTest(ToilTest):
|
|
|
293
365
|
Tests case where multiple jobs are run on 1 worker to ensure that all jobs report back their data
|
|
294
366
|
"""
|
|
295
367
|
options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
|
|
296
|
-
options.clean =
|
|
368
|
+
options.clean = "never"
|
|
297
369
|
options.stats = True
|
|
298
370
|
Job.Runner.startToil(RunTwoJobsPerWorker(), options)
|
|
299
371
|
config = Config()
|
|
@@ -301,28 +373,52 @@ class UtilsTest(ToilTest):
|
|
|
301
373
|
jobStore = Toil.resumeJobStore(config.jobStore)
|
|
302
374
|
stats = get_stats(jobStore)
|
|
303
375
|
collatedStats = process_data(jobStore.config, stats)
|
|
304
|
-
self.assertTrue(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
376
|
+
self.assertTrue(
|
|
377
|
+
len(collatedStats.job_types) == 2,
|
|
378
|
+
"Some jobs are not represented in the stats.",
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
def check_status(self, status, status_fn, process=None, seconds=20):
|
|
382
|
+
time_elapsed = 0.0
|
|
383
|
+
has_stopped = process.poll() is not None if process else False
|
|
384
|
+
current_status = status_fn(self.toilDir)
|
|
385
|
+
while current_status != status:
|
|
386
|
+
if has_stopped:
|
|
387
|
+
# If the process has stopped and the stratus is wrong, it will never be right.
|
|
388
|
+
self.assertEqual(
|
|
389
|
+
current_status,
|
|
390
|
+
status,
|
|
391
|
+
f"Process returned {process.returncode} without status reaching {status}; stuck at {current_status}",
|
|
392
|
+
)
|
|
393
|
+
logger.debug(
|
|
394
|
+
"Workflow is %s; waiting for %s (%s/%s elapsed)",
|
|
395
|
+
current_status,
|
|
396
|
+
status,
|
|
397
|
+
time_elapsed,
|
|
398
|
+
seconds
|
|
399
|
+
)
|
|
309
400
|
time.sleep(0.5)
|
|
310
|
-
|
|
311
|
-
if
|
|
312
|
-
|
|
313
|
-
|
|
401
|
+
time_elapsed += 0.5
|
|
402
|
+
has_stopped = process.poll() is not None if process else False
|
|
403
|
+
current_status = status_fn(self.toilDir)
|
|
404
|
+
if time_elapsed > seconds:
|
|
405
|
+
self.assertEqual(
|
|
406
|
+
current_status,
|
|
407
|
+
status,
|
|
408
|
+
f"Waited {seconds} seconds without status reaching {status}; stuck at {current_status}",
|
|
409
|
+
)
|
|
314
410
|
|
|
315
411
|
def testGetPIDStatus(self):
|
|
316
412
|
"""Test that ToilStatus.getPIDStatus() behaves as expected."""
|
|
317
413
|
wf = subprocess.Popen(self.sort_workflow_cmd)
|
|
318
|
-
self.check_status(
|
|
414
|
+
self.check_status("RUNNING", status_fn=ToilStatus.getPIDStatus, process=wf, seconds=60)
|
|
319
415
|
wf.wait()
|
|
320
|
-
self.check_status(
|
|
416
|
+
self.check_status("COMPLETED", status_fn=ToilStatus.getPIDStatus, process=wf, seconds=60)
|
|
321
417
|
|
|
322
418
|
# TODO: we need to reach into the FileJobStore's files and delete this
|
|
323
419
|
# shared file. We assume we know its internal layout.
|
|
324
|
-
os.remove(os.path.join(self.toilDir,
|
|
325
|
-
self.check_status(
|
|
420
|
+
os.remove(os.path.join(self.toilDir, "files/shared/pid.log"))
|
|
421
|
+
self.check_status("QUEUED", status_fn=ToilStatus.getPIDStatus, process=wf, seconds=60)
|
|
326
422
|
|
|
327
423
|
def testGetStatusFailedToilWF(self):
|
|
328
424
|
"""
|
|
@@ -331,41 +427,71 @@ class UtilsTest(ToilTest):
|
|
|
331
427
|
opportunity to test the 'RUNNING' functionality of getStatus().
|
|
332
428
|
"""
|
|
333
429
|
# --badWorker is set to force failure.
|
|
334
|
-
wf = subprocess.Popen(self.sort_workflow_cmd + [
|
|
335
|
-
self.check_status(
|
|
430
|
+
wf = subprocess.Popen(self.sort_workflow_cmd + ["--badWorker=1"])
|
|
431
|
+
self.check_status("RUNNING", status_fn=ToilStatus.getStatus, process=wf, seconds=60)
|
|
336
432
|
wf.wait()
|
|
337
|
-
self.check_status(
|
|
433
|
+
self.check_status("ERROR", status_fn=ToilStatus.getStatus, process=wf, seconds=60)
|
|
338
434
|
|
|
339
435
|
@needs_cwl
|
|
340
436
|
@needs_docker
|
|
341
437
|
def testGetStatusFailedCWLWF(self):
|
|
342
438
|
"""Test that ToilStatus.getStatus() behaves as expected with a failing CWL workflow."""
|
|
343
439
|
# --badWorker is set to force failure.
|
|
344
|
-
cmd = [
|
|
345
|
-
|
|
440
|
+
cmd = [
|
|
441
|
+
"toil-cwl-runner",
|
|
442
|
+
"--logDebug",
|
|
443
|
+
"--jobStore",
|
|
444
|
+
self.toilDir,
|
|
445
|
+
"--clean=never",
|
|
446
|
+
"--badWorker=1",
|
|
447
|
+
"src/toil/test/cwl/sorttool.cwl",
|
|
448
|
+
"--reverse",
|
|
449
|
+
"--input",
|
|
450
|
+
"src/toil/test/cwl/whale.txt",
|
|
451
|
+
f"--outdir={self.tempDir}",
|
|
452
|
+
]
|
|
453
|
+
logger.info("Run command: %s", " ".join(cmd))
|
|
346
454
|
wf = subprocess.Popen(cmd)
|
|
347
|
-
self.check_status(
|
|
455
|
+
self.check_status("RUNNING", status_fn=ToilStatus.getStatus, process=wf, seconds=60)
|
|
348
456
|
wf.wait()
|
|
349
|
-
self.check_status(
|
|
457
|
+
self.check_status("ERROR", status_fn=ToilStatus.getStatus, process=wf, seconds=60)
|
|
350
458
|
|
|
351
459
|
@needs_cwl
|
|
352
460
|
@needs_docker
|
|
353
461
|
def testGetStatusSuccessfulCWLWF(self):
|
|
354
462
|
"""Test that ToilStatus.getStatus() behaves as expected with a successful CWL workflow."""
|
|
355
|
-
cmd = [
|
|
356
|
-
|
|
463
|
+
cmd = [
|
|
464
|
+
"toil-cwl-runner",
|
|
465
|
+
"--jobStore",
|
|
466
|
+
self.toilDir,
|
|
467
|
+
"--clean=never",
|
|
468
|
+
"src/toil/test/cwl/sorttool.cwl",
|
|
469
|
+
"--reverse",
|
|
470
|
+
"--input",
|
|
471
|
+
"src/toil/test/cwl/whale.txt",
|
|
472
|
+
f"--outdir={self.tempDir}",
|
|
473
|
+
]
|
|
357
474
|
wf = subprocess.Popen(cmd)
|
|
358
|
-
self.check_status(
|
|
475
|
+
self.check_status("RUNNING", status_fn=ToilStatus.getStatus, process=wf, seconds=60)
|
|
359
476
|
wf.wait()
|
|
360
|
-
self.check_status(
|
|
477
|
+
self.check_status("COMPLETED", status_fn=ToilStatus.getStatus, process=wf, seconds=60)
|
|
361
478
|
|
|
362
479
|
@needs_cwl
|
|
363
|
-
@patch(
|
|
480
|
+
@patch("builtins.print")
|
|
364
481
|
def testPrintJobLog(self, mock_print):
|
|
365
482
|
"""Test that ToilStatus.printJobLog() reads the log from a failed command without error."""
|
|
366
483
|
# Run a workflow that will always fail
|
|
367
|
-
cmd = [
|
|
368
|
-
|
|
484
|
+
cmd = [
|
|
485
|
+
"toil-cwl-runner",
|
|
486
|
+
"--logDebug",
|
|
487
|
+
"--jobStore",
|
|
488
|
+
self.toilDir,
|
|
489
|
+
"--clean=never",
|
|
490
|
+
"src/toil/test/cwl/alwaysfails.cwl",
|
|
491
|
+
"--message",
|
|
492
|
+
"Testing",
|
|
493
|
+
]
|
|
494
|
+
logger.info("Run command: %s", " ".join(cmd))
|
|
369
495
|
wf = subprocess.Popen(cmd)
|
|
370
496
|
wf.wait()
|
|
371
497
|
# print log and check output
|
|
@@ -374,7 +500,7 @@ class UtilsTest(ToilTest):
|
|
|
374
500
|
|
|
375
501
|
# Make sure it printed some kind of complaint about the missing command.
|
|
376
502
|
args, kwargs = mock_print.call_args
|
|
377
|
-
self.assertIn(
|
|
503
|
+
self.assertIn("invalidcommand", args[0])
|
|
378
504
|
|
|
379
505
|
@pytest.mark.timeout(1200)
|
|
380
506
|
def testRestartAttribute(self):
|
|
@@ -384,17 +510,27 @@ class UtilsTest(ToilTest):
|
|
|
384
510
|
In this case, the job store should not be destroyed until restart() is called.
|
|
385
511
|
"""
|
|
386
512
|
# Run a workflow that will always fail
|
|
387
|
-
cmd = self.restart_sort_workflow_cmd + [
|
|
513
|
+
cmd = self.restart_sort_workflow_cmd + ["--badWorker=1", "--logDebug"]
|
|
388
514
|
subprocess.run(cmd)
|
|
389
515
|
|
|
390
|
-
restart_cmd = self.restart_sort_workflow_cmd + [
|
|
516
|
+
restart_cmd = self.restart_sort_workflow_cmd + [
|
|
517
|
+
"--badWorker=0",
|
|
518
|
+
"--logDebug",
|
|
519
|
+
"--restart",
|
|
520
|
+
]
|
|
391
521
|
subprocess.run(restart_cmd)
|
|
392
522
|
|
|
393
523
|
# Check the job store exists after restart attempt
|
|
394
524
|
self.assertTrue(os.path.exists(self.toilDir))
|
|
395
525
|
|
|
396
|
-
successful_cmd = [
|
|
397
|
-
|
|
526
|
+
successful_cmd = [
|
|
527
|
+
python,
|
|
528
|
+
"-m",
|
|
529
|
+
"toil.test.sort.sort",
|
|
530
|
+
"--logDebug",
|
|
531
|
+
"file:" + self.toilDir,
|
|
532
|
+
"--restart",
|
|
533
|
+
]
|
|
398
534
|
subprocess.run(successful_cmd)
|
|
399
535
|
|
|
400
536
|
# Check the job store is destroyed after calling restart()
|
|
@@ -405,13 +541,14 @@ def printUnicodeCharacter():
|
|
|
405
541
|
# We want to get a unicode character to stdout but we can't print it directly because of
|
|
406
542
|
# Python encoding issues. To work around this we print in a separate Python process. See
|
|
407
543
|
# http://stackoverflow.com/questions/492483/setting-the-correct-encoding-when-piping-stdout-in-python
|
|
408
|
-
subprocess.check_call([sys.executable,
|
|
544
|
+
subprocess.check_call([sys.executable, "-c", "print('\\xc3\\xbc')"])
|
|
409
545
|
|
|
410
546
|
|
|
411
547
|
class RunTwoJobsPerWorker(Job):
|
|
412
548
|
"""
|
|
413
549
|
Runs child job with same resources as self in an attempt to chain the jobs on the same worker
|
|
414
550
|
"""
|
|
551
|
+
|
|
415
552
|
def __init__(self):
|
|
416
553
|
Job.__init__(self)
|
|
417
554
|
|