toil 8.2.0__py3-none-any.whl → 9.1.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/batchSystems/abstractBatchSystem.py +13 -5
- toil/batchSystems/abstractGridEngineBatchSystem.py +17 -5
- toil/batchSystems/kubernetes.py +13 -2
- toil/batchSystems/mesos/batchSystem.py +33 -2
- toil/batchSystems/registry.py +15 -118
- toil/batchSystems/slurm.py +191 -16
- toil/common.py +20 -1
- toil/cwl/cwltoil.py +97 -119
- toil/cwl/utils.py +103 -3
- toil/fileStores/__init__.py +1 -1
- toil/fileStores/abstractFileStore.py +5 -2
- toil/fileStores/cachingFileStore.py +1 -1
- toil/job.py +30 -14
- toil/jobStores/abstractJobStore.py +35 -255
- toil/jobStores/aws/jobStore.py +864 -1964
- toil/jobStores/aws/utils.py +24 -270
- toil/jobStores/fileJobStore.py +2 -1
- toil/jobStores/googleJobStore.py +32 -13
- toil/jobStores/utils.py +0 -327
- toil/leader.py +27 -22
- toil/lib/accelerators.py +1 -1
- toil/lib/aws/config.py +22 -0
- toil/lib/aws/s3.py +477 -9
- toil/lib/aws/utils.py +22 -33
- toil/lib/checksum.py +88 -0
- toil/lib/conversions.py +33 -31
- toil/lib/directory.py +217 -0
- toil/lib/ec2.py +97 -29
- toil/lib/exceptions.py +2 -1
- toil/lib/expando.py +2 -2
- toil/lib/generatedEC2Lists.py +138 -19
- toil/lib/io.py +33 -2
- toil/lib/memoize.py +21 -7
- toil/lib/misc.py +1 -1
- toil/lib/pipes.py +385 -0
- toil/lib/plugins.py +106 -0
- toil/lib/retry.py +1 -1
- toil/lib/threading.py +1 -1
- toil/lib/url.py +320 -0
- toil/lib/web.py +4 -5
- toil/options/cwl.py +13 -1
- toil/options/runner.py +17 -10
- toil/options/wdl.py +12 -1
- toil/provisioners/__init__.py +5 -2
- toil/provisioners/aws/__init__.py +43 -36
- toil/provisioners/aws/awsProvisioner.py +47 -15
- toil/provisioners/node.py +60 -12
- toil/resource.py +3 -13
- toil/server/app.py +12 -6
- toil/server/cli/wes_cwl_runner.py +2 -2
- toil/server/wes/abstract_backend.py +21 -43
- toil/server/wes/toil_backend.py +2 -2
- toil/test/__init__.py +16 -18
- toil/test/batchSystems/batchSystemTest.py +2 -9
- toil/test/batchSystems/batch_system_plugin_test.py +7 -0
- toil/test/batchSystems/test_slurm.py +103 -14
- toil/test/cwl/cwlTest.py +181 -8
- toil/test/cwl/staging_cat.cwl +27 -0
- toil/test/cwl/staging_make_file.cwl +25 -0
- toil/test/cwl/staging_workflow.cwl +43 -0
- toil/test/cwl/zero_default.cwl +61 -0
- toil/test/docs/scripts/tutorial_staging.py +17 -8
- toil/test/docs/scriptsTest.py +2 -1
- toil/test/jobStores/jobStoreTest.py +23 -133
- toil/test/lib/aws/test_iam.py +7 -7
- toil/test/lib/aws/test_s3.py +30 -33
- toil/test/lib/aws/test_utils.py +9 -9
- toil/test/lib/test_url.py +69 -0
- toil/test/lib/url_plugin_test.py +105 -0
- toil/test/provisioners/aws/awsProvisionerTest.py +60 -7
- toil/test/provisioners/clusterTest.py +15 -2
- toil/test/provisioners/gceProvisionerTest.py +1 -1
- toil/test/server/serverTest.py +78 -36
- toil/test/src/autoDeploymentTest.py +2 -3
- toil/test/src/fileStoreTest.py +89 -87
- toil/test/utils/ABCWorkflowDebug/ABC.txt +1 -0
- toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +4 -4
- toil/test/utils/toilKillTest.py +35 -28
- toil/test/wdl/md5sum/md5sum-gs.json +1 -1
- toil/test/wdl/md5sum/md5sum.json +1 -1
- toil/test/wdl/testfiles/read_file.wdl +18 -0
- toil/test/wdl/testfiles/url_to_optional_file.wdl +2 -1
- toil/test/wdl/wdltoil_test.py +171 -162
- toil/test/wdl/wdltoil_test_kubernetes.py +9 -0
- toil/utils/toilDebugFile.py +6 -3
- toil/utils/toilSshCluster.py +23 -0
- toil/utils/toilStats.py +17 -2
- toil/utils/toilUpdateEC2Instances.py +1 -0
- toil/version.py +10 -10
- toil/wdl/wdltoil.py +1179 -825
- toil/worker.py +16 -8
- {toil-8.2.0.dist-info → toil-9.1.0.dist-info}/METADATA +32 -32
- {toil-8.2.0.dist-info → toil-9.1.0.dist-info}/RECORD +97 -85
- {toil-8.2.0.dist-info → toil-9.1.0.dist-info}/WHEEL +1 -1
- toil/lib/iterables.py +0 -112
- toil/test/docs/scripts/stagingExampleFiles/in.txt +0 -1
- {toil-8.2.0.dist-info → toil-9.1.0.dist-info}/entry_points.txt +0 -0
- {toil-8.2.0.dist-info → toil-9.1.0.dist-info}/licenses/LICENSE +0 -0
- {toil-8.2.0.dist-info → toil-9.1.0.dist-info}/top_level.txt +0 -0
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
import datetime
|
|
14
15
|
import logging
|
|
15
16
|
import os
|
|
16
17
|
import subprocess
|
|
@@ -24,13 +25,22 @@ from uuid import uuid4
|
|
|
24
25
|
|
|
25
26
|
import pytest
|
|
26
27
|
|
|
28
|
+
import toil.lib.aws.session
|
|
29
|
+
|
|
30
|
+
from toil.lib.aws import zone_to_region
|
|
27
31
|
from toil.provisioners import cluster_factory
|
|
28
32
|
from toil.provisioners.aws.awsProvisioner import AWSProvisioner
|
|
33
|
+
from toil.provisioners.aws import (
|
|
34
|
+
_get_spot_history,
|
|
35
|
+
get_aws_zone_from_spot_market,
|
|
36
|
+
get_best_aws_zone,
|
|
37
|
+
)
|
|
29
38
|
from toil.test import (
|
|
30
39
|
ToilTest,
|
|
31
40
|
get_data,
|
|
32
41
|
integrative,
|
|
33
42
|
needs_aws_ec2,
|
|
43
|
+
needs_aws_s3,
|
|
34
44
|
needs_fetchable_appliance,
|
|
35
45
|
needs_mesos,
|
|
36
46
|
slow,
|
|
@@ -53,10 +63,35 @@ if TYPE_CHECKING:
|
|
|
53
63
|
|
|
54
64
|
log = logging.getLogger(__name__)
|
|
55
65
|
|
|
66
|
+
@pytest.fixture
|
|
67
|
+
def aws_zone():
|
|
68
|
+
"""
|
|
69
|
+
Supply an appropriate AWS zone to work in to tests that need one.
|
|
70
|
+
"""
|
|
71
|
+
zone = get_best_aws_zone()
|
|
72
|
+
assert (
|
|
73
|
+
zone is not None
|
|
74
|
+
), "Could not determine AWS availability zone to test in; is TOIL_AWS_ZONE set?"
|
|
75
|
+
return zone
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def aws_region(aws_zone):
|
|
79
|
+
"""
|
|
80
|
+
Supply an appropriate AWS region to work in to tests that need one.
|
|
81
|
+
"""
|
|
82
|
+
return zone_to_region(aws_zone)
|
|
83
|
+
|
|
84
|
+
@pytest.fixture
|
|
85
|
+
def ec2_client(aws_region):
|
|
86
|
+
"""
|
|
87
|
+
Supply an AWS EC2 client tests that need one.
|
|
88
|
+
"""
|
|
89
|
+
return toil.lib.aws.session.client("ec2", aws_region)
|
|
90
|
+
|
|
56
91
|
|
|
57
|
-
class
|
|
92
|
+
class TestAWSProvisionerBenchTest:
|
|
58
93
|
"""
|
|
59
|
-
Tests for the AWS provisioner that don't actually provision
|
|
94
|
+
Tests for the AWS provisioner that don't actually provision instances.
|
|
60
95
|
"""
|
|
61
96
|
|
|
62
97
|
# Needs to talk to EC2 for image discovery
|
|
@@ -71,7 +106,8 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
71
106
|
assert ami.startswith("ami-")
|
|
72
107
|
|
|
73
108
|
@needs_aws_ec2
|
|
74
|
-
|
|
109
|
+
@needs_aws_s3
|
|
110
|
+
def test_read_write_global_files(self, aws_zone):
|
|
75
111
|
"""
|
|
76
112
|
Make sure the `_write_file_to_cloud()` and `_read_file_from_cloud()`
|
|
77
113
|
functions of the AWS provisioner work as intended.
|
|
@@ -79,7 +115,7 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
79
115
|
provisioner = AWSProvisioner(
|
|
80
116
|
f"aws-provisioner-test-{uuid4()}",
|
|
81
117
|
"mesos",
|
|
82
|
-
|
|
118
|
+
aws_zone,
|
|
83
119
|
50,
|
|
84
120
|
None,
|
|
85
121
|
None,
|
|
@@ -90,13 +126,30 @@ class AWSProvisionerBenchTest(ToilTest):
|
|
|
90
126
|
|
|
91
127
|
try:
|
|
92
128
|
url = provisioner._write_file_to_cloud(key, contents=contents)
|
|
93
|
-
|
|
129
|
+
assert url.startswith("s3://")
|
|
94
130
|
|
|
95
|
-
|
|
131
|
+
assert provisioner._read_file_from_cloud(key) == contents
|
|
96
132
|
finally:
|
|
97
133
|
# the cluster was never launched, but we need to clean up the s3 bucket
|
|
98
134
|
provisioner.destroyCluster()
|
|
99
135
|
|
|
136
|
+
@needs_aws_ec2
|
|
137
|
+
def test_get_spot_history(self, ec2_client) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Make sure that we can download spot price history from AWS.
|
|
140
|
+
"""
|
|
141
|
+
history = _get_spot_history(ec2_client, "t3.large")
|
|
142
|
+
# We should have 7 days of history, newest first.
|
|
143
|
+
|
|
144
|
+
@needs_aws_ec2
|
|
145
|
+
def test_get_aws_zone_from_spot_market(self, ec2_client) -> None:
|
|
146
|
+
"""
|
|
147
|
+
Make sure that we can process spot price history to pick a zone.
|
|
148
|
+
"""
|
|
149
|
+
zone_options = ["us-west-2a", "af-south-1c"]
|
|
150
|
+
zone_choice = get_aws_zone_from_spot_market(0.01, "t3.large", ec2_client, zone_options)
|
|
151
|
+
assert zone_choice in zone_options
|
|
152
|
+
|
|
100
153
|
|
|
101
154
|
@needs_aws_ec2
|
|
102
155
|
@needs_fetchable_appliance
|
|
@@ -526,7 +579,7 @@ class AWSAutoscaleTestMultipleNodeTypes(AbstractAWSAutoscaleTest):
|
|
|
526
579
|
runCommand = [
|
|
527
580
|
self.python(),
|
|
528
581
|
self.script(),
|
|
529
|
-
"--fileToSort=/
|
|
582
|
+
"--fileToSort=/etc/passwd",
|
|
530
583
|
"--sortMemory=0.6G",
|
|
531
584
|
"--mergeMemory=3.0G",
|
|
532
585
|
]
|
|
@@ -31,6 +31,8 @@ from toil.test import (
|
|
|
31
31
|
slow,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
+
from toil.test.cwl.cwlTest import TestCWLv12Conformance
|
|
35
|
+
|
|
34
36
|
log = logging.getLogger(__name__)
|
|
35
37
|
|
|
36
38
|
|
|
@@ -237,6 +239,17 @@ class CWLOnARMTest(AbstractClusterTest):
|
|
|
237
239
|
|
|
238
240
|
@needs_env_var("CI_COMMIT_SHA", "a git commit sha")
|
|
239
241
|
def test_cwl_on_arm(self) -> None:
|
|
242
|
+
# Import the test we want to run remotely, so we know right away if it exists.
|
|
243
|
+
test_class = TestCWLv12Conformance
|
|
244
|
+
test_method = test_class.test_run_conformance
|
|
245
|
+
|
|
246
|
+
# Work out how to describe it as a pytest test spec.
|
|
247
|
+
# __qualname__ gives classname.methodname
|
|
248
|
+
test_name = test_method.__qualname__.replace(".", "::")
|
|
249
|
+
# The module path is the file path under src, with dots.
|
|
250
|
+
test_path = test_class.__module__.replace(".", "/")
|
|
251
|
+
test_spec = f"src/{test_path}.py::{test_name}"
|
|
252
|
+
|
|
240
253
|
# Make a cluster
|
|
241
254
|
self.launchCluster()
|
|
242
255
|
# get the leader so we know the IP address - we don't need to wait since create cluster
|
|
@@ -276,12 +289,12 @@ class CWLOnARMTest(AbstractClusterTest):
|
|
|
276
289
|
]
|
|
277
290
|
)
|
|
278
291
|
|
|
279
|
-
# Runs the
|
|
292
|
+
# Runs the test on an ARM instance
|
|
280
293
|
self.sshUtil(
|
|
281
294
|
[
|
|
282
295
|
"bash",
|
|
283
296
|
"-c",
|
|
284
|
-
f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && pytest --log-cli-level DEBUG -r s
|
|
297
|
+
f". .{self.venvDir}/bin/activate && cd {self.cwl_test_dir}/toil && pytest --log-cli-level DEBUG -r s {test_spec}",
|
|
285
298
|
]
|
|
286
299
|
)
|
|
287
300
|
|
|
@@ -341,7 +341,7 @@ class GCEAutoscaleTestMultipleNodeTypes(AbstractGCEAutoscaleTest):
|
|
|
341
341
|
runCommand = [
|
|
342
342
|
"/home/venv/bin/python",
|
|
343
343
|
"/home/sort.py",
|
|
344
|
-
"--fileToSort=/
|
|
344
|
+
"--fileToSort=/etc/passwd",
|
|
345
345
|
"--sortMemory=0.6G",
|
|
346
346
|
"--mergeMemory=3.0G",
|
|
347
347
|
]
|
toil/test/server/serverTest.py
CHANGED
|
@@ -33,7 +33,7 @@ except ImportError:
|
|
|
33
33
|
# extra wasn't installed. We'll then skip them all.
|
|
34
34
|
pass
|
|
35
35
|
|
|
36
|
-
from toil.test import ToilTest, needs_aws_s3, needs_celery_broker, needs_server
|
|
36
|
+
from toil.test import ToilTest, needs_aws_s3, needs_celery_broker, needs_cwl, needs_server, integrative
|
|
37
37
|
|
|
38
38
|
logger = logging.getLogger(__name__)
|
|
39
39
|
logging.basicConfig(level=logging.INFO)
|
|
@@ -185,6 +185,7 @@ class FileStateStoreURLTest(hidden.AbstractStateStoreTest):
|
|
|
185
185
|
|
|
186
186
|
|
|
187
187
|
@needs_aws_s3
|
|
188
|
+
@integrative
|
|
188
189
|
class BucketUsingTest(ToilTest):
|
|
189
190
|
"""
|
|
190
191
|
Base class for tests that need a bucket.
|
|
@@ -268,6 +269,35 @@ class AWSStateStoreTest(hidden.AbstractStateStoreTest, BucketUsingTest):
|
|
|
268
269
|
self.assertEqual(obj.content_length, len("testvalue"))
|
|
269
270
|
|
|
270
271
|
|
|
272
|
+
# Problem: httpx (which the Connexion test client uses the API of)
|
|
273
|
+
# automatically decides whether to send posts in
|
|
274
|
+
# application/x-www-form-urlencoded or multipart/form-data format
|
|
275
|
+
# based on whether they are uploading any files. But the GA4GH WES
|
|
276
|
+
# API run workflow endpoint only accepts multipart/form-data. It takes
|
|
277
|
+
# workflow_attachment as an array of binary strings officially, but this is
|
|
278
|
+
# actually how Swagger takes multiple-file upload fields. See
|
|
279
|
+
# <https://swagger.io/docs/specification/v2_0/file-upload/#multiple-upload>.
|
|
280
|
+
# (httpx doesn't seem to support actually sending multiple files to one field
|
|
281
|
+
# either, but if we send just one file it ends up as the only value in
|
|
282
|
+
# Swagger's array.)
|
|
283
|
+
#
|
|
284
|
+
# The apparently-official workaround for forcing multipart encoding is to
|
|
285
|
+
# construct an empty dict-saped data structure that is truthy, and pass that as
|
|
286
|
+
# your file list. See
|
|
287
|
+
# <https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186>
|
|
288
|
+
class TrueDict(dict):
|
|
289
|
+
"""
|
|
290
|
+
Dict that is truthy even when empty.
|
|
291
|
+
|
|
292
|
+
Used as a workaround to set httpx post request encoding as recommended in
|
|
293
|
+
<https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186>.
|
|
294
|
+
"""
|
|
295
|
+
def __bool__(self) -> bool:
|
|
296
|
+
"""
|
|
297
|
+
Always say the object is truthy.
|
|
298
|
+
"""
|
|
299
|
+
return True
|
|
300
|
+
|
|
271
301
|
@needs_server
|
|
272
302
|
class AbstractToilWESServerTest(ToilTest):
|
|
273
303
|
"""
|
|
@@ -296,11 +326,12 @@ class AbstractToilWESServerTest(ToilTest):
|
|
|
296
326
|
)
|
|
297
327
|
|
|
298
328
|
# Make the FlaskApp
|
|
299
|
-
|
|
329
|
+
self.app = create_app(args)
|
|
300
330
|
|
|
301
|
-
#
|
|
302
|
-
|
|
303
|
-
|
|
331
|
+
# Neither <https://flask.palletsprojects.com/en/stable/testing/> nor
|
|
332
|
+
# <https://connexion.readthedocs.io/en/latest/testing.html#testing>
|
|
333
|
+
# suggests setting a testing flag on the Connexion app or its internal
|
|
334
|
+
# Flask app, so we don't.
|
|
304
335
|
|
|
305
336
|
self.example_cwl = textwrap.dedent(
|
|
306
337
|
"""
|
|
@@ -345,7 +376,6 @@ class AbstractToilWESServerTest(ToilTest):
|
|
|
345
376
|
"""
|
|
346
377
|
rv = client.get(f"/ga4gh/wes/v1/runs/{run_id}")
|
|
347
378
|
self.assertEqual(rv.status_code, 200)
|
|
348
|
-
self.assertTrue(rv.is_json)
|
|
349
379
|
return rv
|
|
350
380
|
|
|
351
381
|
def _check_successful_log(self, client: "FlaskClient", run_id: str) -> None:
|
|
@@ -354,15 +384,16 @@ class AbstractToilWESServerTest(ToilTest):
|
|
|
354
384
|
The workflow should succeed, it should have some tasks, and they should have all succeeded.
|
|
355
385
|
"""
|
|
356
386
|
rv = self._fetch_run_log(client, run_id)
|
|
387
|
+
rv_json = rv.json()
|
|
357
388
|
logger.debug("Log info: %s", rv.json)
|
|
358
|
-
run_log =
|
|
389
|
+
run_log = rv_json.get("run_log")
|
|
359
390
|
self.assertEqual(type(run_log), dict)
|
|
360
391
|
if "exit_code" in run_log:
|
|
361
392
|
# The workflow succeeded if it has an exit code
|
|
362
393
|
self.assertEqual(run_log["exit_code"], 0)
|
|
363
394
|
# The workflow is complete
|
|
364
|
-
self.assertEqual(
|
|
365
|
-
task_logs =
|
|
395
|
+
self.assertEqual(rv_json.get("state"), "COMPLETE")
|
|
396
|
+
task_logs = rv_json.get("task_logs")
|
|
366
397
|
# There are tasks reported
|
|
367
398
|
self.assertEqual(type(task_logs), list)
|
|
368
399
|
self.assertGreater(len(task_logs), 0)
|
|
@@ -375,7 +406,7 @@ class AbstractToilWESServerTest(ToilTest):
|
|
|
375
406
|
"""Report the log for the given workflow run."""
|
|
376
407
|
rv = self._fetch_run_log(client, run_id)
|
|
377
408
|
logger.debug(f"Report log response: {rv.json}")
|
|
378
|
-
run_log = rv.json.get("run_log")
|
|
409
|
+
run_log = rv.json().get("run_log")
|
|
379
410
|
self.assertEqual(type(run_log), dict)
|
|
380
411
|
self.assertEqual(type(run_log.get("stdout")), str)
|
|
381
412
|
self.assertEqual(type(run_log.get("stderr")), str)
|
|
@@ -395,12 +426,13 @@ class AbstractToilWESServerTest(ToilTest):
|
|
|
395
426
|
logger.info("Fetch %s", url)
|
|
396
427
|
rv = client.get(url)
|
|
397
428
|
self.assertEqual(rv.status_code, 200)
|
|
398
|
-
logger.info("Got %s:\n%s", url, rv.
|
|
429
|
+
logger.info("Got %s:\n%s", url, rv.content.decode("utf-8"))
|
|
399
430
|
|
|
400
431
|
def _start_slow_workflow(self, client: "FlaskClient") -> str:
|
|
401
432
|
"""
|
|
402
433
|
Start a slow workflow and return its ID.
|
|
403
434
|
"""
|
|
435
|
+
|
|
404
436
|
rv = client.post(
|
|
405
437
|
"/ga4gh/wes/v1/runs",
|
|
406
438
|
data={
|
|
@@ -408,15 +440,18 @@ class AbstractToilWESServerTest(ToilTest):
|
|
|
408
440
|
"workflow_type": "CWL",
|
|
409
441
|
"workflow_type_version": "v1.0",
|
|
410
442
|
"workflow_params": json.dumps({"delay": "5"}),
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
443
|
+
},
|
|
444
|
+
files={
|
|
445
|
+
"workflow_attachment": (
|
|
446
|
+
"slow.cwl",
|
|
447
|
+
BytesIO(self.slow_cwl.encode()),
|
|
448
|
+
"application/octet-stream",
|
|
449
|
+
),
|
|
414
450
|
},
|
|
415
451
|
)
|
|
416
452
|
# workflow is submitted successfully
|
|
417
453
|
self.assertEqual(rv.status_code, 200)
|
|
418
|
-
|
|
419
|
-
run_id = rv.json.get("run_id")
|
|
454
|
+
run_id = rv.json().get("run_id")
|
|
420
455
|
self.assertIsNotNone(run_id)
|
|
421
456
|
|
|
422
457
|
return run_id
|
|
@@ -428,11 +463,11 @@ class AbstractToilWESServerTest(ToilTest):
|
|
|
428
463
|
|
|
429
464
|
rv = client.get(f"/ga4gh/wes/v1/runs/{run_id}/status")
|
|
430
465
|
self.assertEqual(rv.status_code, 200)
|
|
431
|
-
|
|
432
|
-
self.assertIn("run_id",
|
|
433
|
-
self.assertEqual(
|
|
434
|
-
self.assertIn("state",
|
|
435
|
-
state =
|
|
466
|
+
rv_json = rv.json()
|
|
467
|
+
self.assertIn("run_id", rv_json)
|
|
468
|
+
self.assertEqual(rv_json.get("run_id"), run_id)
|
|
469
|
+
self.assertIn("state", rv_json)
|
|
470
|
+
state = rv_json.get("state")
|
|
436
471
|
self.assertIn(
|
|
437
472
|
state,
|
|
438
473
|
[
|
|
@@ -492,7 +527,10 @@ class ToilWESServerBenchTest(AbstractToilWESServerTest):
|
|
|
492
527
|
"""Test the homepage endpoint."""
|
|
493
528
|
with self.app.test_client() as client:
|
|
494
529
|
rv = client.get("/")
|
|
495
|
-
|
|
530
|
+
# The client will follow the redirect and populate the url on the response
|
|
531
|
+
self.assertEqual(rv.url.path, "/ga4gh/wes/v1/service-info")
|
|
532
|
+
# We see the final 200 OK status code
|
|
533
|
+
self.assertEqual(rv.status_code, 200)
|
|
496
534
|
|
|
497
535
|
def test_health(self) -> None:
|
|
498
536
|
"""Test the health check endpoint."""
|
|
@@ -505,7 +543,7 @@ class ToilWESServerBenchTest(AbstractToilWESServerTest):
|
|
|
505
543
|
with self.app.test_client() as client:
|
|
506
544
|
rv = client.get("/ga4gh/wes/v1/service-info")
|
|
507
545
|
self.assertEqual(rv.status_code, 200)
|
|
508
|
-
service_info = json
|
|
546
|
+
service_info = rv.json()
|
|
509
547
|
|
|
510
548
|
self.assertIn("version", service_info)
|
|
511
549
|
self.assertIn("workflow_type_versions", service_info)
|
|
@@ -519,7 +557,7 @@ class ToilWESServerBenchTest(AbstractToilWESServerTest):
|
|
|
519
557
|
self.assertIn("system_state_counts", service_info)
|
|
520
558
|
self.assertIn("tags", service_info)
|
|
521
559
|
|
|
522
|
-
|
|
560
|
+
@needs_cwl
|
|
523
561
|
class ToilWESServerWorkflowTest(AbstractToilWESServerTest):
|
|
524
562
|
"""
|
|
525
563
|
Tests of the WES server running workflows.
|
|
@@ -548,11 +586,10 @@ class ToilWESServerWorkflowTest(AbstractToilWESServerTest):
|
|
|
548
586
|
{"message": "Hello, world!"} if include_message else {}
|
|
549
587
|
)
|
|
550
588
|
with self.app.test_client() as client:
|
|
551
|
-
rv = client.post("/ga4gh/wes/v1/runs", data=post_data)
|
|
589
|
+
rv = client.post("/ga4gh/wes/v1/runs", data=post_data, files=TrueDict())
|
|
552
590
|
# workflow is submitted successfully
|
|
553
591
|
self.assertEqual(rv.status_code, 200)
|
|
554
|
-
|
|
555
|
-
run_id = rv.json.get("run_id")
|
|
592
|
+
run_id = rv.json().get("run_id")
|
|
556
593
|
self.assertIsNotNone(run_id)
|
|
557
594
|
|
|
558
595
|
# Check status
|
|
@@ -571,11 +608,11 @@ class ToilWESServerWorkflowTest(AbstractToilWESServerTest):
|
|
|
571
608
|
"workflow_type_version": "v1.0",
|
|
572
609
|
"workflow_params": "{}",
|
|
573
610
|
},
|
|
611
|
+
files=TrueDict(),
|
|
574
612
|
)
|
|
575
613
|
self.assertEqual(rv.status_code, 400)
|
|
576
|
-
self.assertTrue(rv.is_json)
|
|
577
614
|
self.assertEqual(
|
|
578
|
-
rv.json.get("msg"),
|
|
615
|
+
rv.json().get("msg"),
|
|
579
616
|
"Relative 'workflow_url' but missing 'workflow_attachment'",
|
|
580
617
|
)
|
|
581
618
|
|
|
@@ -589,20 +626,24 @@ class ToilWESServerWorkflowTest(AbstractToilWESServerTest):
|
|
|
589
626
|
"workflow_type": "CWL",
|
|
590
627
|
"workflow_type_version": "v1.0",
|
|
591
628
|
"workflow_params": json.dumps({"message": "Hello, world!"}),
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
629
|
+
},
|
|
630
|
+
files={
|
|
631
|
+
"workflow_attachment": (
|
|
632
|
+
"example.cwl",
|
|
633
|
+
BytesIO(self.example_cwl.encode()),
|
|
634
|
+
"application/octet-stream",
|
|
635
|
+
),
|
|
595
636
|
},
|
|
596
637
|
)
|
|
597
638
|
# workflow is submitted successfully
|
|
598
639
|
self.assertEqual(rv.status_code, 200)
|
|
599
|
-
|
|
600
|
-
run_id = rv.json.get("run_id")
|
|
640
|
+
run_id = rv.json().get("run_id")
|
|
601
641
|
self.assertIsNotNone(run_id)
|
|
602
642
|
|
|
603
643
|
# Check status
|
|
604
644
|
self._wait_for_success(client, run_id)
|
|
605
645
|
|
|
646
|
+
@integrative
|
|
606
647
|
def test_run_workflow_https_url(self) -> None:
|
|
607
648
|
"""Test run example CWL workflow from the Internet."""
|
|
608
649
|
with self.app.test_client() as client:
|
|
@@ -614,11 +655,11 @@ class ToilWESServerWorkflowTest(AbstractToilWESServerTest):
|
|
|
614
655
|
"workflow_type_version": "v1.2",
|
|
615
656
|
"workflow_params": json.dumps({"message": "Hello, world!"}),
|
|
616
657
|
},
|
|
658
|
+
files=TrueDict(),
|
|
617
659
|
)
|
|
618
660
|
# workflow is submitted successfully
|
|
619
661
|
self.assertEqual(rv.status_code, 200)
|
|
620
|
-
|
|
621
|
-
run_id = rv.json.get("run_id")
|
|
662
|
+
run_id = rv.json().get("run_id")
|
|
622
663
|
self.assertIsNotNone(run_id)
|
|
623
664
|
|
|
624
665
|
# Check status
|
|
@@ -730,6 +771,7 @@ class ToilWESServerWorkflowTest(AbstractToilWESServerTest):
|
|
|
730
771
|
|
|
731
772
|
|
|
732
773
|
@needs_celery_broker
|
|
774
|
+
@integrative
|
|
733
775
|
class ToilWESServerCeleryWorkflowTest(ToilWESServerWorkflowTest):
|
|
734
776
|
"""
|
|
735
777
|
End-to-end workflow-running tests against Celery.
|
|
@@ -4,7 +4,6 @@ import time
|
|
|
4
4
|
from contextlib import contextmanager
|
|
5
5
|
|
|
6
6
|
from toil.exceptions import FailedJobsException
|
|
7
|
-
from toil.lib.iterables import concat
|
|
8
7
|
from toil.test import ApplianceTestSupport, needs_local_appliance, needs_mesos, slow
|
|
9
8
|
from toil.version import exactPython
|
|
10
9
|
|
|
@@ -85,7 +84,7 @@ class AutoDeploymentTest(ApplianceTestSupport):
|
|
|
85
84
|
"--defaultMemory=10M",
|
|
86
85
|
"/data/jobstore",
|
|
87
86
|
]
|
|
88
|
-
command =
|
|
87
|
+
command = pythonArgs + toilArgs
|
|
89
88
|
self.assertRaises(
|
|
90
89
|
subprocess.CalledProcessError, leader.runOnAppliance, *command
|
|
91
90
|
)
|
|
@@ -96,7 +95,7 @@ class AutoDeploymentTest(ApplianceTestSupport):
|
|
|
96
95
|
path=self.sitePackages, packagePath="foo.bar", script=userScript
|
|
97
96
|
)
|
|
98
97
|
# ... and restart Toil.
|
|
99
|
-
command =
|
|
98
|
+
command = pythonArgs + ["--restart"] + toilArgs
|
|
100
99
|
leader.runOnAppliance(*command)
|
|
101
100
|
|
|
102
101
|
def testSplitRootPackages(self):
|