Merge branch 'origin-8442-cwl-crunch2' closes #8442
[arvados.git] / sdk / cwl / tests / test_container.py
1 import arvados_cwl
2 import logging
3 import mock
4 import unittest
5 import os
6 import cwltool.process
7
8 if not os.getenv('ARVADOS_DEBUG'):
9     logging.getLogger('arvados.cwl-runner').setLevel(logging.WARN)
10     logging.getLogger('arvados.arv-run').setLevel(logging.WARN)
11
12
13 class TestContainer(unittest.TestCase):
14
15     # The test passes no builder.resources
16     # Hence the default resources will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
17     @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
18     def test_run(self, keepdocker):
19         runner = mock.MagicMock()
20         runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
21         runner.ignore_docker_for_reuse = False
22
23         keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
24         runner.api.collections().get().execute.return_value = {
25             "portable_data_hash": "99999999999999999999999999999993+99"}
26
27         document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("draft-3")
28
29         tool = {
30             "inputs": [],
31             "outputs": [],
32             "baseCommand": "ls"
33         }
34         arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="containers", avsc_names=avsc_names, basedir="")
35         arvtool.formatgraph = None
36         for j in arvtool.job({}, mock.MagicMock(), basedir="", name="test_run"):
37             j.run()
38             runner.api.container_requests().create.assert_called_with(
39                 body={
40                     'environment': {
41                         'TMPDIR': '/tmp'
42                     },
43                     'name': 'test_run',
44                     'runtime_constraints': {
45                         'vcpus': 1,
46                         'ram': 1073741824
47                     }, 'priority': 1,
48                     'mounts': {
49                         '/var/spool/cwl': {'kind': 'tmp'}
50                     },
51                     'state': 'Committed',
52                     'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
53                     'output_path': '/var/spool/cwl',
54                     'container_image': '99999999999999999999999999999993+99',
55                     'command': ['ls'],
56                     'cwd': '/var/spool/cwl'
57                 })
58
59     # The test passes some fields in builder.resources
60     # For the remaining fields, the defaults will apply: {'cores': 1, 'ram': 1024, 'outdirSize': 1024, 'tmpdirSize': 1024}
61     @mock.patch("arvados.commands.keepdocker.list_images_in_arv")
62     def test_resource_requirements(self, keepdocker):
63         runner = mock.MagicMock()
64         runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
65         runner.ignore_docker_for_reuse = False
66         document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("draft-3")
67
68         keepdocker.return_value = [("zzzzz-4zz18-zzzzzzzzzzzzzz3", "")]
69         runner.api.collections().get().execute.return_value = {
70             "portable_data_hash": "99999999999999999999999999999993+99"}
71
72         tool = {
73             "inputs": [],
74             "outputs": [],
75             "hints": [{
76                 "class": "ResourceRequirement",
77                 "coresMin": 3,
78                 "ramMin": 3000,
79                 "tmpdirMin": 4000
80             }],
81             "baseCommand": "ls"
82         }
83         arvtool = arvados_cwl.ArvadosCommandTool(runner, tool, work_api="containers", avsc_names=avsc_names)
84         arvtool.formatgraph = None
85         for j in arvtool.job({}, mock.MagicMock(), basedir="", name="test_resource_requirements"):
86             j.run()
87
88         runner.api.container_requests().create.assert_called_with(
89             body={
90                 'environment': {
91                     'TMPDIR': '/tmp'
92                 },
93                 'name': 'test_resource_requirements',
94                 'runtime_constraints': {
95                     'vcpus': 3,
96                     'ram': 3145728000
97                 }, 'priority': 1,
98                 'mounts': {
99                     '/var/spool/cwl': {'kind': 'tmp'}
100                 },
101                 'state': 'Committed',
102                 'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
103                 'output_path': '/var/spool/cwl',
104                 'container_image': '99999999999999999999999999999993+99',
105                 'command': ['ls'],
106                 'cwd': '/var/spool/cwl'
107             })
108
109     @mock.patch("arvados.collection.Collection")
110     def test_done(self, col):
111         api = mock.MagicMock()
112
113         runner = mock.MagicMock()
114         runner.api = api
115         runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
116         runner.num_retries = 0
117         runner.ignore_docker_for_reuse = False
118
119         col().open.return_value = []
120         api.collections().list().execute.side_effect = ({"items": []},
121                                                         {"items": [{"manifest_text": "XYZ"}]})
122
123         arvjob = arvados_cwl.ArvadosContainer(runner)
124         arvjob.name = "testjob"
125         arvjob.builder = mock.MagicMock()
126         arvjob.output_callback = mock.MagicMock()
127         arvjob.collect_outputs = mock.MagicMock()
128         arvjob.successCodes = [0]
129
130         arvjob.done({
131             "state": "Complete",
132             "output": "99999999999999999999999999999993+99",
133             "log": "99999999999999999999999999999994+99",
134             "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz",
135             "exit_code": 0
136         })
137
138         api.collections().list.assert_has_calls([
139             mock.call(),
140             mock.call(filters=[['owner_uuid', '=', 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'],
141                           ['portable_data_hash', '=', '99999999999999999999999999999993+99'],
142                           ['name', '=', 'Output 9999999 of testjob']]),
143             mock.call().execute(num_retries=0),
144             mock.call(limit=1, filters=[['portable_data_hash', '=', '99999999999999999999999999999993+99']],
145                  select=['manifest_text']),
146             mock.call().execute(num_retries=0)])
147
148         api.collections().create.assert_called_with(
149             ensure_unique_name=True,
150             body={'portable_data_hash': '99999999999999999999999999999993+99',
151                   'manifest_text': 'XYZ',
152                   'owner_uuid': 'zzzzz-8i9sb-zzzzzzzzzzzzzzz',
153                   'name': 'Output 9999999 of testjob'})
154
155     @mock.patch("arvados.collection.Collection")
156     def test_done_use_existing_collection(self, col):
157         api = mock.MagicMock()
158
159         runner = mock.MagicMock()
160         runner.api = api
161         runner.project_uuid = "zzzzz-8i9sb-zzzzzzzzzzzzzzz"
162         runner.num_retries = 0
163
164         col().open.return_value = []
165         api.collections().list().execute.side_effect = ({"items": [{"uuid": "zzzzz-4zz18-zzzzzzzzzzzzzz2"}]},)
166
167         arvjob = arvados_cwl.ArvadosContainer(runner)
168         arvjob.name = "testjob"
169         arvjob.builder = mock.MagicMock()
170         arvjob.output_callback = mock.MagicMock()
171         arvjob.collect_outputs = mock.MagicMock()
172         arvjob.successCodes = [0]
173
174         arvjob.done({
175             "state": "Complete",
176             "output": "99999999999999999999999999999993+99",
177             "log": "99999999999999999999999999999994+99",
178             "uuid": "zzzzz-8i9sb-zzzzzzzzzzzzzzz",
179             "exit_code": 0
180         })
181
182         api.collections().list.assert_has_calls([
183             mock.call(),
184             mock.call(filters=[['owner_uuid', '=', 'zzzzz-8i9sb-zzzzzzzzzzzzzzz'],
185                                ['portable_data_hash', '=', '99999999999999999999999999999993+99'],
186                                ['name', '=', 'Output 9999999 of testjob']]),
187             mock.call().execute(num_retries=0)])
188
189         self.assertFalse(api.collections().create.called)