2 from arvados_cwl.arvdocker import arv_docker_clear_cache
9 from schema_salad.ref_resolver import Loader
10 from schema_salad.sourceline import cmap
12 from .matcher import JsonDiffMatcher
14 if not os.getenv('ARVADOS_DEBUG'):
15 logging.getLogger('arvados.cwl-runner').setLevel(logging.WARN)
16 logging.getLogger('arvados.arv-run').setLevel(logging.WARN)
19 class TestContainer(unittest.TestCase):
21 # The test passes no builder.resources
22 # Hence the default resources will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
23 @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
24 def test_run(self, keepdocker):
25 for enable_reuse in (True, False):
26 arv_docker_clear_cache()
28 runner = mock.MagicMock()
29 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
30 runner.ignore_docker_for_reuse = False
32 keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
33 runner.api.collections().get().execute.return_value = {
34 "portable_data_hash": "99999999999999999999999999999993+99"}
36 document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.0")
42 "arguments": [{"valueFrom": "$(runtime.outdir)"}]
44 make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
45 arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="containers", avsc_names=avsc_names,
46 basedir="", make_fs_access=make_fs_access, loader=Loader({}))
47 arvtool.formatgraph = None
48 for j in arvtool.job({}, mock.MagicMock(), basedir="", name="test_run_"+str(enable_reuse),
49 make_fs_access=make_fs_access, tmpdir="/tmp"):
50 j.run(enable_reuse=enable_reuse)
51 runner.api.container_requests().create.assert_called_with(
52 body=JsonDiffMatcher({
54 'HOME': '/var/spool/cwl',
57 'name': 'test_run_'+str(enable_reuse),
58 'runtime_constraints': {
62 'use_existing': enable_reuse,
65 '/var/spool/cwl': {'kind': 'tmp'}
68 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
69 'output_path': '/var/spool/cwl',
70 'container_image': 'arvados/jobs',
71 'command': ['ls', '/var/spool/cwl'],
72 'cwd': '/var/spool/cwl',
73 'scheduling_parameters': {},
77 # The test passes some fields in builder.resources
78 # For the remaining fields, the defaults will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
79 @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
80 def test_resource_requirements(self, keepdocker):
81 arv_docker_clear_cache()
82 runner = mock.MagicMock()
83 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
84 runner.ignore_docker_for_reuse = False
85 document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.0")
87 keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
88 runner.api.collections().get().execute.return_value = {
89 "portable_data_hash": "99999999999999999999999999999993+99"}
95 "class": "ResourceRequirement",
100 "class": "http://arvados.org/cwl#RuntimeConstraints",
103 "class": "http://arvados.org/cwl#APIRequirement",
105 "class": "http://arvados.org/cwl#PartitionRequirement",
110 make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
111 arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="containers",
112 avsc_names=avsc_names, make_fs_access=make_fs_access,
114 arvtool.formatgraph = None
115 for j in arvtool.job({}, mock.MagicMock(), basedir="", name="test_resource_requirements",
116 make_fs_access=make_fs_access, tmpdir="/tmp"):
119 call_args, call_kwargs = runner.api.container_requests().create.call_args
121 call_body_expected = {
123 'HOME': '/var/spool/cwl',
126 'name': 'test_resource_requirements',
127 'runtime_constraints': {
130 'keep_cache_ram': 536870912,
133 'use_existing': True,
136 '/var/spool/cwl': {'kind': 'tmp'}
138 'state': 'Committed',
139 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
140 'output_path': '/var/spool/cwl',
141 'container_image': 'arvados/jobs',
143 'cwd': '/var/spool/cwl',
144 'scheduling_parameters': {
145 'partitions': ['blurb']
150 call_body = call_kwargs.get('body', None)
151 self.assertNotEqual(None, call_body)
152 for key in call_body:
153 self.assertEqual(call_body_expected.get(key), call_body.get(key))
156 # The test passes some fields in builder.resources
157 # For the remaining fields, the defaults will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
158 @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
159 @mock.patch("arvados.collection.Collection")
160 def test_initial_work_dir(self, collection_mock, keepdocker):
161 arv_docker_clear_cache()
162 runner = mock.MagicMock()
163 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
164 runner.ignore_docker_for_reuse = False
165 document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.0")
167 keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
168 runner.api.collections().get().execute.return_value = {
169 "portable_data_hash": "99999999999999999999999999999993+99"}
171 sourcemock = mock.MagicMock()
172 def get_collection_mock(p):
174 return (sourcemock, p.split("/", 1)[1])
176 return (sourcemock, "")
177 runner.fs_access.get_collection.side_effect = get_collection_mock
179 vwdmock = mock.MagicMock()
180 collection_mock.return_value = vwdmock
181 vwdmock.portable_data_hash.return_value = "99999999999999999999999999999996+99"
187 "class": "InitialWorkDirRequirement",
191 "location": "keep:99999999999999999999999999999995+99/bar"
194 "class": "Directory",
196 "location": "keep:99999999999999999999999999999995+99"
200 "basename": "filename",
201 "location": "keep:99999999999999999999999999999995+99/baz/filename"
204 "class": "Directory",
205 "basename": "subdir",
206 "location": "keep:99999999999999999999999999999995+99/subdir"
211 make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess, api_client=runner.api)
212 arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="containers",
213 avsc_names=avsc_names, make_fs_access=make_fs_access,
215 arvtool.formatgraph = None
216 for j in arvtool.job({}, mock.MagicMock(), basedir="", name="test_initial_work_dir",
217 make_fs_access=make_fs_access, tmpdir="/tmp"):
220 call_args, call_kwargs = runner.api.container_requests().create.call_args
222 vwdmock.copy.assert_has_calls([mock.call('bar', 'foo', source_collection=sourcemock)])
223 vwdmock.copy.assert_has_calls([mock.call('', 'foo2', source_collection=sourcemock)])
224 vwdmock.copy.assert_has_calls([mock.call('baz/filename', 'filename', source_collection=sourcemock)])
225 vwdmock.copy.assert_has_calls([mock.call('subdir', 'subdir', source_collection=sourcemock)])
227 call_body_expected = {
229 'HOME': '/var/spool/cwl',
232 'name': 'test_initial_work_dir',
233 'runtime_constraints': {
237 'use_existing': True,
240 '/var/spool/cwl': {'kind': 'tmp'},
241 '/var/spool/cwl/foo': {
242 'kind': 'collection',
244 'portable_data_hash': '99999999999999999999999999999996+99'
246 '/var/spool/cwl/foo2': {
247 'kind': 'collection',
249 'portable_data_hash': '99999999999999999999999999999996+99'
251 '/var/spool/cwl/filename': {
252 'kind': 'collection',
254 'portable_data_hash': '99999999999999999999999999999996+99'
256 '/var/spool/cwl/subdir': {
257 'kind': 'collection',
259 'portable_data_hash': '99999999999999999999999999999996+99'
262 'state': 'Committed',
263 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
264 'output_path': '/var/spool/cwl',
265 'container_image': 'arvados/jobs',
267 'cwd': '/var/spool/cwl',
268 'scheduling_parameters': {
273 call_body = call_kwargs.get('body', None)
274 self.assertNotEqual(None, call_body)
275 for key in call_body:
276 self.assertEqual(call_body_expected.get(key), call_body.get(key))
278 @mock.patch("arvados.collection.Collection")
279 def test_done(self, col):
280 api = mock.MagicMock()
282 runner = mock.MagicMock()
284 runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
285 runner.num_retries = 0
286 runner.ignore_docker_for_reuse = False
288 runner.api.containers().get().execute.return_value = {"state":"Complete",
292 col().open.return_value = []
294 arvjob = arvados_cwl.ArvadosContainer(runner)
295 arvjob.name = "testjob"
296 arvjob.builder = mock.MagicMock()
297 arvjob.output_callback = mock.MagicMock()
298 arvjob.collect_outputs = mock.MagicMock()
299 arvjob.successCodes = [0]
300 arvjob.outdir = "/var/spool/cwl"
302 arvjob.collect_outputs.return_value = {"out": "stuff"}
306 "log_uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz1",
307 "output_uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2",
308 "uuid": "zzzzz-xvhdp-zzzzzzzzzzzzzzz",
309 "container_uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
312 self.assertFalse(api.collections().create.called)
314 arvjob.collect_outputs.assert_called_with("keep:abc+123")
315 arvjob.output_callback.assert_called_with({"out": "stuff"}, "success")