10 from schema_salad.ref_resolver import Loader
12 if not os.getenv('ARVADOS_DEBUG'):
13 logging.getLogger('arvados.cwl-runner').setLevel(logging.WARN)
14 logging.getLogger('arvados.arv-run').setLevel(logging.WARN)
17 class TestJob(unittest.TestCase):
19 # The test passes no builder.resources
20 # Hence the default resources will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
22 runner = mock.MagicMock()
23 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
24 runner.ignore_docker_for_reuse = False
25 runner.num_retries = 0
26 document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("draft-3")
32 "arguments": [{"valueFrom": "$(runtime.outdir)"}]
34 make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
35 arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="jobs", avsc_names=avsc_names,
36 basedir="", make_fs_access=make_fs_access, loader=Loader({}))
37 arvtool.formatgraph = None
38 for j in arvtool.job({}, mock.MagicMock(), basedir="", make_fs_access=make_fs_access):
40 runner.api.jobs().create.assert_called_with(
42 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
43 'runtime_constraints': {},
44 'script_parameters': {
46 'task.env': {'HOME': '$(task.outdir)', 'TMPDIR': '$(task.tmpdir)'},
47 'command': ['ls', '$(task.outdir)']
50 'script_version': 'master',
51 'minimum_script_version': '9e5b98e8f5f4727856b53447191f9c06e3da2ba6',
52 'repository': 'arvados',
53 'script': 'crunchrunner',
54 'runtime_constraints': {
55 'docker_image': 'arvados/jobs',
56 'min_cores_per_node': 1,
57 'min_ram_mb_per_node': 1024,
58 'min_scratch_mb_per_node': 2048 # tmpdirSize + outdirSize
62 filters=[['repository', '=', 'arvados'],
63 ['script', '=', 'crunchrunner'],
64 ['script_version', 'in git', '9e5b98e8f5f4727856b53447191f9c06e3da2ba6'],
65 ['docker_image_locator', 'in docker', 'arvados/jobs']]
68 # The test passes some fields in builder.resources
69 # For the remaining fields, the defaults will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
70 def test_resource_requirements(self):
71 runner = mock.MagicMock()
72 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
73 runner.ignore_docker_for_reuse = False
74 runner.num_retries = 0
75 document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("draft-3")
81 "class": "ResourceRequirement",
86 "class": "http://arvados.org/cwl#RuntimeConstraints",
89 "class": "http://arvados.org/cwl#APIRequirement",
93 make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
94 arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="jobs", avsc_names=avsc_names,
95 make_fs_access=make_fs_access, loader=Loader({}))
96 arvtool.formatgraph = None
97 for j in arvtool.job({}, mock.MagicMock(), basedir="", make_fs_access=make_fs_access):
99 runner.api.jobs().create.assert_called_with(
101 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
102 'runtime_constraints': {},
103 'script_parameters': {
105 'task.env': {'HOME': '$(task.outdir)', 'TMPDIR': '$(task.tmpdir)'},
109 'script_version': 'master',
110 'minimum_script_version': '9e5b98e8f5f4727856b53447191f9c06e3da2ba6',
111 'repository': 'arvados',
112 'script': 'crunchrunner',
113 'runtime_constraints': {
114 'docker_image': 'arvados/jobs',
115 'min_cores_per_node': 3,
116 'min_ram_mb_per_node': 3000,
117 'min_scratch_mb_per_node': 5024, # tmpdirSize + outdirSize
118 'keep_cache_mb_per_task': 512
122 filters=[['repository', '=', 'arvados'],
123 ['script', '=', 'crunchrunner'],
124 ['script_version', 'in git', '9e5b98e8f5f4727856b53447191f9c06e3da2ba6'],
125 ['docker_image_locator', 'in docker', 'arvados/jobs']])
127 @mock.patch("arvados.collection.CollectionReader")
128 def test_done(self, reader):
129 api = mock.MagicMock()
131 runner = mock.MagicMock()
133 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
134 runner.num_retries = 0
135 runner.ignore_docker_for_reuse = False
137 reader().open.return_value = []
138 api.collections().list().execute.side_effect = ({"items": []},
139 {"items": [{"manifest_text": "XYZ"}]})
141 arvjob = arvados_cwl.ArvadosJob(runner)
142 arvjob.name = "testjob"
143 arvjob.builder = mock.MagicMock()
144 arvjob.output_callback = mock.MagicMock()
145 arvjob.collect_outputs = mock.MagicMock()
149 "output": "99999999999999999999999999999993+99",
150 "log": "99999999999999999999999999999994+99",
151 "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
154 api.collections().list.assert_has_calls([
156 mock.call(filters=[['owner_uuid', '=', 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'],
157 ['portable_data_hash', '=', '99999999999999999999999999999993+99'],
158 ['name', '=', 'Output 9999999 of testjob']]),
159 mock.call().execute(num_retries=0),
160 mock.call(limit=1, filters=[['portable_data_hash', '=', '99999999999999999999999999999993+99']],
161 select=['manifest_text']),
162 mock.call().execute(num_retries=0)])
164 api.collections().create.assert_called_with(
165 ensure_unique_name=True,
166 body={'portable_data_hash': '99999999999999999999999999999993+99',
167 'manifest_text': 'XYZ',
168 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
169 'name': 'Output 9999999 of testjob'})
171 @mock.patch("arvados.collection.CollectionReader")
172 def test_done_use_existing_collection(self, reader):
173 api = mock.MagicMock()
175 runner = mock.MagicMock()
177 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
178 runner.num_retries = 0
180 reader().open.return_value = []
181 api.collections().list().execute.side_effect = ({"items": [{"uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2"}]},)
183 arvjob = arvados_cwl.ArvadosJob(runner)
184 arvjob.name = "testjob"
185 arvjob.builder = mock.MagicMock()
186 arvjob.output_callback = mock.MagicMock()
187 arvjob.collect_outputs = mock.MagicMock()
191 "output": "99999999999999999999999999999993+99",
192 "log": "99999999999999999999999999999994+99",
193 "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
196 api.collections().list.assert_has_calls([
198 mock.call(filters=[['owner_uuid', '=', 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'],
199 ['portable_data_hash', '=', '99999999999999999999999999999993+99'],
200 ['name', '=', 'Output 9999999 of testjob']]),
201 mock.call().execute(num_retries=0)])
203 self.assertFalse(api.collections().create.called)
206 class TestWorkflow(unittest.TestCase):
207 # The test passes no builder.resources
208 # Hence the default resources will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
209 @mock.patch("arvados.collection.Collection")
210 def test_run(self, mockcollection):
212 arvados_cwl.add_arv_hints()
214 runner = arvados_cwl.ArvCwlRunner(mock.MagicMock())
215 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
216 runner.ignore_docker_for_reuse = False
217 runner.num_retries = 0
218 document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.0")
220 tool, metadata = document_loader.resolve_ref("tests/wf/scatter2.cwl")
221 metadata["cwlVersion"] = tool["cwlVersion"]
223 mockcollection().portable_data_hash.return_value = "99999999999999999999999999999999+118"
225 make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
226 arvtool = arvados_cwl.ArvadosWorkflow(runner, tool, work_api="jobs", avsc_names=avsc_names,
227 basedir="", make_fs_access=make_fs_access, loader=document_loader,
228 makeTool=runner.arv_make_tool, metadata=metadata)
229 arvtool.formatgraph = None
230 it = arvtool.job({}, mock.MagicMock(), basedir="", make_fs_access=make_fs_access)
234 with open("tests/wf/scatter2_subwf.cwl") as f:
237 mockcollection().open().__enter__().write.assert_has_calls([mock.call(subwf)])
238 mockcollection().open().__enter__().write.assert_has_calls([mock.call('{sleeptime: 5}')])
240 runner.api.jobs().create.assert_called_with(
242 'minimum_script_version': '9e5b98e8f5f4727856b53447191f9c06e3da2ba6',
243 'repository': 'arvados',
244 'script_version': 'master',
245 'script': 'crunchrunner',
246 'script_parameters': {
247 'tasks': [{'task.env': {
248 'HOME': '$(task.outdir)',
249 'TMPDIR': '$(task.tmpdir)'},
251 'workflow.cwl': '$(task.keep)/99999999999999999999999999999999+118/workflow.cwl',
252 'cwl.input.yml': '$(task.keep)/99999999999999999999999999999999+118/cwl.input.yml'
254 'command': [u'cwltool', u'--no-container', u'--move-outputs', u'--preserve-entire-environment', u'workflow.cwl#main', u'cwl.input.yml'],
255 'task.stdout': 'cwl.output.json'}]},
256 'runtime_constraints': {
257 'min_scratch_mb_per_node': 2048,
258 'min_cores_per_node': 1,
259 'docker_image': 'arvados/jobs',
260 'min_ram_mb_per_node': 1024
262 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'},
263 filters=[['repository', '=', 'arvados'],
264 ['script', '=', 'crunchrunner'],
265 ['script_version', 'in git', '9e5b98e8f5f4727856b53447191f9c06e3da2ba6'],
266 ['docker_image_locator', 'in docker', 'arvados/jobs']],
269 logging.exception("")