Skip to content

Commit b38edfa

Browse files
authored
Merge pull request #51 from common-workflow-language/symlinksNutil
Attachments connecting to toil/cwl_runner. Add util to compose post. Test cleanup.
2 parents 8d8612c + 77e9033 commit b38edfa

File tree

10 files changed

+468
-253
lines changed

10 files changed

+468
-253
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ python:
33
- '2.7'
44
before_install:
55
- sudo apt-get update -qq
6-
- pip install toil[all]==3.16.0
6+
- pip install toil[all]==3.17.0
77
- pip install . --process-dependency-links
88
- pip install -r dev-requirements.txt
99
script:

README.md

+17-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ $ wes-server
2727
Note! All inputs files must be accessible from the filesystem.
2828

2929
```
30-
$ wes-client --host=localhost:8080 testdata/md5sum.cwl testdata/md5sum.cwl.json
30+
$ wes-client --host=localhost:8080 --proto=http --attachments="testdata/dockstore-tool-md5sum.cwl,testdata/md5sum.input" testdata/md5sum.cwl testdata/md5sum.cwl.json
3131
```
3232

3333
### List workflows
@@ -56,10 +56,17 @@ $ wes-client --proto http --host=locahost:8080 --log <workflow-id>
5656
$ wes-server --backend=wes_service.arvados_wes
5757
```
5858

59+
### Run a standalone server with Toil backend:
60+
61+
```
62+
$ pip install toil[all]
63+
$ wes-server --backend=wes_service.toil_wes --opt extra=--clean=never
64+
```
65+
5966
### Use a different executable with cwl_runner backend
6067

6168
```
62-
$ pip install toil
69+
$ pip install toil[all]
6370
$ wes-server --backend=wes_service.cwl_runner --opt runner=cwltoil --opt extra=--logLevel=CRITICAL
6471
```
6572

@@ -98,7 +105,14 @@ flags, `--host`, `--auth`, and `proto` respectively.
98105

99106
## Development
100107
If you would like to develop against `workflow-service` make sure you pass the provided test and it is flake8 compliant
101-
#### Run test
108+
109+
#### Install from Source
110+
111+
```
112+
$ virtualenv venv && source venv/bin/activate && pip install toil[all] && pip install . --process-dependency-links && pip install -r dev-requirements.txt
113+
```
114+
115+
#### Running Tests
102116
From path `workflow-service` run
103117

104118
```

test/test_integration.py

+53-74
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import absolute_import
22

3-
import json
43
import unittest
54
import time
65
import os
@@ -10,11 +9,28 @@
109
import shutil
1110
import logging
1211

12+
from wes_client.util import build_wes_request
13+
1314
logging.basicConfig(level=logging.INFO)
1415

1516

1617
class IntegrationTest(unittest.TestCase):
1718
"""A baseclass that's inherited for use with different cwl backends."""
19+
@classmethod
20+
def setUpClass(cls):
21+
# cwl
22+
cls.cwl_dockstore_url = 'https://dockstore.org:8443/api/ga4gh/v2/tools/quay.io%2Fbriandoconnor%2Fdockstore-tool-md5sum/versions/master/plain-CWL/descriptor/%2FDockstore.cwl'
23+
cls.cwl_local_path = os.path.abspath('testdata/md5sum.cwl')
24+
cls.cwl_json_input = "file://" + os.path.abspath('testdata/md5sum.json')
25+
cls.cwl_attachments = ['file://' + os.path.abspath('testdata/md5sum.input'),
26+
'file://' + os.path.abspath('testdata/dockstore-tool-md5sum.cwl')]
27+
# wdl
28+
cls.wdl_local_path = os.path.abspath('testdata/md5sum.wdl')
29+
cls.wdl_json_input = "file://" + os.path.abspath('testdata/md5sum.wdl.json')
30+
cls.wdl_attachments = ['file://' + os.path.abspath('testdata/md5sum.input')]
31+
32+
# manual test (wdl only working locally atm)
33+
cls.manual = False
1834

1935
def setUp(self):
2036
"""Start a (local) wes-service server to make requests against."""
@@ -35,88 +51,42 @@ def tearDown(self):
3551
unittest.TestCase.tearDown(self)
3652

3753
def test_dockstore_md5sum(self):
38-
"""Fetch the md5sum cwl from dockstore, run it on the wes-service server, and check for the correct output."""
39-
cwl_dockstore_url = 'https://dockstore.org:8443/api/ga4gh/v2/tools/quay.io%2Fbriandoconnor%2Fdockstore-tool-md5sum/versions/master/plain-CWL/descriptor/%2FDockstore.cwl'
40-
output_filepath, _ = run_cwl_md5sum(cwl_input=cwl_dockstore_url)
41-
42-
self.assertTrue(check_for_file(output_filepath), 'Output file was not found: ' + str(output_filepath))
43-
54+
"""HTTP md5sum cwl (dockstore), run it on the wes-service server, and check for the correct output."""
55+
outfile_path, _ = run_md5sum(wf_input=self.cwl_dockstore_url,
56+
json_input=self.cwl_json_input,
57+
workflow_attachment=self.cwl_attachments)
58+
self.assertTrue(check_for_file(outfile_path), 'Output file was not found: ' + str(outfile_path))
59+
4460
def test_local_md5sum(self):
45-
"""Pass a local md5sum cwl to the wes-service server, and check for the correct output."""
46-
cwl_local_path = os.path.abspath('testdata/md5sum.cwl')
47-
workflow_attachment_path = os.path.abspath('testdata/dockstore-tool-md5sum.cwl')
48-
output_filepath, _ = run_cwl_md5sum(cwl_input='file://' + cwl_local_path,
49-
workflow_attachment='file://' + workflow_attachment_path)
50-
51-
self.assertTrue(check_for_file(output_filepath), 'Output file was not found: ' + str(output_filepath))
52-
53-
def test_multipart_upload(self):
54-
"""Pass a local md5sum cwl to the wes-service server, and check for uploaded file in service."""
55-
cwl_local_path = os.path.abspath('testdata/md5sum.cwl')
56-
workflow_attachment_path = os.path.abspath('testdata/dockstore-tool-md5sum.cwl')
57-
out_file_path, run_id = run_cwl_md5sum(cwl_input='file://' + cwl_local_path,
58-
workflow_attachment='file://' + workflow_attachment_path)
59-
60-
get_response = get_log_request(run_id)["request"]
61-
62-
self.assertTrue(check_for_file(out_file_path), 'Output file was not found: '
63-
+ get_response["workflow_attachment"])
64-
self.assertTrue(check_for_file(get_response["workflow_url"][7:]), 'Output file was not found: '
65-
+ get_response["workflow_url"][:7])
66-
61+
"""LOCAL md5sum cwl to the wes-service server, and check for the correct output."""
62+
outfile_path, run_id = run_md5sum(wf_input=self.cwl_local_path,
63+
json_input=self.cwl_json_input,
64+
workflow_attachment=self.cwl_attachments)
65+
self.assertTrue(check_for_file(outfile_path), 'Output file was not found: ' + str(outfile_path))
66+
6767
def test_run_attachments(self):
68-
"""Pass a local md5sum cwl to the wes-service server, check for attachments."""
69-
cwl_local_path = os.path.abspath('testdata/md5sum.cwl')
70-
workflow_attachment_path = os.path.abspath('testdata/dockstore-tool-md5sum.cwl')
71-
out_file_path, run_id = run_cwl_md5sum(cwl_input='file://' + cwl_local_path,
72-
workflow_attachment='file://' + workflow_attachment_path)
73-
68+
"""LOCAL md5sum cwl to the wes-service server, check for attachments."""
69+
outfile_path, run_id = run_md5sum(wf_input=self.cwl_local_path,
70+
json_input=self.cwl_json_input,
71+
workflow_attachment=self.cwl_attachments)
7472
get_response = get_log_request(run_id)["request"]
73+
self.assertTrue(check_for_file(outfile_path), 'Output file was not found: ' + get_response["workflow_attachment"])
7574
attachment_tool_path = get_response["workflow_attachment"][7:] + "/dockstore-tool-md5sum.cwl"
76-
self.assertTrue(check_for_file(out_file_path), 'Output file was not found: '
77-
+ get_response["workflow_attachment"])
78-
self.assertTrue(check_for_file(attachment_tool_path), 'Attachment file was not found: '
79-
+ get_response["workflow_attachment"])
75+
self.assertTrue(check_for_file(attachment_tool_path), 'Attachment file was not found: ' + get_response["workflow_attachment"])
8076

8177

82-
def run_cwl_md5sum(cwl_input, workflow_attachment=None):
78+
def run_md5sum(wf_input, json_input, workflow_attachment=None):
8379
"""Pass a local md5sum cwl to the wes-service server, and return the path of the output file that was created."""
8480
endpoint = 'http://localhost:8080/ga4gh/wes/v1/runs'
85-
params = {'output_file': {'path': '/tmp/md5sum.txt', 'class': 'File'},
86-
'input_file': {'path': os.path.abspath('testdata/md5sum.input'), 'class': 'File'}}
87-
88-
parts = [("workflow_params", json.dumps(params)), ("workflow_type", "CWL"), ("workflow_type_version", "v1.0")]
89-
if cwl_input.startswith("file://"):
90-
parts.append(("workflow_attachment", ("md5sum.cwl", open(cwl_input[7:], "rb"))))
91-
parts.append(("workflow_url", os.path.basename(cwl_input[7:])))
92-
if workflow_attachment:
93-
parts.append(("workflow_attachment", ("dockstore-tool-md5sum.cwl", open(workflow_attachment[7:], "rb"))))
94-
else:
95-
parts.append(("workflow_url", cwl_input))
81+
parts = build_wes_request(wf_input,
82+
json_input,
83+
attachments=workflow_attachment)
9684
response = requests.post(endpoint, files=parts).json()
85+
assert 'run_id' in response, str(response.json())
9786
output_dir = os.path.abspath(os.path.join('workflows', response['run_id'], 'outdir'))
9887
return os.path.join(output_dir, 'md5sum.txt'), response['run_id']
9988

10089

101-
def run_wdl_md5sum(wdl_input):
102-
"""Pass a local md5sum wdl to the wes-service server, and return the path of the output file that was created."""
103-
endpoint = 'http://localhost:8080/ga4gh/wes/v1/workflows'
104-
params = '{"ga4ghMd5.inputFile": "' + os.path.abspath('testdata/md5sum.input') + '"}'
105-
parts = [("workflow_params", params),
106-
("workflow_type", "WDL"),
107-
("workflow_type_version", "v1.0"),
108-
("workflow_url", wdl_input)]
109-
response = requests.post(endpoint, files=parts).json()
110-
output_dir = os.path.abspath(os.path.join('workflows', response['workflow_id'], 'outdir'))
111-
check_travis_log = os.path.join(output_dir, 'stderr')
112-
with open(check_travis_log, 'r') as f:
113-
logging.info(f.read())
114-
logging.info(subprocess.check_output(['ls', os.path.join('workflows', response['workflow_id'])]))
115-
logging.info('\n')
116-
logging.info(subprocess.check_output(['ls', output_dir]))
117-
return os.path.join(output_dir, 'md5sum.txt'), response['workflow_id']
118-
119-
12090
def get_log_request(run_id):
12191
endpoint = 'http://localhost:8080/ga4gh/wes/v1/runs/{}'.format(run_id)
12292
return requests.get(endpoint).json()
@@ -130,14 +100,12 @@ def get_server_pids():
130100
return pids
131101

132102

133-
def check_for_file(filepath, seconds=40):
103+
def check_for_file(filepath, seconds=120):
134104
"""Return True if a file exists within a certain amount of time."""
135105
wait_counter = 0
136106
while not os.path.exists(filepath):
137107
time.sleep(1)
138108
wait_counter += 1
139-
if os.path.exists(filepath):
140-
return True
141109
if wait_counter > seconds:
142110
return False
143111
return True
@@ -164,11 +132,22 @@ def setUp(self):
164132
Start a (local) wes-service server to make requests against.
165133
Use toil as the wes-service server 'backend'.
166134
"""
167-
self.wes_server_process = subprocess.Popen('python {} --backend=wes_service.toil_wes --opt="extra=--logLevel=CRITICAL"'
135+
self.wes_server_process = subprocess.Popen('python {} --backend=wes_service.toil_wes '
136+
'--opt="extra=--logLevel=CRITICAL" '
137+
'--opt="extra=--clean=never"'
168138
''.format(os.path.abspath('wes_service/wes_service_main.py')),
169139
shell=True)
170140
time.sleep(5)
171141

142+
def test_local_wdl(self):
143+
"""LOCAL md5sum wdl to the wes-service server, and check for the correct output."""
144+
# Working locally but not on travis... >.<;
145+
if self.manual:
146+
outfile_path, run_id = run_md5sum(wf_input=self.wdl_local_path,
147+
json_input=self.wdl_json_input,
148+
workflow_attachment=self.wdl_attachments)
149+
self.assertTrue(check_for_file(outfile_path), 'Output file was not found: ' + str(outfile_path))
150+
172151

173152
# Prevent pytest/unittest's discovery from attempting to discover the base test class.
174153
del IntegrationTest

testdata/md5sum.cwl

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ steps:
1515
in:
1616
input_file: input_file
1717
out: [output_file]
18+

testdata/md5sum.json

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{"output_file": {"path": "/tmp/md5sum.txt", "class": "File"},
2+
"input_file": {"path": "md5sum.input", "class": "File"}}

0 commit comments

Comments
 (0)