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",
45 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2",
46 "portable_data_hash": "99999999999999999999999999999992+99",
49 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz4",
50 "portable_data_hash": "99999999999999999999999999999994+99",
53 stubs.api.collections().get().execute.return_value = {
54 "portable_data_hash": "99999999999999999999999999999993+99"}
56 stubs.expect_job_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
57 stubs.api.jobs().create().execute.return_value = {
58 "uuid": stubs.expect_job_uuid,
62 stubs.expect_container_request_uuid = "zzzzz-xvhdp-zzzzzzzzzzzzzzz"
63 stubs.api.container_requests().create().execute.return_value = {
64 "uuid": stubs.expect_container_request_uuid,
65 "container_uuid": "zzzzz-dz642-zzzzzzzzzzzzzzz",
69 stubs.expect_pipeline_template_uuid = "zzzzz-d1hrv-zzzzzzzzzzzzzzz"
70 stubs.api.pipeline_templates().create().execute.return_value = {
71 "uuid": stubs.expect_pipeline_template_uuid,
73 stubs.expect_job_spec = {
74 'runtime_constraints': {
75 'docker_image': 'arvados/jobs'
77 'script_parameters': {
79 'path': '99999999999999999999999999999992+99/blorp.txt',
83 '99999999999999999999999999999991+99/wf/submit_wf.cwl'
85 'repository': 'arvados',
86 'script_version': 'master',
87 'script': 'cwl-runner'
90 stubs.expect_container_spec = {
97 '/var/lib/cwl/workflow': {
98 'portable_data_hash': '99999999999999999999999999999991+99',
102 'path': '/var/spool/cwl/cwl.output.json',
105 '/var/lib/cwl/job/cwl.input.json': {
106 'portable_data_hash': '33be5c865fe12e1e4788d2f1bc627f7a+60/cwl.input.json',
110 'state': 'Committed',
111 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
112 'command': ['arvados-cwl-runner', '--local', '--api=containers', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json'],
113 'name': 'submit_wf.cwl',
114 'container_image': '99999999999999999999999999999993+99',
115 'output_path': '/var/spool/cwl',
116 'cwd': '/var/spool/cwl',
117 'runtime_constraints': {
123 return func(self, stubs, *args, **kwargs)
127 class TestSubmit(unittest.TestCase):
129 def test_submit(self, stubs):
130 capture_stdout = cStringIO.StringIO()
131 exited = arvados_cwl.main(
132 ["--submit", "--no-wait",
133 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
134 capture_stdout, sys.stderr, api_client=stubs.api)
135 self.assertEqual(exited, 0)
137 stubs.api.collections().create.assert_has_calls([
141 './tool a3954c369b8924d40547ec8cf5f6a7f4+449 '
142 '0:16:blub.txt 16:433:submit_tool.cwl\n./wf '
143 'e046cace0b1a0a6ee645f6ea8688f7e2+364 0:364:submit_wf.cwl\n',
144 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
145 'name': 'submit_wf.cwl',
146 }, ensure_unique_name=True),
147 mock.call().execute(),
150 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
151 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
153 }, ensure_unique_name=True),
154 mock.call().execute()])
156 expect_job = copy.deepcopy(stubs.expect_job_spec)
157 expect_job["owner_uuid"] = stubs.fake_user_uuid
158 stubs.api.jobs().create.assert_called_with(
161 self.assertEqual(capture_stdout.getvalue(),
162 stubs.expect_job_uuid + '\n')
165 def test_submit_with_project_uuid(self, stubs):
166 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
168 exited = arvados_cwl.main(
169 ["--submit", "--no-wait",
170 "--project-uuid", project_uuid,
171 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
172 sys.stdout, sys.stderr, api_client=stubs.api)
173 self.assertEqual(exited, 0)
175 expect_body = copy.deepcopy(stubs.expect_job_spec)
176 expect_body["owner_uuid"] = project_uuid
177 stubs.api.jobs().create.assert_called_with(
182 def test_submit_container(self, stubs):
183 capture_stdout = cStringIO.StringIO()
184 exited = arvados_cwl.main(
185 ["--submit", "--no-wait", "--api=containers", "--debug",
186 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
187 capture_stdout, sys.stderr, api_client=stubs.api)
188 self.assertEqual(exited, 0)
190 stubs.api.collections().create.assert_has_calls([
194 './tool a3954c369b8924d40547ec8cf5f6a7f4+449 '
195 '0:16:blub.txt 16:433:submit_tool.cwl\n./wf '
196 'e046cace0b1a0a6ee645f6ea8688f7e2+364 0:364:submit_wf.cwl\n',
197 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
198 'name': 'submit_wf.cwl',
199 }, ensure_unique_name=True),
200 mock.call().execute(),
203 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
204 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
206 }, ensure_unique_name=True),
207 mock.call().execute()])
209 expect_container = copy.deepcopy(stubs.expect_container_spec)
210 expect_container["owner_uuid"] = stubs.fake_user_uuid
211 stubs.api.container_requests().create.assert_called_with(
212 body=expect_container)
213 self.assertEqual(capture_stdout.getvalue(),
214 stubs.expect_container_request_uuid + '\n')
217 class TestCreateTemplate(unittest.TestCase):
219 def test_create(self, stubs):
220 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
222 capture_stdout = cStringIO.StringIO()
224 exited = arvados_cwl.main(
225 ["--create-template", "--no-wait",
226 "--project-uuid", project_uuid,
227 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
228 capture_stdout, sys.stderr, api_client=stubs.api)
229 self.assertEqual(exited, 0)
231 stubs.api.pipeline_instances().create.refute_called()
232 stubs.api.jobs().create.refute_called()
234 expect_component = copy.deepcopy(stubs.expect_job_spec)
235 expect_component['script_parameters']['x'] = {
239 'value': '99999999999999999999999999999992+99/blorp.txt',
243 "submit_wf.cwl": expect_component,
245 "name": "submit_wf.cwl",
246 "owner_uuid": project_uuid,
248 stubs.api.pipeline_templates().create.assert_called_with(
249 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
251 self.assertEqual(capture_stdout.getvalue(),
252 stubs.expect_pipeline_template_uuid + '\n')
255 class TestTemplateInputs(unittest.TestCase):
259 'runtime_constraints': {
260 'docker_image': 'arvados/jobs',
262 'script_parameters': {
264 '99999999999999999999999999999991+99/'
265 'wf/inputs_test.cwl',
266 'optionalFloatInput': None,
271 'title': "It's a file; we expect to find some characters in it.",
272 'description': 'If there were anything further to say, it would be said here,\nor here.'
276 'dataclass': 'number',
278 'title': 'Floats like a duck',
282 'optionalFloatInput': {
283 'type': ['null', 'float'],
284 'dataclass': 'number',
289 'dataclass': 'boolean',
291 'title': 'True or false?',
294 'repository': 'arvados',
295 'script_version': 'master',
296 'script': 'cwl-runner',
299 "name": "inputs_test.cwl",
303 def test_inputs_empty(self, stubs):
304 exited = arvados_cwl.main(
305 ["--create-template", "--no-wait",
306 "tests/wf/inputs_test.cwl", "tests/order/empty_order.json"],
307 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
308 self.assertEqual(exited, 0)
310 expect_template = copy.deepcopy(self.expect_template)
311 expect_template["owner_uuid"] = stubs.fake_user_uuid
313 stubs.api.pipeline_templates().create.assert_called_with(
314 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
317 def test_inputs(self, stubs):
318 exited = arvados_cwl.main(
319 ["--create-template", "--no-wait",
320 "tests/wf/inputs_test.cwl", "tests/order/inputs_test_order.json"],
321 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
322 self.assertEqual(exited, 0)
324 self.expect_template["owner_uuid"] = stubs.fake_user_uuid
326 expect_template = copy.deepcopy(self.expect_template)
327 expect_template["owner_uuid"] = stubs.fake_user_uuid
328 params = expect_template[
329 "components"]["inputs_test.cwl"]["script_parameters"]
330 params["fileInput"]["value"] = '99999999999999999999999999999992+99/blorp.txt'
331 params["floatInput"]["value"] = 1.234
332 params["boolInput"]["value"] = True
334 stubs.api.pipeline_templates().create.assert_called_with(
335 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)