X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/e97a5d828bdf7cb9626d72efd94d3bcf718a18c9..a89fbc8b4f2d8db8654175428bd1f041eed6f109:/sdk/cwl/tests/test_submit.py diff --git a/sdk/cwl/tests/test_submit.py b/sdk/cwl/tests/test_submit.py index d2dd6e8162..305d51e144 100644 --- a/sdk/cwl/tests/test_submit.py +++ b/sdk/cwl/tests/test_submit.py @@ -47,17 +47,26 @@ _rootDesc = None def stubs(func): @functools.wraps(func) + @mock.patch("arvados_cwl.arvdocker.determine_image_id") + @mock.patch("uuid.uuid4") @mock.patch("arvados.commands.keepdocker.list_images_in_arv") @mock.patch("arvados.collection.KeepClient") @mock.patch("arvados.keep.KeepClient") @mock.patch("arvados.events.subscribe") - def wrapped(self, events, keep_client1, keep_client2, keepdocker, *args, **kwargs): + def wrapped(self, events, keep_client1, keep_client2, keepdocker, + uuid4, determine_image_id, *args, **kwargs): class Stubs(object): pass stubs = Stubs() stubs.events = events stubs.keepdocker = keepdocker + uuid4.side_effect = ["df80736f-f14d-4b10-b2e3-03aa27f034bb", "df80736f-f14d-4b10-b2e3-03aa27f034b1", + "df80736f-f14d-4b10-b2e3-03aa27f034b2", "df80736f-f14d-4b10-b2e3-03aa27f034b3", + "df80736f-f14d-4b10-b2e3-03aa27f034b4", "df80736f-f14d-4b10-b2e3-03aa27f034b5"] + + determine_image_id.return_value = None + def putstub(p, **kwargs): return "%s+%i" % (hashlib.md5(p).hexdigest(), len(p)) keep_client1().put.side_effect = putstub @@ -67,12 +76,12 @@ def stubs(func): stubs.keep_client = keep_client2 stubs.docker_images = { - "arvados/jobs:"+arvados_cwl.__version__: [("zzzzz-4zz18-zzzzzzzzzzzzzd3", "")], - "debian:8": [("zzzzz-4zz18-zzzzzzzzzzzzzd4", "")], - "arvados/jobs:123": [("zzzzz-4zz18-zzzzzzzzzzzzzd5", "")], - "arvados/jobs:latest": [("zzzzz-4zz18-zzzzzzzzzzzzzd6", "")], + "arvados/jobs:"+arvados_cwl.__version__: [("zzzzz-4zz18-zzzzzzzzzzzzzd3", {})], + "debian:buster-slim": [("zzzzz-4zz18-zzzzzzzzzzzzzd4", {})], + "arvados/jobs:123": [("zzzzz-4zz18-zzzzzzzzzzzzzd5", {})], + "arvados/jobs:latest": [("zzzzz-4zz18-zzzzzzzzzzzzzd6", {})], } - def kd(a, b, image_name=None, image_tag=None): + def kd(a, b, image_name=None, image_tag=None, project_uuid=None): return stubs.docker_images.get("%s:%s" % (image_name, image_tag), []) stubs.keepdocker.side_effect = kd @@ -87,6 +96,7 @@ def stubs(func): stubs.api = mock.MagicMock() stubs.api._rootDesc = get_rootDesc() stubs.api._rootDesc["uuidPrefix"] = "zzzzz" + stubs.api._rootDesc["revision"] = "20210628" stubs.api.users().current().execute.return_value = { "uuid": stubs.fake_user_uuid, @@ -95,6 +105,11 @@ def stubs(func): stubs.api.containers().current().execute.return_value = { "uuid": stubs.fake_container_uuid, } + stubs.api.config()["StorageClasses"].items.return_value = { + "default": { + "Default": True + } + }.items() class CollectionExecute(object): def __init__(self, exe): @@ -303,7 +318,7 @@ def stubs(func): 'state': 'Committed', 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'], 'name': 'submit_wf.cwl', @@ -340,15 +355,14 @@ class TestSubmit(unittest.TestCase): def setUp(self): cwltool.process._names = set() + arvados_cwl.arvdocker.arv_docker_clear_cache() - @stubs - def test_error_when_multiple_storage_classes_specified(self, stubs): - storage_classes = "foo,bar" - exited = arvados_cwl.main( - ["--debug", "--storage-classes", storage_classes, - "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], - sys.stdin, sys.stderr, api_client=stubs.api) - self.assertEqual(exited, 1) + def tearDown(self): + root_logger = logging.getLogger('') + + # Remove existing RuntimeStatusLoggingHandlers if they exist + handlers = [h for h in root_logger.handlers if not isinstance(h, arvados_cwl.executor.RuntimeStatusLoggingHandler)] + root_logger.handlers = handlers @mock.patch("time.sleep") @stubs @@ -413,7 +427,7 @@ class TestSubmit(unittest.TestCase): expect_container["command"] = [ 'arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--disable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -437,7 +451,7 @@ class TestSubmit(unittest.TestCase): expect_container["command"] = [ 'arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--disable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] expect_container["use_existing"] = False @@ -448,7 +462,7 @@ class TestSubmit(unittest.TestCase): "enableReuse": False, }, ] - expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$graph"][0]["$namespaces"] = { + expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$namespaces"] = { "arv": "http://arvados.org/cwl#", "cwltool": "http://commonwl.org/cwltool#" } @@ -469,7 +483,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=stop', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -492,7 +506,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", "--output-name="+output_name, '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -514,7 +528,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", "--debug", "--storage-classes=foo", '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -525,7 +539,28 @@ class TestSubmit(unittest.TestCase): stubs.expect_container_request_uuid + '\n') self.assertEqual(exited, 0) - @mock.patch("arvados_cwl.task_queue.TaskQueue") + @stubs + def test_submit_multiple_storage_classes(self, stubs): + exited = arvados_cwl.main( + ["--debug", "--submit", "--no-wait", "--api=containers", "--storage-classes=foo,bar", "--intermediate-storage-classes=baz", + "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + + expect_container = copy.deepcopy(stubs.expect_container_spec) + expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', + '--no-log-timestamps', '--disable-validate', '--disable-color', + '--eval-timeout=20', '--thread-count=0', + '--enable-reuse', "--collection-cache-size=256", "--debug", + "--storage-classes=foo,bar", "--intermediate-storage-classes=baz", '--on-error=continue', + '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] + + stubs.api.container_requests().create.assert_called_with( + body=JsonDiffMatcher(expect_container)) + self.assertEqual(stubs.capture_stdout.getvalue(), + stubs.expect_container_request_uuid + '\n') + self.assertEqual(exited, 0) + + @mock.patch("cwltool.task_queue.TaskQueue") @mock.patch("arvados_cwl.arvworkflow.ArvadosWorkflow.job") @mock.patch("arvados_cwl.executor.ArvCwlExecutor.make_output_collection") @stubs @@ -546,13 +581,14 @@ class TestSubmit(unittest.TestCase): make_output.assert_called_with(u'Output of submit_wf.cwl', ['foo'], '', 'zzzzz-4zz18-zzzzzzzzzzzzzzzz') self.assertEqual(exited, 0) - @mock.patch("arvados_cwl.task_queue.TaskQueue") + @mock.patch("cwltool.task_queue.TaskQueue") @mock.patch("arvados_cwl.arvworkflow.ArvadosWorkflow.job") @mock.patch("arvados_cwl.executor.ArvCwlExecutor.make_output_collection") @stubs def test_default_storage_classes_correctly_propagate_to_make_output_collection(self, stubs, make_output, job, tq): final_output_c = arvados.collection.Collection() make_output.return_value = ({},final_output_c) + stubs.api.config().get.return_value = {"default": {"Default": True}} def set_final_output(job_order, output_callback, runtimeContext): output_callback("zzzzz-4zz18-zzzzzzzzzzzzzzzz", "success") @@ -567,6 +603,27 @@ class TestSubmit(unittest.TestCase): make_output.assert_called_with(u'Output of submit_wf.cwl', ['default'], '', 'zzzzz-4zz18-zzzzzzzzzzzzzzzz') self.assertEqual(exited, 0) + @mock.patch("cwltool.task_queue.TaskQueue") + @mock.patch("arvados_cwl.arvworkflow.ArvadosWorkflow.job") + @mock.patch("arvados_cwl.executor.ArvCwlExecutor.make_output_collection") + @stubs + def test_storage_class_hint_to_make_output_collection(self, stubs, make_output, job, tq): + final_output_c = arvados.collection.Collection() + make_output.return_value = ({},final_output_c) + + def set_final_output(job_order, output_callback, runtimeContext): + output_callback("zzzzz-4zz18-zzzzzzzzzzzzzzzz", "success") + return [] + job.side_effect = set_final_output + + exited = arvados_cwl.main( + ["--debug", "--local", + "tests/wf/submit_storage_class_wf.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + + make_output.assert_called_with(u'Output of submit_storage_class_wf.cwl', ['foo', 'bar'], '', 'zzzzz-4zz18-zzzzzzzzzzzzzzzz') + self.assertEqual(exited, 0) + @stubs def test_submit_container_output_ttl(self, stubs): exited = arvados_cwl.main( @@ -577,7 +634,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', "--intermediate-output-ttl=3600", @@ -600,7 +657,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', "--trash-intermediate", @@ -624,7 +681,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", "--output-tags="+output_tags, '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -655,6 +712,7 @@ class TestSubmit(unittest.TestCase): @mock.patch("time.sleep") @stubs def test_submit_file_keepref(self, stubs, tm, collectionReader): + collectionReader().exists.return_value = True collectionReader().find.return_value = arvados.arvfile.ArvadosFile(mock.MagicMock(), "blorp.txt") exited = arvados_cwl.main( ["--submit", "--no-wait", "--api=containers", "--debug", @@ -701,7 +759,7 @@ class TestSubmit(unittest.TestCase): 'container_image': '999999999999999999999999999999d3+99', 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', '/var/lib/cwl/workflow/expect_arvworkflow.cwl#main', '/var/lib/cwl/cwl.input.json'], 'cwd': '/var/spool/cwl', @@ -771,7 +829,7 @@ class TestSubmit(unittest.TestCase): ], 'requirements': [ { - 'dockerPull': 'debian:8', + 'dockerPull': 'debian:buster-slim', 'class': 'DockerRequirement', "http://arvados.org/cwl#dockerCollectionPDH": "999999999999999999999999999999d4+99" } @@ -796,7 +854,7 @@ class TestSubmit(unittest.TestCase): 'container_image': "999999999999999999999999999999d3+99", 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'], 'cwd': '/var/spool/cwl', @@ -851,6 +909,7 @@ class TestSubmit(unittest.TestCase): @stubs def test_submit_container_project(self, stubs): project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.groups().get().execute.return_value = {"group_class": "project"} exited = arvados_cwl.main( ["--submit", "--no-wait", "--api=containers", "--debug", "--project-uuid="+project_uuid, "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], @@ -860,7 +919,7 @@ class TestSubmit(unittest.TestCase): expect_container["owner_uuid"] = project_uuid expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - "--eval-timeout=20", "--thread-count=1", + "--eval-timeout=20", "--thread-count=0", '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', '--project-uuid='+project_uuid, @@ -882,7 +941,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=60.0', '--thread-count=1', + '--eval-timeout=60.0', '--thread-count=0', '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -903,7 +962,7 @@ class TestSubmit(unittest.TestCase): expect_container = copy.deepcopy(stubs.expect_container_spec) expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=500", '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -990,12 +1049,12 @@ class TestSubmit(unittest.TestCase): "keep_cache": 512 } ] - expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$graph"][0]["$namespaces"] = { + expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$namespaces"] = { "arv": "http://arvados.org/cwl#", } expect_container['command'] = ['arvados-cwl-runner', '--local', '--api=containers', '--no-log-timestamps', '--disable-validate', '--disable-color', - '--eval-timeout=20', '--thread-count=1', + '--eval-timeout=20', '--thread-count=0', '--enable-reuse', "--collection-cache-size=512", '--debug', '--on-error=continue', '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] @@ -1005,9 +1064,6 @@ class TestSubmit(unittest.TestCase): stubs.expect_container_request_uuid + '\n') self.assertEqual(exited, 0) - def tearDown(self): - arvados_cwl.arvdocker.arv_docker_clear_cache() - @mock.patch("arvados.commands.keepdocker.find_one_image_hash") @mock.patch("cwltool.docker.DockerCommandLineJob.get_image") @mock.patch("arvados.api") @@ -1018,12 +1074,25 @@ class TestSubmit(unittest.TestCase): arvrunner.project_uuid = "" api.return_value = mock.MagicMock() arvrunner.api = api.return_value + arvrunner.runtimeContext.match_local_docker = False arvrunner.api.links().list().execute.side_effect = ({"items": [{"created_at": "", "head_uuid": "zzzzz-4zz18-zzzzzzzzzzzzzzb", "link_class": "docker_image_repo+tag", "name": "arvados/jobs:"+arvados_cwl.__version__, "owner_uuid": "", "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0}, + {"items": [{"created_at": "", + "head_uuid": "", + "link_class": "docker_image_hash", + "name": "123456", + "owner_uuid": "", + "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0}, + {"items": [{"created_at": "", + "head_uuid": "zzzzz-4zz18-zzzzzzzzzzzzzzb", + "link_class": "docker_image_repo+tag", + "name": "arvados/jobs:"+arvados_cwl.__version__, + "owner_uuid": "", + "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0}, {"items": [{"created_at": "", "head_uuid": "", "link_class": "docker_image_hash", @@ -1037,12 +1106,18 @@ class TestSubmit(unittest.TestCase): "owner_uuid": "", "manifest_text": "", "properties": "" - }], "items_available": 1, "offset": 0},) + }], "items_available": 1, "offset": 0}, + {"items": [{"uuid": "zzzzz-4zz18-zzzzzzzzzzzzzzb", + "owner_uuid": "", + "manifest_text": "", + "properties": "" + }], "items_available": 1, "offset": 0}) arvrunner.api.collections().create().execute.return_value = {"uuid": ""} arvrunner.api.collections().get().execute.return_value = {"uuid": "zzzzz-4zz18-zzzzzzzzzzzzzzb", "portable_data_hash": "9999999999999999999999999999999b+99"} + self.assertEqual("9999999999999999999999999999999b+99", - arvados_cwl.runner.arvados_jobs_image(arvrunner, "arvados/jobs:"+arvados_cwl.__version__)) + arvados_cwl.runner.arvados_jobs_image(arvrunner, "arvados/jobs:"+arvados_cwl.__version__, arvrunner.runtimeContext)) @stubs @@ -1061,7 +1136,7 @@ class TestSubmit(unittest.TestCase): "--disable-validate", "--disable-color", "--eval-timeout=20", - '--thread-count=1', + '--thread-count=0', "--enable-reuse", "--collection-cache-size=256", '--debug', @@ -1084,9 +1159,6 @@ class TestSubmit(unittest.TestCase): "content": { "$graph": [ { - "$namespaces": { - "cwltool": "http://commonwl.org/cwltool#" - }, "arguments": [ "md5sum", "example.conf" @@ -1134,7 +1206,7 @@ class TestSubmit(unittest.TestCase): "hints": [ { "class": "DockerRequirement", - "dockerPull": "debian:8", + "dockerPull": "debian:buster-slim", "http://arvados.org/cwl#dockerCollectionPDH": "999999999999999999999999999999d4+99" }, { @@ -1175,6 +1247,9 @@ class TestSubmit(unittest.TestCase): ] } ], + "$namespaces": { + "cwltool": "http://commonwl.org/cwltool#" + }, "cwlVersion": "v1.0" }, "kind": "json" @@ -1261,9 +1336,35 @@ class TestSubmit(unittest.TestCase): stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) self.assertEqual(exited, 1) + @stubs + def test_submit_validate_project_uuid(self, stubs): + # Fails with bad cluster prefix + exited = arvados_cwl.main( + ["--submit", "--no-wait", "--api=containers", "--debug", "--project-uuid=zzzzb-j7d0g-zzzzzzzzzzzzzzz", + "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + self.assertEqual(exited, 1) + + # Project lookup fails + stubs.api.groups().get().execute.side_effect = Exception("Bad project") + exited = arvados_cwl.main( + ["--submit", "--no-wait", "--api=containers", "--debug", "--project-uuid=zzzzz-j7d0g-zzzzzzzzzzzzzzx", + "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + self.assertEqual(exited, 1) + + # It should work this time because it is looking up a user (and only group is stubbed out to fail) + exited = arvados_cwl.main( + ["--submit", "--no-wait", "--api=containers", "--debug", "--project-uuid=zzzzz-tpzed-zzzzzzzzzzzzzzx", + "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + self.assertEqual(exited, 0) + + @mock.patch("arvados.collection.CollectionReader") @stubs def test_submit_uuid_inputs(self, stubs, collectionReader): + collectionReader().exists.return_value = True collectionReader().find.return_value = arvados.arvfile.ArvadosFile(mock.MagicMock(), "file1.txt") def list_side_effect(**kwargs): m = mock.MagicMock() @@ -1347,19 +1448,119 @@ class TestSubmit(unittest.TestCase): self.assertEqual(exited, 1) self.assertRegex( capture_stderr.getvalue(), - r"Collection uuid zzzzz-4zz18-zzzzzzzzzzzzzzz not found") + r"Collection\s*uuid\s*zzzzz-4zz18-zzzzzzzzzzzzzzz\s*not\s*found") finally: cwltool_logger.removeHandler(stderr_logger) + @stubs + def test_submit_set_process_properties(self, stubs): + exited = arvados_cwl.main( + ["--submit", "--no-wait", "--api=containers", "--debug", + "tests/wf/submit_wf_process_properties.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + + expect_container = copy.deepcopy(stubs.expect_container_spec) + expect_container["name"] = "submit_wf_process_properties.cwl" + expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$graph"][1]["hints"] = [ + { + "class": "http://arvados.org/cwl#ProcessProperties", + "processProperties": [ + {"propertyName": "baz", + "propertyValue": "$(inputs.x.basename)"}, + {"propertyName": "foo", + "propertyValue": "bar"}, + {"propertyName": "quux", + "propertyValue": { + "q1": 1, + "q2": 2 + } + } + ], + } + ] + expect_container["mounts"]["/var/lib/cwl/workflow.json"]["content"]["$namespaces"] = { + "arv": "http://arvados.org/cwl#" + } + + expect_container["properties"] = { + "baz": "blorp.txt", + "foo": "bar", + "quux": { + "q1": 1, + "q2": 2 + } + } + + stubs.api.container_requests().create.assert_called_with( + body=JsonDiffMatcher(expect_container)) + self.assertEqual(stubs.capture_stdout.getvalue(), + stubs.expect_container_request_uuid + '\n') + self.assertEqual(exited, 0) + + + @stubs + def test_submit_enable_preemptible(self, stubs): + exited = arvados_cwl.main( + ["--submit", "--no-wait", "--api=containers", "--debug", "--enable-preemptible", + "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + + expect_container = copy.deepcopy(stubs.expect_container_spec) + expect_container['command'] = ['arvados-cwl-runner', '--local', '--api=containers', + '--no-log-timestamps', '--disable-validate', '--disable-color', + '--eval-timeout=20', '--thread-count=0', + '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', + '--enable-preemptible', + '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] + + stubs.api.container_requests().create.assert_called_with( + body=JsonDiffMatcher(expect_container)) + self.assertEqual(stubs.capture_stdout.getvalue(), + stubs.expect_container_request_uuid + '\n') + self.assertEqual(exited, 0) + + @stubs + def test_submit_disable_preemptible(self, stubs): + exited = arvados_cwl.main( + ["--submit", "--no-wait", "--api=containers", "--debug", "--disable-preemptible", + "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"], + stubs.capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client) + + expect_container = copy.deepcopy(stubs.expect_container_spec) + expect_container['command'] = ['arvados-cwl-runner', '--local', '--api=containers', + '--no-log-timestamps', '--disable-validate', '--disable-color', + '--eval-timeout=20', '--thread-count=0', + '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue', + '--disable-preemptible', + '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'] + + stubs.api.container_requests().create.assert_called_with( + body=JsonDiffMatcher(expect_container)) + self.assertEqual(stubs.capture_stdout.getvalue(), + stubs.expect_container_request_uuid + '\n') + self.assertEqual(exited, 0) + class TestCreateWorkflow(unittest.TestCase): existing_workflow_uuid = "zzzzz-7fd4e-validworkfloyml" expect_workflow = StripYAMLComments( open("tests/wf/expect_upload_packed.cwl").read().rstrip()) + def setUp(self): + cwltool.process._names = set() + arvados_cwl.arvdocker.arv_docker_clear_cache() + + def tearDown(self): + root_logger = logging.getLogger('') + + # Remove existing RuntimeStatusLoggingHandlers if they exist + handlers = [h for h in root_logger.handlers if not isinstance(h, arvados_cwl.executor.RuntimeStatusLoggingHandler)] + root_logger.handlers = handlers + @stubs def test_create(self, stubs): project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.groups().get().execute.return_value = {"group_class": "project"} exited = arvados_cwl.main( ["--create-workflow", "--debug", @@ -1389,6 +1590,7 @@ class TestCreateWorkflow(unittest.TestCase): @stubs def test_create_name(self, stubs): project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.groups().get().execute.return_value = {"group_class": "project"} exited = arvados_cwl.main( ["--create-workflow", "--debug", @@ -1419,6 +1621,9 @@ class TestCreateWorkflow(unittest.TestCase): @stubs def test_update(self, stubs): + project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.workflows().get().execute.return_value = {"owner_uuid": project_uuid} + exited = arvados_cwl.main( ["--update-workflow", self.existing_workflow_uuid, "--debug", @@ -1430,6 +1635,7 @@ class TestCreateWorkflow(unittest.TestCase): "name": "submit_wf.cwl", "description": "", "definition": self.expect_workflow, + "owner_uuid": project_uuid } } stubs.api.workflows().update.assert_called_with( @@ -1439,8 +1645,12 @@ class TestCreateWorkflow(unittest.TestCase): self.existing_workflow_uuid + '\n') self.assertEqual(exited, 0) + @stubs def test_update_name(self, stubs): + project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.workflows().get().execute.return_value = {"owner_uuid": project_uuid} + exited = arvados_cwl.main( ["--update-workflow", self.existing_workflow_uuid, "--debug", "--name", "testing 123", @@ -1452,6 +1662,7 @@ class TestCreateWorkflow(unittest.TestCase): "name": "testing 123", "description": "", "definition": self.expect_workflow, + "owner_uuid": project_uuid } } stubs.api.workflows().update.assert_called_with( @@ -1464,6 +1675,7 @@ class TestCreateWorkflow(unittest.TestCase): @stubs def test_create_collection_per_tool(self, stubs): project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.groups().get().execute.return_value = {"group_class": "project"} exited = arvados_cwl.main( ["--create-workflow", "--debug", @@ -1493,6 +1705,7 @@ class TestCreateWorkflow(unittest.TestCase): @stubs def test_create_with_imports(self, stubs): project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.groups().get().execute.return_value = {"group_class": "project"} exited = arvados_cwl.main( ["--create-workflow", "--debug", @@ -1511,6 +1724,7 @@ class TestCreateWorkflow(unittest.TestCase): @stubs def test_create_with_no_input(self, stubs): project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz' + stubs.api.groups().get().execute.return_value = {"group_class": "project"} exited = arvados_cwl.main( ["--create-workflow", "--debug",