12 import arvados.collection
14 import arvados_cwl.runner
17 from .matcher import JsonDiffMatcher
18 from .mock_discovery import get_rootDesc
23 @functools.wraps(func)
24 @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
25 @mock.patch("arvados.collection.KeepClient")
26 @mock.patch("arvados.keep.KeepClient")
27 @mock.patch("arvados.events.subscribe")
28 def wrapped(self, events, keep_client1, keep_client2, keepdocker, *args, **kwargs):
33 stubs.keepdocker = keepdocker
36 def putstub(p, **kwargs):
37 return "%s+%i" % (hashlib.md5(p).hexdigest(), len(p))
38 keep_client1().put.side_effect = putstub
39 keep_client1.put.side_effect = putstub
40 keep_client2().put.side_effect = putstub
41 keep_client2.put.side_effect = putstub
43 stubs.keep_client = keep_client2
44 stubs.keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
45 stubs.fake_user_uuid = "zzzzz-tpzed-zzzzzzzzzzzzzzz"
47 stubs.api = mock.MagicMock()
48 stubs.api._rootDesc = get_rootDesc()
50 stubs.api.users().current().execute.return_value = {
51 "uuid": stubs.fake_user_uuid,
53 stubs.api.collections().list().execute.return_value = {"items": []}
54 stubs.api.collections().create().execute.side_effect = ({
55 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz1",
56 "portable_data_hash": "99999999999999999999999999999991+99",
59 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2",
60 "portable_data_hash": "99999999999999999999999999999992+99",
61 "manifest_text": "./tool 00000000000000000000000000000000+0 0:0:submit_tool.cwl 0:0:blub.txt"
64 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz4",
65 "portable_data_hash": "99999999999999999999999999999994+99",
69 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz5",
70 "portable_data_hash": "99999999999999999999999999999995+99",
74 "uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz6",
75 "portable_data_hash": "99999999999999999999999999999996+99",
79 stubs.api.collections().get().execute.return_value = {
80 "portable_data_hash": "99999999999999999999999999999993+99", "manifest_text": "./tool 00000000000000000000000000000000+0 0:0:submit_tool.cwl 0:0:blub.txt"}
82 stubs.expect_job_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
83 stubs.api.jobs().create().execute.return_value = {
84 "uuid": stubs.expect_job_uuid,
88 stubs.expect_container_request_uuid = "zzzzz-xvhdp-zzzzzzzzzzzzzzz"
89 stubs.api.container_requests().create().execute.return_value = {
90 "uuid": stubs.expect_container_request_uuid,
91 "container_uuid": "zzzzz-dz642-zzzzzzzzzzzzzzz",
95 stubs.expect_pipeline_template_uuid = "zzzzz-d1hrv-zzzzzzzzzzzzzzz"
96 stubs.api.pipeline_templates().create().execute.return_value = {
97 "uuid": stubs.expect_pipeline_template_uuid,
99 stubs.expect_job_spec = {
100 'runtime_constraints': {
101 'docker_image': 'arvados/jobs:'+arvados_cwl.__version__
103 'script_parameters': {
105 'basename': 'blorp.txt',
106 'location': 'keep:99999999999999999999999999999994+99/blorp.txt',
110 'basename': '99999999999999999999999999999998+99',
111 'location': 'keep:99999999999999999999999999999998+99',
115 'basename': 'anonymous',
117 "basename": "renamed.txt",
119 "location": "keep:99999999999999999999999999999998+99/file1.txt"
124 '99999999999999999999999999999991+99/wf/submit_wf.cwl'
126 'repository': 'arvados',
127 'script_version': arvados_cwl.__version__,
128 'script': 'cwl-runner'
130 stubs.pipeline_component = stubs.expect_job_spec.copy()
131 stubs.expect_pipeline_instance = {
132 'name': 'submit_wf.cwl',
133 'state': 'RunningOnServer',
136 'runtime_constraints': {'docker_image': 'arvados/jobs:'+arvados_cwl.__version__},
137 'script_parameters': {
138 'y': {"value": {'basename': '99999999999999999999999999999998+99', 'location': 'keep:99999999999999999999999999999998+99', 'class': 'Directory'}},
139 'x': {"value": {'basename': 'blorp.txt', 'class': 'File', 'location': 'keep:99999999999999999999999999999994+99/blorp.txt'}},
140 'z': {"value": {'basename': 'anonymous', 'class': 'Directory',
142 {'basename': 'renamed.txt', 'class': 'File', 'location': 'keep:99999999999999999999999999999998+99/file1.txt'}
144 'cwl:tool': '99999999999999999999999999999991+99/wf/submit_wf.cwl',
145 'arv:enable_reuse': True
147 'repository': 'arvados',
148 'script_version': arvados_cwl.__version__,
149 'script': 'cwl-runner',
150 'job': {'state': 'Queued', 'uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'}
154 stubs.pipeline_create = copy.deepcopy(stubs.expect_pipeline_instance)
155 stubs.expect_pipeline_uuid = "zzzzz-d1hrv-zzzzzzzzzzzzzzz"
156 stubs.pipeline_create["uuid"] = stubs.expect_pipeline_uuid
157 stubs.pipeline_with_job = copy.deepcopy(stubs.pipeline_create)
158 stubs.pipeline_with_job["components"]["cwl-runner"]["job"] = {
159 "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz",
162 stubs.api.pipeline_instances().create().execute.return_value = stubs.pipeline_create
163 stubs.api.pipeline_instances().get().execute.return_value = stubs.pipeline_with_job
165 stubs.expect_container_spec = {
172 '/var/lib/cwl/workflow': {
173 'portable_data_hash': '99999999999999999999999999999991+99',
177 'path': '/var/spool/cwl/cwl.output.json',
180 '/var/lib/cwl/job/cwl.input.json': {
181 'portable_data_hash': 'd20d7cddd1984f105dd3702c7f125afb+60/cwl.input.json',
185 'state': 'Committed',
186 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
187 'command': ['arvados-cwl-runner', '--local', '--api=containers', '--enable-reuse', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json'],
188 'name': 'submit_wf.cwl',
189 'container_image': 'arvados/jobs:'+arvados_cwl.__version__,
190 'output_path': '/var/spool/cwl',
191 'cwd': '/var/spool/cwl',
192 'runtime_constraints': {
199 stubs.expect_workflow_uuid = "zzzzz-7fd4e-zzzzzzzzzzzzzzz"
200 stubs.api.workflows().create().execute.return_value = {
201 "uuid": stubs.expect_workflow_uuid,
204 return func(self, stubs, *args, **kwargs)
208 class TestSubmit(unittest.TestCase):
209 @mock.patch("time.sleep")
211 def test_submit(self, stubs, tm):
212 capture_stdout = cStringIO.StringIO()
213 exited = arvados_cwl.main(
214 ["--submit", "--no-wait", "--debug",
215 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
216 capture_stdout, sys.stderr, api_client=stubs.api)
217 self.assertEqual(exited, 0)
219 stubs.api.collections().create.assert_has_calls([
223 './tool d51232d96b6116d964a69bfb7e0c73bf+450 '
224 '0:16:blub.txt 16:434:submit_tool.cwl\n./wf '
225 'cc2ffb940e60adf1b2b282c67587e43d+413 0:413:submit_wf.cwl\n',
226 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
227 'name': 'submit_wf.cwl',
228 }, ensure_unique_name=True),
229 mock.call().execute(),
230 mock.call(body={'manifest_text': '. d41d8cd98f00b204e9800998ecf8427e+0 '
231 '0:0:blub.txt 0:0:submit_tool.cwl\n',
232 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
233 'replication_desired': None,
234 'name': 'New collection'
235 }, ensure_unique_name=True),
236 mock.call().execute(num_retries=4),
239 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
240 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
242 }, ensure_unique_name=True),
243 mock.call().execute()])
245 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
246 expect_pipeline["owner_uuid"] = stubs.fake_user_uuid
247 stubs.api.pipeline_instances().create.assert_called_with(
248 body=expect_pipeline)
249 self.assertEqual(capture_stdout.getvalue(),
250 stubs.expect_pipeline_uuid + '\n')
253 @mock.patch("time.sleep")
255 def test_submit_no_reuse(self, stubs, tm):
256 capture_stdout = cStringIO.StringIO()
257 exited = arvados_cwl.main(
258 ["--submit", "--no-wait", "--debug", "--disable-reuse",
259 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
260 capture_stdout, sys.stderr, api_client=stubs.api)
261 self.assertEqual(exited, 0)
263 stubs.expect_pipeline_instance["components"]["cwl-runner"]["script_parameters"]["arv:enable_reuse"] = {"value": False}
265 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
266 expect_pipeline["owner_uuid"] = stubs.fake_user_uuid
267 stubs.api.pipeline_instances().create.assert_called_with(
268 body=expect_pipeline)
269 self.assertEqual(capture_stdout.getvalue(),
270 stubs.expect_pipeline_uuid + '\n')
272 @mock.patch("time.sleep")
274 def test_submit_output_name(self, stubs, tm):
275 output_name = "test_output_name"
277 capture_stdout = cStringIO.StringIO()
278 exited = arvados_cwl.main(
279 ["--submit", "--no-wait", "--debug", "--output-name", output_name,
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.expect_pipeline_instance["components"]["cwl-runner"]["script_parameters"]["arv:output_name"] = output_name
286 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
287 expect_pipeline["owner_uuid"] = stubs.fake_user_uuid
288 stubs.api.pipeline_instances().create.assert_called_with(
289 body=expect_pipeline)
290 self.assertEqual(capture_stdout.getvalue(),
291 stubs.expect_pipeline_uuid + '\n')
293 @mock.patch("time.sleep")
295 def test_submit_output_tags(self, stubs, tm):
296 output_tags = "tag0,tag1,tag2"
298 capture_stdout = cStringIO.StringIO()
299 exited = arvados_cwl.main(
300 ["--submit", "--no-wait", "--debug", "--output-tags", output_tags,
301 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
302 capture_stdout, sys.stderr, api_client=stubs.api)
303 self.assertEqual(exited, 0)
305 stubs.expect_pipeline_instance["components"]["cwl-runner"]["script_parameters"]["arv:output_tags"] = output_tags
307 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
308 expect_pipeline["owner_uuid"] = stubs.fake_user_uuid
309 stubs.api.pipeline_instances().create.assert_called_with(
310 body=expect_pipeline)
311 self.assertEqual(capture_stdout.getvalue(),
312 stubs.expect_pipeline_uuid + '\n')
314 @mock.patch("time.sleep")
316 def test_submit_with_project_uuid(self, stubs, tm):
317 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
319 exited = arvados_cwl.main(
320 ["--submit", "--no-wait",
321 "--project-uuid", project_uuid,
322 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
323 sys.stdout, sys.stderr, api_client=stubs.api)
324 self.assertEqual(exited, 0)
326 expect_pipeline = copy.deepcopy(stubs.expect_pipeline_instance)
327 expect_pipeline["owner_uuid"] = project_uuid
328 stubs.api.pipeline_instances().create.assert_called_with(
329 body=expect_pipeline)
332 def test_submit_container(self, stubs):
333 capture_stdout = cStringIO.StringIO()
335 exited = arvados_cwl.main(
336 ["--submit", "--no-wait", "--api=containers", "--debug",
337 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
338 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
339 self.assertEqual(exited, 0)
341 logging.exception("")
343 stubs.api.collections().create.assert_has_calls([
347 './tool d51232d96b6116d964a69bfb7e0c73bf+450 '
348 '0:16:blub.txt 16:434:submit_tool.cwl\n./wf '
349 'cc2ffb940e60adf1b2b282c67587e43d+413 0:413:submit_wf.cwl\n',
350 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
351 'name': 'submit_wf.cwl',
352 }, ensure_unique_name=True),
353 mock.call().execute(),
354 mock.call(body={'manifest_text': '. d41d8cd98f00b204e9800998ecf8427e+0 '
355 '0:0:blub.txt 0:0:submit_tool.cwl\n',
356 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
357 'name': 'New collection',
358 'replication_desired': None,
359 }, ensure_unique_name=True),
360 mock.call().execute(num_retries=4),
363 '. 979af1245a12a1fed634d4222473bfdc+16 0:16:blorp.txt\n',
364 'owner_uuid': 'zzzzz-tpzed-zzzzzzzzzzzzzzz',
366 }, ensure_unique_name=True),
367 mock.call().execute()])
369 expect_container = copy.deepcopy(stubs.expect_container_spec)
370 expect_container["owner_uuid"] = stubs.fake_user_uuid
371 stubs.api.container_requests().create.assert_called_with(
372 body=expect_container)
373 self.assertEqual(capture_stdout.getvalue(),
374 stubs.expect_container_request_uuid + '\n')
377 def test_submit_container_no_reuse(self, stubs):
378 capture_stdout = cStringIO.StringIO()
380 exited = arvados_cwl.main(
381 ["--submit", "--no-wait", "--api=containers", "--debug", "--disable-reuse",
382 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
383 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
384 self.assertEqual(exited, 0)
386 logging.exception("")
388 stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', '--disable-reuse', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json']
390 expect_container = copy.deepcopy(stubs.expect_container_spec)
391 expect_container["owner_uuid"] = stubs.fake_user_uuid
392 stubs.api.container_requests().create.assert_called_with(
393 body=expect_container)
394 self.assertEqual(capture_stdout.getvalue(),
395 stubs.expect_container_request_uuid + '\n')
398 def test_submit_container_output_name(self, stubs):
399 output_name = "test_output_name"
401 capture_stdout = cStringIO.StringIO()
403 exited = arvados_cwl.main(
404 ["--submit", "--no-wait", "--api=containers", "--debug", "--output-name", output_name,
405 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
406 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
407 self.assertEqual(exited, 0)
409 logging.exception("")
411 stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', "--output-name="+output_name, '--enable-reuse', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json']
413 expect_container = copy.deepcopy(stubs.expect_container_spec)
414 expect_container["owner_uuid"] = stubs.fake_user_uuid
415 stubs.api.container_requests().create.assert_called_with(
416 body=expect_container)
417 self.assertEqual(capture_stdout.getvalue(),
418 stubs.expect_container_request_uuid + '\n')
421 def test_submit_container_output_tags(self, stubs):
422 output_tags = "tag0,tag1,tag2"
424 capture_stdout = cStringIO.StringIO()
426 exited = arvados_cwl.main(
427 ["--submit", "--no-wait", "--api=containers", "--debug", "--output-tags", output_tags,
428 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
429 capture_stdout, sys.stderr, api_client=stubs.api, keep_client=stubs.keep_client)
430 self.assertEqual(exited, 0)
432 logging.exception("")
434 stubs.expect_container_spec["command"] = ['arvados-cwl-runner', '--local', '--api=containers', "--output-tags="+output_tags, '--enable-reuse', '/var/lib/cwl/workflow/submit_wf.cwl', '/var/lib/cwl/job/cwl.input.json']
436 expect_container = copy.deepcopy(stubs.expect_container_spec)
437 expect_container["owner_uuid"] = stubs.fake_user_uuid
438 stubs.api.container_requests().create.assert_called_with(
439 body=expect_container)
440 self.assertEqual(capture_stdout.getvalue(),
441 stubs.expect_container_request_uuid + '\n')
443 @mock.patch("arvados.commands.keepdocker.find_one_image_hash")
444 @mock.patch("cwltool.docker.get_image")
445 @mock.patch("arvados.api")
446 def test_arvados_jobs_image(self, api, get_image, find_one_image_hash):
447 arvrunner = mock.MagicMock()
448 arvrunner.project_uuid = ""
449 api.return_value = mock.MagicMock()
450 arvrunner.api = api.return_value
451 arvrunner.api.links().list().execute.side_effect = ({"items": [], "items_available": 0, "offset": 0},
452 {"items": [], "items_available": 0, "offset": 0},
453 {"items": [], "items_available": 0, "offset": 0},
454 {"items": [{"created_at": "",
456 "link_class": "docker_image_hash",
459 "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0},
460 {"items": [], "items_available": 0, "offset": 0},
461 {"items": [{"created_at": "",
463 "link_class": "docker_image_repo+tag",
464 "name": "arvados/jobs:"+arvados_cwl.__version__,
466 "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0},
467 {"items": [{"created_at": "",
469 "link_class": "docker_image_hash",
472 "properties": {"image_timestamp": ""}}], "items_available": 1, "offset": 0} ,
474 find_one_image_hash.return_value = "123456"
476 arvrunner.api.collections().list().execute.side_effect = ({"items": [], "items_available": 0, "offset": 0},
477 {"items": [{"uuid": "",
481 }], "items_available": 1, "offset": 0},
482 {"items": [{"uuid": ""}], "items_available": 1, "offset": 0})
483 arvrunner.api.collections().create().execute.return_value = {"uuid": ""}
484 self.assertEqual("arvados/jobs:"+arvados_cwl.__version__, arvados_cwl.runner.arvados_jobs_image(arvrunner))
486 class TestCreateTemplate(unittest.TestCase):
488 def test_create(self, stubs):
489 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
491 capture_stdout = cStringIO.StringIO()
493 exited = arvados_cwl.main(
494 ["--create-template", "--debug",
495 "--project-uuid", project_uuid,
496 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
497 capture_stdout, sys.stderr, api_client=stubs.api)
498 self.assertEqual(exited, 0)
500 stubs.api.pipeline_instances().create.refute_called()
501 stubs.api.jobs().create.refute_called()
503 expect_component = copy.deepcopy(stubs.expect_job_spec)
504 expect_component['script_parameters']['x'] = {
508 'value': '99999999999999999999999999999994+99/blorp.txt',
510 expect_component['script_parameters']['y'] = {
511 'dataclass': 'Collection',
514 'value': '99999999999999999999999999999998+99',
516 expect_component['script_parameters']['z'] = {
517 'dataclass': 'Collection',
523 "submit_wf.cwl": expect_component,
525 "name": "submit_wf.cwl",
526 "owner_uuid": project_uuid,
528 stubs.api.pipeline_templates().create.assert_called_with(
529 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
531 self.assertEqual(capture_stdout.getvalue(),
532 stubs.expect_pipeline_template_uuid + '\n')
535 class TestCreateWorkflow(unittest.TestCase):
537 def test_create(self, stubs):
538 project_uuid = 'zzzzz-j7d0g-zzzzzzzzzzzzzzz'
540 capture_stdout = cStringIO.StringIO()
542 exited = arvados_cwl.main(
543 ["--create-workflow", "--debug",
544 "--project-uuid", project_uuid,
545 "tests/wf/submit_wf.cwl", "tests/submit_test_job.json"],
546 capture_stdout, sys.stderr, api_client=stubs.api)
547 self.assertEqual(exited, 0)
549 stubs.api.pipeline_templates().create.refute_called()
550 stubs.api.container_requests().create.refute_called()
552 with open("tests/wf/expect_packed.cwl") as f:
553 expect_workflow = f.read()
557 "owner_uuid": project_uuid,
558 "name": "submit_wf.cwl",
560 "definition": expect_workflow
563 stubs.api.workflows().create.assert_called_with(
564 body=JsonDiffMatcher(body))
566 self.assertEqual(capture_stdout.getvalue(),
567 stubs.expect_workflow_uuid + '\n')
570 class TestTemplateInputs(unittest.TestCase):
574 'runtime_constraints': {
575 'docker_image': 'arvados/jobs:'+arvados_cwl.__version__,
577 'script_parameters': {
579 '99999999999999999999999999999991+99/'
580 'wf/inputs_test.cwl',
581 'optionalFloatInput': None,
586 'title': "It's a file; we expect to find some characters in it.",
587 'description': 'If there were anything further to say, it would be said here,\nor here.'
591 'dataclass': 'number',
593 'title': 'Floats like a duck',
597 'optionalFloatInput': {
598 'type': ['null', 'float'],
599 'dataclass': 'number',
604 'dataclass': 'boolean',
606 'title': 'True or false?',
609 'repository': 'arvados',
610 'script_version': arvados_cwl.__version__,
611 'script': 'cwl-runner',
614 "name": "inputs_test.cwl",
618 def test_inputs_empty(self, stubs):
619 exited = arvados_cwl.main(
620 ["--create-template", "--no-wait",
621 "tests/wf/inputs_test.cwl", "tests/order/empty_order.json"],
622 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
623 self.assertEqual(exited, 0)
625 expect_template = copy.deepcopy(self.expect_template)
626 expect_template["owner_uuid"] = stubs.fake_user_uuid
628 stubs.api.pipeline_templates().create.assert_called_with(
629 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)
632 def test_inputs(self, stubs):
633 exited = arvados_cwl.main(
634 ["--create-template", "--no-wait",
635 "tests/wf/inputs_test.cwl", "tests/order/inputs_test_order.json"],
636 cStringIO.StringIO(), sys.stderr, api_client=stubs.api)
637 self.assertEqual(exited, 0)
639 self.expect_template["owner_uuid"] = stubs.fake_user_uuid
641 expect_template = copy.deepcopy(self.expect_template)
642 expect_template["owner_uuid"] = stubs.fake_user_uuid
643 params = expect_template[
644 "components"]["inputs_test.cwl"]["script_parameters"]
645 params["fileInput"]["value"] = '99999999999999999999999999999994+99/blorp.txt'
646 params["floatInput"]["value"] = 1.234
647 params["boolInput"]["value"] = True
649 stubs.api.pipeline_templates().create.assert_called_with(
650 body=JsonDiffMatcher(expect_template), ensure_unique_name=True)