3 import arvados.collection
13 from .matcher import JsonDiffMatcher
17 @functools.wraps(func)
18 @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
19 @mock.patch("arvados.collection.KeepClient")
20 @mock.patch("arvados.events.subscribe")
21 def wrapped(self, events, KeepClient, keepdocker, *args, **kwargs):
26 stubs.KeepClient = KeepClient
27 stubs.keepdocker = keepdocker
29 def putstub(p, **kwargs):
30 return "%s+%i" % (hashlib.md5(p).hexdigest(), len(p))
31 stubs.KeepClient().put.side_effect = putstub
33 stubs.keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
34 stubs.fake_user_uuid = "zzzzz-tpzed-zzzzzzzzzzzzzzz"
36 stubs.api = mock.MagicMock()
37 stubs.api.users().current().execute.return_value = {
38 "uuid": stubs.fake_user_uuid,
40 stubs.api.collections().list().execute.return_value = {"items": []}
41 stubs.api.collections().create().execute.side_effect = ({
42 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz1",
43 "portable_data_hash": "99999999999999999999999999999991+99",
46 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2",
47 "portable_data_hash": "99999999999999999999999999999992+99",
48 "manifest_text": "./tool 00000000000000000000000000000000+0 0:0:submit_tool.cwl 0:0:blub.txt"
51 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz4",
52 "portable_data_hash": "99999999999999999999999999999994+99",
56 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz5",
57 "portable_data_hash": "99999999999999999999999999999995+99",
60 stubs.api.collections().get().execute.return_value = {
61 "portable_data_hash": "99999999999999999999999999999993+99", "manifest_text": "./tool 00000000000000000000000000000000+0 0:0:submit_tool.cwl 0:0:blub.txt"}
63 stubs.expect_job_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
64 stubs.api.jobs().create().execute.return_value = {
65 "uuid": stubs.expect_job_uuid,
69 stubs.expect_container_request_uuid = "zzzzz-xvhdp-zzzzzzzzzzzzzzz"
70 stubs.api.container_requests().create().execute.return_value = {
71 "uuid": stubs.expect_container_request_uuid,
72 "container_uuid": "zzzzz-dz642-zzzzzzzzzzzzzzz",
76 stubs.expect_pipeline_template_uuid = "zzzzz-d1hrv-zzzzzzzzzzzzzzz"
77 stubs.api.pipeline_templates().create().execute.return_value = {
78 "uuid": stubs.expect_pipeline_template_uuid,
80 stubs.expect_job_spec = {
81 'runtime_constraints': {
82 'docker_image': 'arvados/jobs'
84 'script_parameters': {
86 'basename': 'blorp.txt',
87 'location': '99999999999999999999999999999994+99/blorp.txt',
91 '99999999999999999999999999999991+99/wf/submit_wf.cwl'
93 'repository': 'arvados',
94 'script_version': 'master',
95 'script': 'cwl-runner'
98 stubs.expect_container_spec = {
105 '/var/lib/cwl/workflow': {
106 'portable_data_hash': '99999999999999999999999999999991+99',
110 'path': '/var/spool/cwl/cwl.output.json',
113 '/var/lib/cwl/job/cwl.input.json': {
114 'portable_data_hash': '765fda0d9897729ff467a4609879c00a+60/cwl.input.json',
118 'state': 'Committed',
119 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
120 'command': ['arvados-cwl-runner', '--local', '--api=containers', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json'],
121 'name': 'submit_wf.cwl',
122 'container_image': '99999999999999999999999999999993+99',
123 'output_path': '/var/spool/cwl',
124 'cwd': '/var/spool/cwl',
125 'runtime_constraints': {
131 return func(self, stubs, *args, **kwargs)
135 class TestSubmit(unittest.TestCase):
137 def test_submit(self, stubs):
138 capture_stdout = cStringIO.StringIO()
139 exited = arvados_cwl.main(
140 ["--submit", "--no-wait",
141 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
142 capture_stdout, sys.stderr, api_client=stubs.api)
143 self.assertEqual(exited, 0)
145 stubs.api.collections().create.assert_has_calls([
149 './tool d51232d96b6116d964a69bfb7e0c73bf+450 '
150 '0:16:blub.txt 16:434:submit_tool.cwl\n./wf '
151 '4d31c5fefd087faf67ca8db0111af36c+353 0:353:submit_wf.cwl\n',
152 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
153 'name': 'submit_wf.cwl',
154 }, ensure_unique_name=True),
155 mock.call().execute(),
156 mock.call(body={'manifest_text': '. d41d8cd98f00b204e9800998ecf8427e+0 '
157 '0:0:blub.txt 0:0:submit_tool.cwl\n',
158 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
159 'name': 'New collection'},
160 ensure_unique_name=True),
161 mock.call().execute(num_retries=4),
164 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
165 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
167 }, ensure_unique_name=True),
168 mock.call().execute()])
170 expect_job = copy.deepcopy(stubs.expect_job_spec)
171 expect_job["owner_uuid"] = stubs.fake_user_uuid
172 stubs.api.jobs().create.assert_called_with(
175 self.assertEqual(capture_stdout.getvalue(),
176 stubs.expect_job_uuid + '\n')
179 def test_submit_with_project_uuid(self, stubs):
180 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
182 exited = arvados_cwl.main(
183 ["--submit", "--no-wait",
184 "--project-uuid", project_uuid,
185 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
186 sys.stdout, sys.stderr, api_client=stubs.api)
187 self.assertEqual(exited, 0)
189 expect_body = copy.deepcopy(stubs.expect_job_spec)
190 expect_body["owner_uuid"] = project_uuid
191 stubs.api.jobs().create.assert_called_with(
196 def test_submit_container(self, stubs):
197 capture_stdout = cStringIO.StringIO()
198 exited = arvados_cwl.main(
199 ["--submit", "--no-wait", "--api=containers", "--debug",
200 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
201 capture_stdout, sys.stderr, api_client=stubs.api)
202 self.assertEqual(exited, 0)
204 stubs.api.collections().create.assert_has_calls([
208 './tool d51232d96b6116d964a69bfb7e0c73bf+450 '
209 '0:16:blub.txt 16:434:submit_tool.cwl\n./wf '
210 '4d31c5fefd087faf67ca8db0111af36c+353 0:353:submit_wf.cwl\n',
211 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
212 'name': 'submit_wf.cwl',
213 }, ensure_unique_name=True),
214 mock.call().execute(),
215 mock.call(body={'manifest_text': '. d41d8cd98f00b204e9800998ecf8427e+0 '
216 '0:0:blub.txt 0:0:submit_tool.cwl\n',
217 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
218 'name': 'New collection'},
219 ensure_unique_name=True),
220 mock.call().execute(num_retries=4),
223 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
224 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
226 }, ensure_unique_name=True),
227 mock.call().execute()])
229 expect_container = copy.deepcopy(stubs.expect_container_spec)
230 expect_container["owner_uuid"] = stubs.fake_user_uuid
231 stubs.api.container_requests().create.assert_called_with(
232 body=expect_container)
233 self.assertEqual(capture_stdout.getvalue(),
234 stubs.expect_container_request_uuid + '\n')
237 class TestCreateTemplate(unittest.TestCase):
239 def test_create(self, stubs):
240 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
242 capture_stdout = cStringIO.StringIO()
244 exited = arvados_cwl.main(
245 ["--create-template", "--no-wait", "--debug",
246 "--project-uuid", project_uuid,
247 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
248 capture_stdout, sys.stderr, api_client=stubs.api)
249 self.assertEqual(exited, 0)
251 stubs.api.pipeline_instances().create.refute_called()
252 stubs.api.jobs().create.refute_called()
254 expect_component = copy.deepcopy(stubs.expect_job_spec)
255 expect_component['script_parameters']['x'] = {
259 'value': '99999999999999999999999999999994+99/blorp.txt',
263 "submit_wf.cwl": expect_component,
265 "name": "submit_wf.cwl",
266 "owner_uuid": project_uuid,
268 stubs.api.pipeline_templates().create.assert_called_with(
269 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
271 self.assertEqual(capture_stdout.getvalue(),
272 stubs.expect_pipeline_template_uuid + '\n')
275 class TestTemplateInputs(unittest.TestCase):
279 'runtime_constraints': {
280 'docker_image': 'arvados/jobs',
282 'script_parameters': {
284 '99999999999999999999999999999991+99/'
285 'wf/inputs_test.cwl',
286 'optionalFloatInput': None,
291 'title': "It's a file; we expect to find some characters in it.",
292 'description': 'If there were anything further to say, it would be said here,\nor here.'
296 'dataclass': 'number',
298 'title': 'Floats like a duck',
302 'optionalFloatInput': {
303 'type': ['null', 'float'],
304 'dataclass': 'number',
309 'dataclass': 'boolean',
311 'title': 'True or false?',
314 'repository': 'arvados',
315 'script_version': 'master',
316 'script': 'cwl-runner',
319 "name": "inputs_test.cwl",
323 def test_inputs_empty(self, stubs):
324 exited = arvados_cwl.main(
325 ["--create-template", "--no-wait",
326 "tests/wf/inputs_test.cwl", "tests/order/empty_order.json"],
327 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
328 self.assertEqual(exited, 0)
330 expect_template = copy.deepcopy(self.expect_template)
331 expect_template["owner_uuid"] = stubs.fake_user_uuid
333 stubs.api.pipeline_templates().create.assert_called_with(
334 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
337 def test_inputs(self, stubs):
338 exited = arvados_cwl.main(
339 ["--create-template", "--no-wait",
340 "tests/wf/inputs_test.cwl", "tests/order/inputs_test_order.json"],
341 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
342 self.assertEqual(exited, 0)
344 self.expect_template["owner_uuid"] = stubs.fake_user_uuid
346 expect_template = copy.deepcopy(self.expect_template)
347 expect_template["owner_uuid"] = stubs.fake_user_uuid
348 params = expect_template[
349 "components"]["inputs_test.cwl"]["script_parameters"]
350 params["fileInput"]["value"] = '99999999999999999999999999999994+99/blorp.txt'
351 params["floatInput"]["value"] = 1.234
352 params["boolInput"]["value"] = True
354 stubs.api.pipeline_templates().create.assert_called_with(
355 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)