1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: Apache-2.0
16 import arvados.collection
18 import arvados_cwl.runner
21 from .matcher import JsonDiffMatcher, StripYAMLComments
22 from .mock_discovery import get_rootDesc
24 import ruamel.yaml as yaml
29 @functools.wraps(func)
30 @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
31 @mock.patch("arvados.collection.KeepClient")
32 @mock.patch("arvados.keep.KeepClient")
33 @mock.patch("arvados.events.subscribe")
34 def wrapped(self, events, keep_client1, keep_client2, keepdocker, *args, **kwargs):
39 stubs.keepdocker = keepdocker
41 def putstub(p, **kwargs):
42 return "%s+%i" % (hashlib.md5(p).hexdigest(), len(p))
43 keep_client1().put.side_effect = putstub
44 keep_client1.put.side_effect = putstub
45 keep_client2().put.side_effect = putstub
46 keep_client2.put.side_effect = putstub
48 stubs.keep_client = keep_client2
49 stubs.keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
50 stubs.fake_user_uuid = "zzzzz-tpzed-zzzzzzzzzzzzzzz"
52 stubs.api = mock.MagicMock()
53 stubs.api._rootDesc = get_rootDesc()
55 stubs.api.users().current().execute.return_value = {
56 "uuid": stubs.fake_user_uuid,
58 stubs.api.collections().list().execute.return_value = {"items": []}
60 class CollectionExecute(object):
61 def __init__(self, exe):
63 def execute(self, num_retries=None):
66 def collection_createstub(created_collections, body, ensure_unique_name=None):
67 mt = body["manifest_text"]
68 uuid = "zzzzz-4zz18-zzzzzzzzzzzzzz%d" % len(created_collections)
69 pdh = "%s+%i" % (hashlib.md5(mt).hexdigest(), len(mt))
70 created_collections[uuid] = {
72 "portable_data_hash": pdh,
75 return CollectionExecute(created_collections[uuid])
77 def collection_getstub(created_collections, uuid):
78 for v in created_collections.itervalues():
79 if uuid in (v["uuid"], v["portable_data_hash"]):
80 return CollectionExecute(v)
82 created_collections = {
83 "99999999999999999999999999999998+99": {
85 "portable_data_hash": "99999999999999999999999999999998+99",
86 "manifest_text": ". 99999999999999999999999999999998+99 0:0:file1.txt"
88 "99999999999999999999999999999994+99": {
90 "portable_data_hash": "99999999999999999999999999999994+99",
91 "manifest_text": ". 99999999999999999999999999999994+99 0:0:expect_arvworkflow.cwl"
94 stubs.api.collections().create.side_effect = functools.partial(collection_createstub, created_collections)
95 stubs.api.collections().get.side_effect = functools.partial(collection_getstub, created_collections)
97 stubs.expect_job_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
98 stubs.api.jobs().create().execute.return_value = {
99 "uuid": stubs.expect_job_uuid,
103 stubs.expect_container_request_uuid = "zzzzz-xvhdp-zzzzzzzzzzzzzzz"
104 stubs.api.container_requests().create().execute.return_value = {
105 "uuid": stubs.expect_container_request_uuid,
106 "container_uuid": "zzzzz-dz642-zzzzzzzzzzzzzzz",
110 stubs.expect_pipeline_template_uuid = "zzzzz-d1hrv-zzzzzzzzzzzzzzz"
111 stubs.api.pipeline_templates().create().execute.return_value = {
112 "uuid": stubs.expect_pipeline_template_uuid,
114 stubs.expect_job_spec = {
115 'runtime_constraints': {
116 'docker_image': 'arvados/jobs:'+arvados_cwl.__version__,
117 'min_ram_mb_per_node': 1024
119 'script_parameters': {
121 'basename': 'blorp.txt',
122 'location': 'keep:169f39d466a5438ac4a90e779bf750c7+53/blorp.txt',
126 'basename': '99999999999999999999999999999998+99',
127 'location': 'keep:99999999999999999999999999999998+99',
131 'basename': 'anonymous',
133 "basename": "renamed.txt",
135 "location": "keep:99999999999999999999999999999998+99/file1.txt"
139 'cwl:tool': '3fffdeaa75e018172e1b583425f4ebff+60/workflow.cwl#main'
141 'repository': 'arvados',
142 'script_version': 'master',
143 'minimum_script_version': '570509ab4d2ef93d870fd2b1f2eab178afb1bad9',
144 'script': 'cwl-runner'
146 stubs.pipeline_component = stubs.expect_job_spec.copy()
147 stubs.expect_pipeline_instance = {
148 'name': 'submit_wf.cwl',
149 'state': 'RunningOnServer',
153 'runtime_constraints': {'docker_image': 'arvados/jobs:'+arvados_cwl.__version__, 'min_ram_mb_per_node': 1024},
154 'script_parameters': {
155 'y': {"value": {'basename': '99999999999999999999999999999998+99', 'location': 'keep:99999999999999999999999999999998+99', 'class': 'Directory'}},
157 'basename': 'blorp.txt',
159 'location': 'keep:169f39d466a5438ac4a90e779bf750c7+53/blorp.txt',
162 'z': {"value": {'basename': 'anonymous', 'class': 'Directory',
165 'basename': 'renamed.txt',
166 'class': 'File', 'location':
167 'keep:99999999999999999999999999999998+99/file1.txt'
170 'cwl:tool': '3fffdeaa75e018172e1b583425f4ebff+60/workflow.cwl#main',
172 'arv:enable_reuse': True,
173 'arv:on_error': 'continue'
175 'repository': 'arvados',
176 'script_version': 'master',
177 'minimum_script_version': '570509ab4d2ef93d870fd2b1f2eab178afb1bad9',
178 'script': 'cwl-runner',
179 'job': {'state': 'Queued', 'uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'}
183 stubs.pipeline_create = copy.deepcopy(stubs.expect_pipeline_instance)
184 stubs.expect_pipeline_uuid = "zzzzz-d1hrv-zzzzzzzzzzzzzzz"
185 stubs.pipeline_create["uuid"] = stubs.expect_pipeline_uuid
186 stubs.pipeline_with_job = copy.deepcopy(stubs.pipeline_create)
187 stubs.pipeline_with_job["components"]["cwl-runner"]["job"] = {
188 "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz",
191 stubs.api.pipeline_instances().create().execute.return_value = stubs.pipeline_create
192 stubs.api.pipeline_instances().get().execute.return_value = stubs.pipeline_with_job
194 with open("tests/wf/submit_wf_packed.cwl") as f:
195 expect_packed_workflow = yaml.round_trip_load(f)
197 stubs.expect_container_spec = {
204 '/var/lib/cwl/workflow.json': {
205 'content': expect_packed_workflow,
209 'path': '/var/spool/cwl/cwl.output.json',
212 '/var/lib/cwl/cwl.input.json': {
216 'basename': '99999999999999999999999999999998+99',
217 'location': 'keep:99999999999999999999999999999998+99',
218 'class': 'Directory'},
220 'basename': u'blorp.txt',
222 'location': u'keep:169f39d466a5438ac4a90e779bf750c7+53/blorp.txt',
225 'z': {'basename': 'anonymous', 'class': 'Directory', 'listing': [
226 {'basename': 'renamed.txt',
228 'location': 'keep:99999999999999999999999999999998+99/file1.txt'
236 'state': 'Committed',
237 'command': ['arvados-cwl-runner', '--local', '--api=containers',
238 '--no-log-timestamps', '--disable-validate',
239 '--eval-timeout=20', '--thread-count=4',
240 '--enable-reuse', '--debug', '--on-error=continue',
241 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'],
242 'name': 'submit_wf.cwl',
243 'container_image': 'arvados/jobs:'+arvados_cwl.__version__,
244 'output_path': '/var/spool/cwl',
245 'cwd': '/var/spool/cwl',
246 'runtime_constraints': {
249 'ram': 1024*1024*1024
251 'use_existing': True,
256 stubs.expect_workflow_uuid = "zzzzz-7fd4e-zzzzzzzzzzzzzzz"
257 stubs.api.workflows().create().execute.return_value = {
258 "uuid": stubs.expect_workflow_uuid,
260 def update_mock(**kwargs):
261 stubs.updated_uuid = kwargs.get('uuid')
263 stubs.api.workflows().update.side_effect = update_mock
264 stubs.api.workflows().update().execute.side_effect = lambda **kwargs: {
265 "uuid": stubs.updated_uuid,
268 return func(self, stubs, *args, **kwargs)
272 class TestSubmit(unittest.TestCase):
273 @mock.patch("arvados_cwl.runner.arv_docker_get_image")
274 @mock.patch("time.sleep")
276 def test_submit(self, stubs, tm, arvdock):
277 capture_stdout = cStringIO.StringIO()
278 exited = arvados_cwl.main(
279 ["--submit", "--no-wait", "--api=jobs", "--debug",
280 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
281 capture_stdout, sys.stderr, api_client=stubs.api)
282 self.assertEqual(exited, 0)
284 stubs.api.collections().create.assert_has_calls([
285 mock.call(body=JsonDiffMatcher({
287 '. 5bcc9fe8f8d5992e6cf418dc7ce4dbb3+16 0:16:blub.txt\n',
288 'replication_desired': None,
289 'name': 'submit_tool.cwl dependencies',
290 }), ensure_unique_name=True),
291 mock.call(body=JsonDiffMatcher({
293 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
294 'replication_desired': None,
295 'name': 'submit_wf.cwl input',
296 }), ensure_unique_name=True),
297 mock.call(body=JsonDiffMatcher({
299 '. 61df2ed9ee3eb7dd9b799e5ca35305fa+1217 0:1217:workflow.cwl\n',
300 'replication_desired': None,
301 'name': 'submit_wf.cwl',
302 }), ensure_unique_name=True) ])
304 arvdock.assert_has_calls([
305 mock.call(stubs.api, {"class": "DockerRequirement", "dockerPull": "debian:8"}, True, None),
306 mock.call(stubs.api, {'dockerPull': 'arvados/jobs:'+arvados_cwl.__version__}, True, None)
309 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
310 stubs.api.pipeline_instances().create.assert_called_with(
311 body=JsonDiffMatcher(expect_pipeline))
312 self.assertEqual(capture_stdout.getvalue(),
313 stubs.expect_pipeline_uuid + '\n')
316 @mock.patch("time.sleep")
318 def test_submit_no_reuse(self, stubs, tm):
319 capture_stdout = cStringIO.StringIO()
320 exited = arvados_cwl.main(
321 ["--submit", "--no-wait", "--api=jobs", "--debug", "--disable-reuse",
322 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
323 capture_stdout, sys.stderr, api_client=stubs.api)
324 self.assertEqual(exited, 0)
326 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
327 expect_pipeline["components"]["cwl-runner"]["script_parameters"]["arv:enable_reuse"] = {"value": False}
328 expect_pipeline["properties"] = {"run_options": {"enable_job_reuse": False}}
330 stubs.api.pipeline_instances().create.assert_called_with(
331 body=JsonDiffMatcher(expect_pipeline))
332 self.assertEqual(capture_stdout.getvalue(),
333 stubs.expect_pipeline_uuid + '\n')
335 @mock.patch("time.sleep")
337 def test_submit_on_error(self, stubs, tm):
338 capture_stdout = cStringIO.StringIO()
339 exited = arvados_cwl.main(
340 ["--submit", "--no-wait", "--api=jobs", "--debug", "--on-error=stop",
341 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
342 capture_stdout, sys.stderr, api_client=stubs.api)
343 self.assertEqual(exited, 0)
345 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
346 expect_pipeline["components"]["cwl-runner"]["script_parameters"]["arv:on_error"] = "stop"
348 stubs.api.pipeline_instances().create.assert_called_with(
349 body=JsonDiffMatcher(expect_pipeline))
350 self.assertEqual(capture_stdout.getvalue(),
351 stubs.expect_pipeline_uuid + '\n')
354 @mock.patch("time.sleep")
356 def test_submit_runner_ram(self, stubs, tm):
357 capture_stdout = cStringIO.StringIO()
358 exited = arvados_cwl.main(
359 ["--submit", "--no-wait", "--debug", "--submit-runner-ram=2048",
360 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
361 capture_stdout, sys.stderr, api_client=stubs.api)
362 self.assertEqual(exited, 0)
364 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
365 expect_pipeline["components"]["cwl-runner"]["runtime_constraints"]["min_ram_mb_per_node"] = 2048
367 stubs.api.pipeline_instances().create.assert_called_with(
368 body=JsonDiffMatcher(expect_pipeline))
369 self.assertEqual(capture_stdout.getvalue(),
370 stubs.expect_pipeline_uuid + '\n')
373 @mock.patch("time.sleep")
375 def test_submit_invalid_runner_ram(self, stubs, tm):
376 capture_stdout = cStringIO.StringIO()
377 exited = arvados_cwl.main(
378 ["--submit", "--no-wait", "--debug", "--submit-runner-ram=-2048",
379 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
380 capture_stdout, sys.stderr, api_client=stubs.api)
381 self.assertEqual(exited, 1)
383 @mock.patch("time.sleep")
385 def test_submit_output_name(self, stubs, tm):
386 output_name = "test_output_name"
388 capture_stdout = cStringIO.StringIO()
389 exited = arvados_cwl.main(
390 ["--submit", "--no-wait", "--debug", "--output-name", output_name,
391 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
392 capture_stdout, sys.stderr, api_client=stubs.api)
393 self.assertEqual(exited, 0)
395 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
396 expect_pipeline["components"]["cwl-runner"]["script_parameters"]["arv:output_name"] = output_name
398 stubs.api.pipeline_instances().create.assert_called_with(
399 body=JsonDiffMatcher(expect_pipeline))
400 self.assertEqual(capture_stdout.getvalue(),
401 stubs.expect_pipeline_uuid + '\n')
404 @mock.patch("time.sleep")
406 def test_submit_pipeline_name(self, stubs, tm):
407 capture_stdout = cStringIO.StringIO()
408 exited = arvados_cwl.main(
409 ["--submit", "--no-wait", "--debug", "--name=hello job 123",
410 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
411 capture_stdout, sys.stderr, api_client=stubs.api)
412 self.assertEqual(exited, 0)
414 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
415 expect_pipeline["name"] = "hello job 123"
417 stubs.api.pipeline_instances().create.assert_called_with(
418 body=JsonDiffMatcher(expect_pipeline))
419 self.assertEqual(capture_stdout.getvalue(),
420 stubs.expect_pipeline_uuid + '\n')
422 @mock.patch("time.sleep")
424 def test_submit_output_tags(self, stubs, tm):
425 output_tags = "tag0,tag1,tag2"
427 capture_stdout = cStringIO.StringIO()
428 exited = arvados_cwl.main(
429 ["--submit", "--no-wait", "--debug", "--output-tags", output_tags,
430 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
431 capture_stdout, sys.stderr, api_client=stubs.api)
432 self.assertEqual(exited, 0)
434 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
435 expect_pipeline["components"]["cwl-runner"]["script_parameters"]["arv:output_tags"] = output_tags
437 stubs.api.pipeline_instances().create.assert_called_with(
438 body=JsonDiffMatcher(expect_pipeline))
439 self.assertEqual(capture_stdout.getvalue(),
440 stubs.expect_pipeline_uuid + '\n')
442 @mock.patch("time.sleep")
444 def test_submit_with_project_uuid(self, stubs, tm):
445 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
447 exited = arvados_cwl.main(
448 ["--submit", "--no-wait", "--debug",
449 "--project-uuid", project_uuid,
450 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
451 sys.stdout, sys.stderr, api_client=stubs.api)
452 self.assertEqual(exited, 0)
454 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
455 expect_pipeline["owner_uuid"] = project_uuid
456 stubs.api.pipeline_instances().create.assert_called_with(
457 body=JsonDiffMatcher(expect_pipeline))
460 def test_submit_container(self, stubs):
461 capture_stdout = cStringIO.StringIO()
463 exited = arvados_cwl.main(
464 ["--submit", "--no-wait", "--api=containers", "--debug",
465 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
466 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
467 self.assertEqual(exited, 0)
469 logging.exception("")
471 stubs.api.collections().create.assert_has_calls([
472 mock.call(body=JsonDiffMatcher({
474 '. 5bcc9fe8f8d5992e6cf418dc7ce4dbb3+16 0:16:blub.txt\n',
475 'replication_desired': None,
476 'name': 'submit_tool.cwl dependencies',
477 }), ensure_unique_name=True),
478 mock.call(body=JsonDiffMatcher({
480 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
481 'replication_desired': None,
482 'name': 'submit_wf.cwl input',
483 }), ensure_unique_name=True)])
485 expect_container = copy.deepcopy(stubs.expect_container_spec)
486 stubs.api.container_requests().create.assert_called_with(
487 body=JsonDiffMatcher(expect_container))
488 self.assertEqual(capture_stdout.getvalue(),
489 stubs.expect_container_request_uuid + '\n')
492 def test_submit_container_no_reuse(self, stubs):
493 capture_stdout = cStringIO.StringIO()
495 exited = arvados_cwl.main(
496 ["--submit", "--no-wait", "--api=containers", "--debug", "--disable-reuse",
497 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
498 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
499 self.assertEqual(exited, 0)
501 logging.exception("")
503 expect_container = copy.deepcopy(stubs.expect_container_spec)
504 expect_container["command"] = [
505 'arvados-cwl-runner', '--local', '--api=containers',
506 '--no-log-timestamps', '--disable-validate',
507 '--eval-timeout=20', '--thread-count=4',
508 '--disable-reuse', '--debug', '--on-error=continue',
509 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
510 expect_container["use_existing"] = False
512 stubs.api.container_requests().create.assert_called_with(
513 body=JsonDiffMatcher(expect_container))
514 self.assertEqual(capture_stdout.getvalue(),
515 stubs.expect_container_request_uuid + '\n')
519 def test_submit_container_reuse_disabled_by_workflow(self, stubs):
520 capture_stdout = cStringIO.StringIO()
522 exited = arvados_cwl.main(
523 ["--submit", "--no-wait", "--api=containers", "--debug",
524 "tests/wf/submit_wf_no_reuse.cwl", "tests/submit_test_job.json"],
525 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
526 self.assertEqual(exited, 0)
528 expect_container = copy.deepcopy(stubs.expect_container_spec)
529 expect_container["command"] = [
530 'arvados-cwl-runner', '--local', '--api=containers',
531 '--no-log-timestamps', '--disable-validate',
532 '--eval-timeout=20', '--thread-count=4',
533 '--disable-reuse', '--debug', '--on-error=continue',
534 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
535 expect_container["use_existing"] = False
536 expect_container["name"] = "submit_wf_no_reuse.cwl"
537 expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$graph"][1]["hints"] = [
539 "class": "http://arvados.org/cwl#ReuseRequirement",
540 "enableReuse": False,
543 expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$graph"][0]["$namespaces"] = {
544 "arv": "http://arvados.org/cwl#",
545 "cwltool": "http://commonwl.org/cwltool#"
548 stubs.api.container_requests().create.assert_called_with(
549 body=JsonDiffMatcher(expect_container))
550 self.assertEqual(capture_stdout.getvalue(),
551 stubs.expect_container_request_uuid + '\n')
555 def test_submit_container_on_error(self, stubs):
556 capture_stdout = cStringIO.StringIO()
558 exited = arvados_cwl.main(
559 ["--submit", "--no-wait", "--api=containers", "--debug", "--on-error=stop",
560 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
561 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
562 self.assertEqual(exited, 0)
564 logging.exception("")
566 expect_container = copy.deepcopy(stubs.expect_container_spec)
567 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
568 '--no-log-timestamps', '--disable-validate',
569 '--eval-timeout=20', '--thread-count=4',
570 '--enable-reuse', '--debug', '--on-error=stop',
571 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
573 stubs.api.container_requests().create.assert_called_with(
574 body=JsonDiffMatcher(expect_container))
575 self.assertEqual(capture_stdout.getvalue(),
576 stubs.expect_container_request_uuid + '\n')
579 def test_submit_container_output_name(self, stubs):
580 output_name = "test_output_name"
582 capture_stdout = cStringIO.StringIO()
584 exited = arvados_cwl.main(
585 ["--submit", "--no-wait", "--api=containers", "--debug", "--output-name", output_name,
586 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
587 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
588 self.assertEqual(exited, 0)
590 logging.exception("")
592 expect_container = copy.deepcopy(stubs.expect_container_spec)
593 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
594 '--no-log-timestamps', '--disable-validate',
595 '--eval-timeout=20', '--thread-count=4',
597 "--output-name="+output_name, '--debug', '--on-error=continue',
598 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
599 expect_container["output_name"] = output_name
601 stubs.api.container_requests().create.assert_called_with(
602 body=JsonDiffMatcher(expect_container))
603 self.assertEqual(capture_stdout.getvalue(),
604 stubs.expect_container_request_uuid + '\n')
608 def test_submit_container_output_ttl(self, stubs):
609 capture_stdout = cStringIO.StringIO()
611 exited = arvados_cwl.main(
612 ["--submit", "--no-wait", "--api=containers", "--debug", "--intermediate-output-ttl", "3600",
613 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
614 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
615 self.assertEqual(exited, 0)
617 logging.exception("")
619 expect_container = copy.deepcopy(stubs.expect_container_spec)
620 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
621 '--no-log-timestamps', '--disable-validate',
622 '--eval-timeout=20', '--thread-count=4',
623 '--enable-reuse', '--debug', '--on-error=continue',
624 "--intermediate-output-ttl=3600",
625 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
627 stubs.api.container_requests().create.assert_called_with(
628 body=JsonDiffMatcher(expect_container))
629 self.assertEqual(capture_stdout.getvalue(),
630 stubs.expect_container_request_uuid + '\n')
633 def test_submit_container_trash_intermediate(self, stubs):
634 capture_stdout = cStringIO.StringIO()
636 exited = arvados_cwl.main(
637 ["--submit", "--no-wait", "--api=containers", "--debug", "--trash-intermediate",
638 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
639 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
640 self.assertEqual(exited, 0)
642 logging.exception("")
644 expect_container = copy.deepcopy(stubs.expect_container_spec)
645 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
646 '--no-log-timestamps', '--disable-validate',
647 '--eval-timeout=20', '--thread-count=4',
648 '--enable-reuse', '--debug', '--on-error=continue',
649 "--trash-intermediate",
650 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
652 stubs.api.container_requests().create.assert_called_with(
653 body=JsonDiffMatcher(expect_container))
654 self.assertEqual(capture_stdout.getvalue(),
655 stubs.expect_container_request_uuid + '\n')
658 def test_submit_container_output_tags(self, stubs):
659 output_tags = "tag0,tag1,tag2"
661 capture_stdout = cStringIO.StringIO()
663 exited = arvados_cwl.main(
664 ["--submit", "--no-wait", "--api=containers", "--debug", "--output-tags", output_tags,
665 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
666 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
667 self.assertEqual(exited, 0)
669 logging.exception("")
671 expect_container = copy.deepcopy(stubs.expect_container_spec)
672 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
673 '--no-log-timestamps', '--disable-validate',
674 '--eval-timeout=20', '--thread-count=4',
676 "--output-tags="+output_tags, '--debug', '--on-error=continue',
677 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
679 stubs.api.container_requests().create.assert_called_with(
680 body=JsonDiffMatcher(expect_container))
681 self.assertEqual(capture_stdout.getvalue(),
682 stubs.expect_container_request_uuid + '\n')
685 def test_submit_container_runner_ram(self, stubs):
686 capture_stdout = cStringIO.StringIO()
688 exited = arvados_cwl.main(
689 ["--submit", "--no-wait", "--api=containers", "--debug", "--submit-runner-ram=2048",
690 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
691 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
692 self.assertEqual(exited, 0)
694 logging.exception("")
696 expect_container = copy.deepcopy(stubs.expect_container_spec)
697 expect_container["runtime_constraints"]["ram"] = 2048*1024*1024
699 stubs.api.container_requests().create.assert_called_with(
700 body=JsonDiffMatcher(expect_container))
701 self.assertEqual(capture_stdout.getvalue(),
702 stubs.expect_container_request_uuid + '\n')
704 @mock.patch("arvados.collection.CollectionReader")
705 @mock.patch("time.sleep")
707 def test_submit_file_keepref(self, stubs, tm, collectionReader):
708 capture_stdout = cStringIO.StringIO()
709 exited = arvados_cwl.main(
710 ["--submit", "--no-wait", "--api=containers", "--debug",
711 "tests/wf/submit_keepref_wf.cwl"],
712 capture_stdout, sys.stderr, api_client=stubs.api)
713 self.assertEqual(exited, 0)
716 @mock.patch("arvados.collection.CollectionReader")
717 @mock.patch("time.sleep")
719 def test_submit_keepref(self, stubs, tm, reader):
720 capture_stdout = cStringIO.StringIO()
722 with open("tests/wf/expect_arvworkflow.cwl") as f:
723 reader().open().__enter__().read.return_value = f.read()
725 exited = arvados_cwl.main(
726 ["--submit", "--no-wait", "--api=containers", "--debug",
727 "keep:99999999999999999999999999999994+99/expect_arvworkflow.cwl#main", "-x", "XxX"],
728 capture_stdout, sys.stderr, api_client=stubs.api)
729 self.assertEqual(exited, 0)
739 'path': '/var/spool/cwl/cwl.output.json',
742 '/var/lib/cwl/workflow': {
743 'portable_data_hash': '99999999999999999999999999999994+99',
746 '/var/lib/cwl/cwl.input.json': {
752 }, 'state': 'Committed',
753 'output_path': '/var/spool/cwl',
754 'name': 'expect_arvworkflow.cwl#main',
755 'container_image': 'arvados/jobs:'+arvados_cwl.__version__,
756 'command': ['arvados-cwl-runner', '--local', '--api=containers',
757 '--no-log-timestamps', '--disable-validate',
758 '--eval-timeout=20', '--thread-count=4',
759 '--enable-reuse', '--debug', '--on-error=continue',
760 '/var/lib/cwl/workflow/expect_arvworkflow.cwl#main', '/var/lib/cwl/cwl.input.json'],
761 'cwd': '/var/spool/cwl',
762 'runtime_constraints': {
767 'use_existing': True,
772 stubs.api.container_requests().create.assert_called_with(
773 body=JsonDiffMatcher(expect_container))
774 self.assertEqual(capture_stdout.getvalue(),
775 stubs.expect_container_request_uuid + '\n')
778 @mock.patch("arvados.collection.CollectionReader")
779 @mock.patch("time.sleep")
781 def test_submit_jobs_keepref(self, stubs, tm, reader):
782 capture_stdout = cStringIO.StringIO()
784 with open("tests/wf/expect_arvworkflow.cwl") as f:
785 reader().open().__enter__().read.return_value = f.read()
787 exited = arvados_cwl.main(
788 ["--submit", "--no-wait", "--api=jobs", "--debug",
789 "keep:99999999999999999999999999999994+99/expect_arvworkflow.cwl#main", "-x", "XxX"],
790 capture_stdout, sys.stderr, api_client=stubs.api)
791 self.assertEqual(exited, 0)
793 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
794 expect_pipeline["components"]["cwl-runner"]["script_parameters"]["x"] = "XxX"
795 del expect_pipeline["components"]["cwl-runner"]["script_parameters"]["y"]
796 del expect_pipeline["components"]["cwl-runner"]["script_parameters"]["z"]
797 expect_pipeline["components"]["cwl-runner"]["script_parameters"]["cwl:tool"] = "99999999999999999999999999999994+99/expect_arvworkflow.cwl#main"
798 expect_pipeline["name"] = "expect_arvworkflow.cwl#main"
799 stubs.api.pipeline_instances().create.assert_called_with(
800 body=JsonDiffMatcher(expect_pipeline))
802 @mock.patch("time.sleep")
804 def test_submit_arvworkflow(self, stubs, tm):
805 capture_stdout = cStringIO.StringIO()
807 with open("tests/wf/expect_arvworkflow.cwl") as f:
808 stubs.api.workflows().get().execute.return_value = {"definition": f.read(), "name": "a test workflow"}
810 exited = arvados_cwl.main(
811 ["--submit", "--no-wait", "--api=containers", "--debug",
812 "962eh-7fd4e-gkbzl62qqtfig37", "-x", "XxX"],
813 capture_stdout, sys.stderr, api_client=stubs.api)
814 self.assertEqual(exited, 0)
824 'path': '/var/spool/cwl/cwl.output.json',
827 '/var/lib/cwl/workflow.json': {
830 'cwlVersion': 'v1.0',
835 {'type': 'string', 'id': '#main/x'}
838 {'in': [{'source': '#main/x', 'id': '#main/step1/x'}],
839 'run': '#submit_tool.cwl',
849 'inputBinding': {'position': 1},
851 'id': '#submit_tool.cwl/x'}
854 {'dockerPull': 'debian:8', 'class': 'DockerRequirement'}
856 'id': '#submit_tool.cwl',
858 'baseCommand': 'cat',
859 'class': 'CommandLineTool'
864 '/var/lib/cwl/cwl.input.json': {
870 }, 'state': 'Committed',
871 'output_path': '/var/spool/cwl',
872 'name': 'a test workflow',
873 'container_image': 'arvados/jobs:'+arvados_cwl.__version__,
874 'command': ['arvados-cwl-runner', '--local', '--api=containers',
875 '--no-log-timestamps', '--disable-validate',
876 '--eval-timeout=20', '--thread-count=4',
877 '--enable-reuse', '--debug', '--on-error=continue',
878 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'],
879 'cwd': '/var/spool/cwl',
880 'runtime_constraints': {
885 'use_existing': True,
887 "template_uuid": "962eh-7fd4e-gkbzl62qqtfig37"
892 stubs.api.container_requests().create.assert_called_with(
893 body=JsonDiffMatcher(expect_container))
894 self.assertEqual(capture_stdout.getvalue(),
895 stubs.expect_container_request_uuid + '\n')
899 def test_submit_container_name(self, stubs):
900 capture_stdout = cStringIO.StringIO()
902 exited = arvados_cwl.main(
903 ["--submit", "--no-wait", "--api=containers", "--debug", "--name=hello container 123",
904 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
905 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
906 self.assertEqual(exited, 0)
908 logging.exception("")
910 expect_container = copy.deepcopy(stubs.expect_container_spec)
911 expect_container["name"] = "hello container 123"
913 stubs.api.container_requests().create.assert_called_with(
914 body=JsonDiffMatcher(expect_container))
915 self.assertEqual(capture_stdout.getvalue(),
916 stubs.expect_container_request_uuid + '\n')
920 def test_submit_container_project(self, stubs):
921 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
922 capture_stdout = cStringIO.StringIO()
924 exited = arvados_cwl.main(
925 ["--submit", "--no-wait", "--api=containers", "--debug", "--project-uuid="+project_uuid,
926 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
927 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
928 self.assertEqual(exited, 0)
930 logging.exception("")
932 expect_container = copy.deepcopy(stubs.expect_container_spec)
933 expect_container["owner_uuid"] = project_uuid
934 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
935 '--no-log-timestamps', '--disable-validate',
936 "--eval-timeout=20", "--thread-count=4",
937 '--enable-reuse', '--debug', '--on-error=continue',
938 '--project-uuid='+project_uuid,
939 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
941 stubs.api.container_requests().create.assert_called_with(
942 body=JsonDiffMatcher(expect_container))
943 self.assertEqual(capture_stdout.getvalue(),
944 stubs.expect_container_request_uuid + '\n')
947 def test_submit_container_eval_timeout(self, stubs):
948 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
949 capture_stdout = cStringIO.StringIO()
951 exited = arvados_cwl.main(
952 ["--submit", "--no-wait", "--api=containers", "--debug", "--eval-timeout=60",
953 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
954 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
955 self.assertEqual(exited, 0)
957 logging.exception("")
959 expect_container = copy.deepcopy(stubs.expect_container_spec)
960 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
961 '--no-log-timestamps', '--disable-validate',
962 '--eval-timeout=60.0', '--thread-count=4',
963 '--enable-reuse', '--debug', '--on-error=continue',
964 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
966 stubs.api.container_requests().create.assert_called_with(
967 body=JsonDiffMatcher(expect_container))
968 self.assertEqual(capture_stdout.getvalue(),
969 stubs.expect_container_request_uuid + '\n')
973 def test_submit_container_thread_count(self, stubs):
974 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
975 capture_stdout = cStringIO.StringIO()
977 exited = arvados_cwl.main(
978 ["--submit", "--no-wait", "--api=containers", "--debug", "--thread-count=20",
979 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
980 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
981 self.assertEqual(exited, 0)
983 logging.exception("")
985 expect_container = copy.deepcopy(stubs.expect_container_spec)
986 expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
987 '--no-log-timestamps', '--disable-validate',
988 '--eval-timeout=20', '--thread-count=20',
989 '--enable-reuse', '--debug', '--on-error=continue',
990 '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
992 stubs.api.container_requests().create.assert_called_with(
993 body=JsonDiffMatcher(expect_container))
994 self.assertEqual(capture_stdout.getvalue(),
995 stubs.expect_container_request_uuid + '\n')
999 def test_submit_job_runner_image(self, stubs):
1000 capture_stdout = cStringIO.StringIO()
1002 exited = arvados_cwl.main(
1003 ["--submit", "--no-wait", "--api=jobs", "--debug", "--submit-runner-image=arvados/jobs:123",
1004 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1005 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
1006 self.assertEqual(exited, 0)
1008 logging.exception("")
1010 stubs.expect_pipeline_instance["components"]["cwl-runner"]["runtime_constraints"]["docker_image"] = "arvados/jobs:123"
1012 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
1013 stubs.api.pipeline_instances().create.assert_called_with(
1014 body=JsonDiffMatcher(expect_pipeline))
1015 self.assertEqual(capture_stdout.getvalue(),
1016 stubs.expect_pipeline_uuid + '\n')
1019 def test_submit_container_runner_image(self, stubs):
1020 capture_stdout = cStringIO.StringIO()
1022 exited = arvados_cwl.main(
1023 ["--submit", "--no-wait", "--api=containers", "--debug", "--submit-runner-image=arvados/jobs:123",
1024 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1025 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
1026 self.assertEqual(exited, 0)
1028 logging.exception("")
1030 stubs.expect_container_spec["container_image"] = "arvados/jobs:123"
1032 expect_container = copy.deepcopy(stubs.expect_container_spec)
1033 stubs.api.container_requests().create.assert_called_with(
1034 body=JsonDiffMatcher(expect_container))
1035 self.assertEqual(capture_stdout.getvalue(),
1036 stubs.expect_container_request_uuid + '\n')
1039 def test_submit_priority(self, stubs):
1040 capture_stdout = cStringIO.StringIO()
1042 exited = arvados_cwl.main(
1043 ["--submit", "--no-wait", "--api=containers", "--debug", "--priority=669",
1044 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1045 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
1046 self.assertEqual(exited, 0)
1048 logging.exception("")
1050 stubs.expect_container_spec["priority"] = 669
1052 expect_container = copy.deepcopy(stubs.expect_container_spec)
1053 stubs.api.container_requests().create.assert_called_with(
1054 body=JsonDiffMatcher(expect_container))
1055 self.assertEqual(capture_stdout.getvalue(),
1056 stubs.expect_container_request_uuid + '\n')
1059 @mock.patch("arvados.commands.keepdocker.find_one_image_hash")
1060 @mock.patch("cwltool.docker.DockerCommandLineJob.get_image")
1061 @mock.patch("arvados.api")
1062 def test_arvados_jobs_image(self, api, get_image, find_one_image_hash):
1063 arvrunner = mock.MagicMock()
1064 arvrunner.project_uuid = ""
1065 api.return_value = mock.MagicMock()
1066 arvrunner.api = api.return_value
1067 arvrunner.api.links().list().execute.side_effect = ({"items": [{"created_at": "",
1068 "head_uuid": "zzzzz-4zz18-zzzzzzzzzzzzzzb",
1069 "link_class": "docker_image_repo+tag",
1070 "name": "arvados/jobs:"+arvados_cwl.__version__,
1072 "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0},
1073 {"items": [{"created_at": "",
1075 "link_class": "docker_image_hash",
1078 "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0}
1080 find_one_image_hash.return_value = "123456"
1082 arvrunner.api.collections().list().execute.side_effect = ({"items": [{"uuid": "zzzzz-4zz18-zzzzzzzzzzzzzzb",
1084 "manifest_text": "",
1086 }], "items_available": 1, "offset": 0},)
1087 arvrunner.api.collections().create().execute.return_value = {"uuid": ""}
1088 self.assertEqual("arvados/jobs:"+arvados_cwl.__version__,
1089 arvados_cwl.runner.arvados_jobs_image(arvrunner, "arvados/jobs:"+arvados_cwl.__version__))
1092 def test_submit_secrets(self, stubs):
1093 capture_stdout = cStringIO.StringIO()
1095 exited = arvados_cwl.main(
1096 ["--submit", "--no-wait", "--api=containers", "--debug",
1097 "tests/wf/secret_wf.cwl", "tests/secret_test_job.yml"],
1098 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
1099 self.assertEqual(exited, 0)
1101 logging.exception("")
1104 expect_container = {
1106 "arvados-cwl-runner",
1109 "--no-log-timestamps",
1110 "--disable-validate",
1111 "--eval-timeout=20",
1115 "--on-error=continue",
1116 "/var/lib/cwl/workflow.json#main",
1117 "/var/lib/cwl/cwl.input.json"
1119 "container_image": "arvados/jobs:"+arvados_cwl.__version__,
1120 "cwd": "/var/spool/cwl",
1122 "/var/lib/cwl/cwl.input.json": {
1125 "$include": "/secrets/s0"
1130 "/var/lib/cwl/workflow.json": {
1135 "cwltool": "http://commonwl.org/cwltool#"
1141 "class": "CommandLineTool",
1144 "class": "http://commonwl.org/cwltool#Secrets",
1146 "#secret_job.cwl/pw"
1150 "id": "#secret_job.cwl",
1153 "id": "#secret_job.cwl/pw",
1159 "id": "#secret_job.cwl/out",
1163 "stdout": "hashed_example.txt",
1166 "class": "InitialWorkDirRequirement",
1169 "entry": "username: user\npassword: $(inputs.pw)\n",
1170 "entryname": "example.conf"
1177 "class": "Workflow",
1180 "class": "DockerRequirement",
1181 "dockerPull": "debian:8"
1184 "class": "http://commonwl.org/cwltool#Secrets",
1200 "outputSource": "#main/step1/out",
1206 "id": "#main/step1",
1209 "id": "#main/step1/pw",
1210 "source": "#main/pw"
1216 "run": "#secret_job.cwl"
1221 "cwlVersion": "v1.0"
1226 "kind": "collection",
1231 "path": "/var/spool/cwl/cwl.output.json"
1234 "name": "secret_wf.cwl",
1235 "output_path": "/var/spool/cwl",
1238 "runtime_constraints": {
1249 "state": "Committed",
1250 "use_existing": True
1253 stubs.api.container_requests().create.assert_called_with(
1254 body=JsonDiffMatcher(expect_container))
1255 self.assertEqual(capture_stdout.getvalue(),
1256 stubs.expect_container_request_uuid + '\n')
1259 def test_submit_request_uuid(self, stubs):
1260 stubs.expect_container_request_uuid = "zzzzz-xvhdp-yyyyyyyyyyyyyyy"
1262 stubs.api.container_requests().update().execute.return_value = {
1263 "uuid": stubs.expect_container_request_uuid,
1264 "container_uuid": "zzzzz-dz642-zzzzzzzzzzzzzzz",
1268 capture_stdout = cStringIO.StringIO()
1270 exited = arvados_cwl.main(
1271 ["--submit", "--no-wait", "--api=containers", "--debug", "--submit-request-uuid=zzzzz-xvhdp-yyyyyyyyyyyyyyy",
1272 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1273 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
1274 self.assertEqual(exited, 0)
1276 logging.exception("")
1278 stubs.api.container_requests().update.assert_called_with(
1279 uuid="zzzzz-xvhdp-yyyyyyyyyyyyyyy", body=JsonDiffMatcher(stubs.expect_container_spec))
1280 self.assertEqual(capture_stdout.getvalue(),
1281 stubs.expect_container_request_uuid + '\n')
1284 class TestCreateTemplate(unittest.TestCase):
1285 existing_template_uuid = "zzzzz-d1hrv-validworkfloyml"
1287 def _adjust_script_params(self, expect_component):
1288 expect_component['script_parameters']['x'] = {
1289 'dataclass': 'File',
1292 'value': '169f39d466a5438ac4a90e779bf750c7+53/blorp.txt',
1294 expect_component['script_parameters']['y'] = {
1295 'dataclass': 'Collection',
1297 'type': 'Directory',
1298 'value': '99999999999999999999999999999998+99',
1300 expect_component['script_parameters']['z'] = {
1301 'dataclass': 'Collection',
1303 'type': 'Directory',
1307 def test_create(self, stubs):
1308 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
1310 capture_stdout = cStringIO.StringIO()
1312 exited = arvados_cwl.main(
1313 ["--create-workflow", "--debug",
1315 "--project-uuid", project_uuid,
1316 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1317 capture_stdout, sys.stderr, api_client=stubs.api)
1318 self.assertEqual(exited, 0)
1320 stubs.api.pipeline_instances().create.refute_called()
1321 stubs.api.jobs().create.refute_called()
1323 expect_component = copy.deepcopy(stubs.expect_job_spec)
1324 self._adjust_script_params(expect_component)
1327 "submit_wf.cwl": expect_component,
1329 "name": "submit_wf.cwl",
1330 "owner_uuid": project_uuid,
1332 stubs.api.pipeline_templates().create.assert_called_with(
1333 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
1335 self.assertEqual(capture_stdout.getvalue(),
1336 stubs.expect_pipeline_template_uuid + '\n')
1340 def test_create_name(self, stubs):
1341 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
1343 capture_stdout = cStringIO.StringIO()
1345 exited = arvados_cwl.main(
1346 ["--create-workflow", "--debug",
1347 "--project-uuid", project_uuid,
1349 "--name", "testing 123",
1350 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1351 capture_stdout, sys.stderr, api_client=stubs.api)
1352 self.assertEqual(exited, 0)
1354 stubs.api.pipeline_instances().create.refute_called()
1355 stubs.api.jobs().create.refute_called()
1357 expect_component = copy.deepcopy(stubs.expect_job_spec)
1358 self._adjust_script_params(expect_component)
1361 "testing 123": expect_component,
1363 "name": "testing 123",
1364 "owner_uuid": project_uuid,
1366 stubs.api.pipeline_templates().create.assert_called_with(
1367 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
1369 self.assertEqual(capture_stdout.getvalue(),
1370 stubs.expect_pipeline_template_uuid + '\n')
1374 def test_update_name(self, stubs):
1375 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
1377 capture_stdout = cStringIO.StringIO()
1379 exited = arvados_cwl.main(
1380 ["--update-workflow", self.existing_template_uuid,
1382 "--project-uuid", project_uuid,
1384 "--name", "testing 123",
1385 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1386 capture_stdout, sys.stderr, api_client=stubs.api)
1387 self.assertEqual(exited, 0)
1389 stubs.api.pipeline_instances().create.refute_called()
1390 stubs.api.jobs().create.refute_called()
1392 expect_component = copy.deepcopy(stubs.expect_job_spec)
1393 self._adjust_script_params(expect_component)
1396 "testing 123": expect_component,
1398 "name": "testing 123",
1399 "owner_uuid": project_uuid,
1401 stubs.api.pipeline_templates().create.refute_called()
1402 stubs.api.pipeline_templates().update.assert_called_with(
1403 body=JsonDiffMatcher(expect_template), uuid=self.existing_template_uuid)
1405 self.assertEqual(capture_stdout.getvalue(),
1406 self.existing_template_uuid + '\n')
1409 class TestCreateWorkflow(unittest.TestCase):
1410 existing_workflow_uuid = "zzzzz-7fd4e-validworkfloyml"
1411 expect_workflow = StripYAMLComments(
1412 open("tests/wf/expect_packed.cwl").read())
1415 def test_create(self, stubs):
1416 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
1418 capture_stdout = cStringIO.StringIO()
1420 exited = arvados_cwl.main(
1421 ["--create-workflow", "--debug",
1423 "--project-uuid", project_uuid,
1424 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1425 capture_stdout, sys.stderr, api_client=stubs.api)
1426 self.assertEqual(exited, 0)
1428 stubs.api.pipeline_templates().create.refute_called()
1429 stubs.api.container_requests().create.refute_called()
1433 "owner_uuid": project_uuid,
1434 "name": "submit_wf.cwl",
1436 "definition": self.expect_workflow,
1439 stubs.api.workflows().create.assert_called_with(
1440 body=JsonDiffMatcher(body))
1442 self.assertEqual(capture_stdout.getvalue(),
1443 stubs.expect_workflow_uuid + '\n')
1447 def test_create_name(self, stubs):
1448 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
1450 capture_stdout = cStringIO.StringIO()
1452 exited = arvados_cwl.main(
1453 ["--create-workflow", "--debug",
1455 "--project-uuid", project_uuid,
1456 "--name", "testing 123",
1457 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1458 capture_stdout, sys.stderr, api_client=stubs.api)
1459 self.assertEqual(exited, 0)
1461 stubs.api.pipeline_templates().create.refute_called()
1462 stubs.api.container_requests().create.refute_called()
1466 "owner_uuid": project_uuid,
1467 "name": "testing 123",
1469 "definition": self.expect_workflow,
1472 stubs.api.workflows().create.assert_called_with(
1473 body=JsonDiffMatcher(body))
1475 self.assertEqual(capture_stdout.getvalue(),
1476 stubs.expect_workflow_uuid + '\n')
1479 def test_incompatible_api(self, stubs):
1480 capture_stderr = cStringIO.StringIO()
1481 logging.getLogger('arvados.cwl-runner').addHandler(
1482 logging.StreamHandler(capture_stderr))
1484 exited = arvados_cwl.main(
1485 ["--update-workflow", self.existing_workflow_uuid,
1488 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1489 sys.stderr, sys.stderr, api_client=stubs.api)
1490 self.assertEqual(exited, 1)
1491 self.assertRegexpMatches(
1492 capture_stderr.getvalue(),
1493 "--update-workflow arg '{}' uses 'containers' API, but --api='jobs' specified".format(self.existing_workflow_uuid))
1496 def test_update(self, stubs):
1497 capture_stdout = cStringIO.StringIO()
1499 exited = arvados_cwl.main(
1500 ["--update-workflow", self.existing_workflow_uuid,
1502 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1503 capture_stdout, sys.stderr, api_client=stubs.api)
1504 self.assertEqual(exited, 0)
1508 "name": "submit_wf.cwl",
1510 "definition": self.expect_workflow,
1513 stubs.api.workflows().update.assert_called_with(
1514 uuid=self.existing_workflow_uuid,
1515 body=JsonDiffMatcher(body))
1516 self.assertEqual(capture_stdout.getvalue(),
1517 self.existing_workflow_uuid + '\n')
1521 def test_update_name(self, stubs):
1522 capture_stdout = cStringIO.StringIO()
1524 exited = arvados_cwl.main(
1525 ["--update-workflow", self.existing_workflow_uuid,
1526 "--debug", "--name", "testing 123",
1527 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
1528 capture_stdout, sys.stderr, api_client=stubs.api)
1529 self.assertEqual(exited, 0)
1533 "name": "testing 123",
1535 "definition": self.expect_workflow,
1538 stubs.api.workflows().update.assert_called_with(
1539 uuid=self.existing_workflow_uuid,
1540 body=JsonDiffMatcher(body))
1541 self.assertEqual(capture_stdout.getvalue(),
1542 self.existing_workflow_uuid + '\n')
1546 def test_create_collection_per_tool(self, stubs):
1547 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
1549 capture_stdout = cStringIO.StringIO()
1551 exited = arvados_cwl.main(
1552 ["--create-workflow", "--debug",
1554 "--project-uuid", project_uuid,
1555 "tests/collection_per_tool/collection_per_tool.cwl"],
1556 capture_stdout, sys.stderr, api_client=stubs.api)
1557 self.assertEqual(exited, 0)
1559 toolfile = "tests/collection_per_tool/collection_per_tool_packed.cwl"
1560 expect_workflow = StripYAMLComments(open(toolfile).read())
1564 "owner_uuid": project_uuid,
1565 "name": "collection_per_tool.cwl",
1567 "definition": expect_workflow,
1570 stubs.api.workflows().create.assert_called_with(
1571 body=JsonDiffMatcher(body))
1573 self.assertEqual(capture_stdout.getvalue(),
1574 stubs.expect_workflow_uuid + '\n')
1576 class TestTemplateInputs(unittest.TestCase):
1579 "inputs_test.cwl": {
1580 'runtime_constraints': {
1581 'docker_image': 'arvados/jobs:'+arvados_cwl.__version__,
1582 'min_ram_mb_per_node': 1024
1584 'script_parameters': {
1586 '6c5ee1cd606088106d9f28367cde1e41+60/workflow.cwl#main',
1587 'optionalFloatInput': None,
1590 'dataclass': 'File',
1592 'title': "It's a file; we expect to find some characters in it.",
1593 'description': 'If there were anything further to say, it would be said here,\nor here.'
1597 'dataclass': 'number',
1599 'title': 'Floats like a duck',
1603 'optionalFloatInput': {
1604 'type': ['null', 'float'],
1605 'dataclass': 'number',
1610 'dataclass': 'boolean',
1612 'title': 'True or false?',
1615 'repository': 'arvados',
1616 'script_version': 'master',
1617 'minimum_script_version': '570509ab4d2ef93d870fd2b1f2eab178afb1bad9',
1618 'script': 'cwl-runner',
1621 "name": "inputs_test.cwl",
1625 def test_inputs_empty(self, stubs):
1626 exited = arvados_cwl.main(
1627 ["--create-template",
1628 "tests/wf/inputs_test.cwl", "tests/order/empty_order.json"],
1629 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
1630 self.assertEqual(exited, 0)
1632 stubs.api.pipeline_templates().create.assert_called_with(
1633 body=JsonDiffMatcher(self.expect_template), ensure_unique_name=True)
1636 def test_inputs(self, stubs):
1637 exited = arvados_cwl.main(
1638 ["--create-template",
1639 "tests/wf/inputs_test.cwl", "tests/order/inputs_test_order.json"],
1640 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
1641 self.assertEqual(exited, 0)
1643 expect_template = copy.deepcopy(self.expect_template)
1644 params = expect_template[
1645 "components"]["inputs_test.cwl"]["script_parameters"]
1646 params["fileInput"]["value"] = '169f39d466a5438ac4a90e779bf750c7+53/blorp.txt'
1647 params["cwl:tool"] = '6c5ee1cd606088106d9f28367cde1e41+60/workflow.cwl#main'
1648 params["floatInput"]["value"] = 1.234
1649 params["boolInput"]["value"] = True
1651 stubs.api.pipeline_templates().create.assert_called_with(
1652 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)