Resolve deprecation warnings
[arvados.git] / tools / crunchstat-summary / tests / test_examples.py
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 import arvados
6 import collections
7 import crunchstat_summary.command
8 import difflib
9 import glob
10 import gzip
11 from io import open
12 import mock
13 import os
14 import sys
15 import unittest
16
17 from crunchstat_summary.command import UTF8Decode
18
19 TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
20
21
22 class ReportDiff(unittest.TestCase):
23     def diff_known_report(self, logfile, cmd):
24         expectfile = logfile+'.report'
25         with open(expectfile, encoding='utf-8') as f:
26             expect = f.readlines()
27         self.diff_report(cmd, expect, expectfile=expectfile)
28
29     def diff_report(self, cmd, expect, expectfile='(expected)'):
30         got = [x+"\n" for x in cmd.report().strip("\n").split("\n")]
31         self.assertEqual(got, expect, "\n"+"".join(difflib.context_diff(
32             expect, got, fromfile=expectfile, tofile="(generated)")))
33
34
35 class SummarizeFile(ReportDiff):
36     def test_example_files(self):
37         for fnm in glob.glob(os.path.join(TESTS_DIR, '*.txt.gz')):
38             logfile = os.path.join(TESTS_DIR, fnm)
39             args = crunchstat_summary.command.ArgumentParser().parse_args(
40                 ['--log-file', logfile])
41             cmd = crunchstat_summary.command.Command(args)
42             cmd.run()
43             self.diff_known_report(logfile, cmd)
44
45
46 class HTMLFromFile(ReportDiff):
47     def test_example_files(self):
48         # Note we don't test the output content at all yet; we're
49         # mainly just verifying the --format=html option isn't ignored
50         # and the HTML code path doesn't crash.
51         for fnm in glob.glob(os.path.join(TESTS_DIR, '*.txt.gz')):
52             logfile = os.path.join(TESTS_DIR, fnm)
53             args = crunchstat_summary.command.ArgumentParser().parse_args(
54                 ['--format=html', '--log-file', logfile])
55             cmd = crunchstat_summary.command.Command(args)
56             cmd.run()
57             if sys.version_info >= (3,2):
58                 self.assertRegex(cmd.report(), r'(?is)<html>.*</html>\s*$')
59             else:
60                 self.assertRegexpMatches(cmd.report(), r'(?is)<html>.*</html>\s*$')
61
62
63 class SummarizeEdgeCases(unittest.TestCase):
64     def test_error_messages(self):
65         logfile = open(os.path.join(TESTS_DIR, 'crunchstat_error_messages.txt'), encoding='utf-8')
66         s = crunchstat_summary.summarizer.Summarizer(logfile)
67         s.run()
68
69
70 class SummarizeContainer(ReportDiff):
71     fake_container = {
72         'uuid': '9tee4-dz642-lymtndkpy39eibk',
73         'created_at': '2017-08-18T14:27:25.371388141',
74         'log': '9tee4-4zz18-ihyzym9tcwjwg4r',
75     }
76     fake_request = {
77         'uuid': '9tee4-xvhdp-uper95jktm10d3w',
78         'name': 'container',
79         'created_at': '2017-08-18T14:27:25.242339223Z',
80         'container_uuid': fake_container['uuid'],
81     }
82     reportfile = os.path.join(
83         TESTS_DIR, 'container_9tee4-dz642-lymtndkpy39eibk.txt.gz')
84     logfile = os.path.join(
85         TESTS_DIR, 'container_9tee4-dz642-lymtndkpy39eibk-crunchstat.txt.gz')
86     arvmountlog = os.path.join(
87         TESTS_DIR, 'container_9tee4-dz642-lymtndkpy39eibk-arv-mount.txt.gz')
88
89     @mock.patch('arvados.collection.CollectionReader')
90     @mock.patch('arvados.api')
91     def test_container(self, mock_api, mock_cr):
92         mock_api().container_requests().index().execute.return_value = {'items':[]}
93         mock_api().container_requests().get().execute.return_value = self.fake_request
94         mock_api().containers().get().execute.return_value = self.fake_container
95         mock_cr().__iter__.return_value = [
96             'crunch-run.txt', 'stderr.txt', 'node-info.txt',
97             'container.json', 'crunchstat.txt', 'arv-mount.txt']
98         def _open(n):
99             if n == "crunchstat.txt":
100                 return UTF8Decode(gzip.open(self.logfile))
101             elif n == "arv-mount.txt":
102                 return UTF8Decode(gzip.open(self.arvmountlog))
103         mock_cr().open.side_effect = _open
104         args = crunchstat_summary.command.ArgumentParser().parse_args(
105             ['--job', self.fake_request['uuid']])
106         cmd = crunchstat_summary.command.Command(args)
107         cmd.run()
108         self.diff_known_report(self.reportfile, cmd)
109
110
111 class SummarizeJob(ReportDiff):
112     fake_job_uuid = '4xphq-8i9sb-jq0ekny1xou3zoh'
113     fake_log_id = 'fake-log-collection-id'
114     fake_job = {
115         'uuid': fake_job_uuid,
116         'log': fake_log_id,
117     }
118     logfile = os.path.join(TESTS_DIR, 'logfile_20151204190335.txt.gz')
119
120     @mock.patch('arvados.collection.CollectionReader')
121     @mock.patch('arvados.api')
122     def test_job_report(self, mock_api, mock_cr):
123         mock_api().jobs().get().execute.return_value = self.fake_job
124         mock_cr().__iter__.return_value = ['fake-logfile.txt']
125         mock_cr().open.return_value = UTF8Decode(gzip.open(self.logfile))
126         args = crunchstat_summary.command.ArgumentParser().parse_args(
127             ['--job', self.fake_job_uuid])
128         cmd = crunchstat_summary.command.Command(args)
129         cmd.run()
130         self.diff_known_report(self.logfile, cmd)
131         mock_api().jobs().get.assert_called_with(uuid=self.fake_job_uuid)
132         mock_cr.assert_called_with(self.fake_log_id)
133         mock_cr().open.assert_called_with('fake-logfile.txt')
134
135
136 class SummarizePipeline(ReportDiff):
137     fake_instance = {
138         'uuid': 'zzzzz-d1hrv-i3e77t9z5y8j9cc',
139         'owner_uuid': 'zzzzz-tpzed-xurymjxw79nv3jz',
140         'components': collections.OrderedDict([
141             ['foo', {
142                 'job': {
143                     'uuid': 'zzzzz-8i9sb-000000000000000',
144                     'log': 'fake-log-pdh-0',
145                     'runtime_constraints': {
146                         'min_ram_mb_per_node': 900,
147                         'min_cores_per_node': 1,
148                     },
149                 },
150             }],
151             ['bar', {
152                 'job': {
153                     'uuid': 'zzzzz-8i9sb-000000000000001',
154                     'log': 'fake-log-pdh-1',
155                     'runtime_constraints': {
156                         'min_ram_mb_per_node': 900,
157                         'min_cores_per_node': 1,
158                     },
159                 },
160             }],
161             ['no-job-assigned', {}],
162             ['unfinished-job', {
163                 'job': {
164                     'uuid': 'zzzzz-8i9sb-xxxxxxxxxxxxxxx',
165                 },
166             }],
167             ['baz', {
168                 'job': {
169                     'uuid': 'zzzzz-8i9sb-000000000000002',
170                     'log': 'fake-log-pdh-2',
171                     'runtime_constraints': {
172                         'min_ram_mb_per_node': 900,
173                         'min_cores_per_node': 1,
174                     },
175                 },
176             }]]),
177     }
178
179     @mock.patch('arvados.collection.CollectionReader')
180     @mock.patch('arvados.api')
181     def test_pipeline(self, mock_api, mock_cr):
182         logfile = os.path.join(TESTS_DIR, 'logfile_20151204190335.txt.gz')
183         mock_api().pipeline_instances().get().execute. \
184             return_value = self.fake_instance
185         mock_cr().__iter__.return_value = ['fake-logfile.txt']
186         mock_cr().open.side_effect = [UTF8Decode(gzip.open(logfile)) for _ in range(3)]
187         args = crunchstat_summary.command.ArgumentParser().parse_args(
188             ['--pipeline-instance', self.fake_instance['uuid']])
189         cmd = crunchstat_summary.command.Command(args)
190         cmd.run()
191
192         with open(logfile+'.report', encoding='utf-8') as f:
193             job_report = [line for line in f if not line.startswith('#!! ')]
194         expect = (
195             ['### Summary for foo (zzzzz-8i9sb-000000000000000)\n'] +
196             job_report + ['\n'] +
197             ['### Summary for bar (zzzzz-8i9sb-000000000000001)\n'] +
198             job_report + ['\n'] +
199             ['### Summary for unfinished-job (partial) (zzzzz-8i9sb-xxxxxxxxxxxxxxx)\n',
200              '(no report generated)\n',
201              '\n'] +
202             ['### Summary for baz (zzzzz-8i9sb-000000000000002)\n'] +
203             job_report)
204         self.diff_report(cmd, expect)
205         mock_cr.assert_has_calls(
206             [
207                 mock.call('fake-log-pdh-0'),
208                 mock.call('fake-log-pdh-1'),
209                 mock.call('fake-log-pdh-2'),
210             ], any_order=True)
211         mock_cr().open.assert_called_with('fake-logfile.txt')
212
213
214 class SummarizeACRJob(ReportDiff):
215     fake_job = {
216         'uuid': 'zzzzz-8i9sb-i3e77t9z5y8j9cc',
217         'owner_uuid': 'zzzzz-tpzed-xurymjxw79nv3jz',
218         'components': {
219             'foo': 'zzzzz-8i9sb-000000000000000',
220             'bar': 'zzzzz-8i9sb-000000000000001',
221             'unfinished-job': 'zzzzz-8i9sb-xxxxxxxxxxxxxxx',
222             'baz': 'zzzzz-8i9sb-000000000000002',
223         }
224     }
225     fake_jobs_index = { 'items': [
226         {
227             'uuid': 'zzzzz-8i9sb-000000000000000',
228             'log': 'fake-log-pdh-0',
229             'runtime_constraints': {
230                 'min_ram_mb_per_node': 900,
231                 'min_cores_per_node': 1,
232             },
233         },
234         {
235             'uuid': 'zzzzz-8i9sb-000000000000001',
236             'log': 'fake-log-pdh-1',
237             'runtime_constraints': {
238                 'min_ram_mb_per_node': 900,
239                 'min_cores_per_node': 1,
240             },
241         },
242         {
243             'uuid': 'zzzzz-8i9sb-xxxxxxxxxxxxxxx',
244         },
245         {
246             'uuid': 'zzzzz-8i9sb-000000000000002',
247             'log': 'fake-log-pdh-2',
248             'runtime_constraints': {
249                 'min_ram_mb_per_node': 900,
250                 'min_cores_per_node': 1,
251             },
252         },
253     ]}
254     @mock.patch('arvados.collection.CollectionReader')
255     @mock.patch('arvados.api')
256     def test_acr_job(self, mock_api, mock_cr):
257         logfile = os.path.join(TESTS_DIR, 'logfile_20151204190335.txt.gz')
258         mock_api().jobs().index().execute.return_value = self.fake_jobs_index
259         mock_api().jobs().get().execute.return_value = self.fake_job
260         mock_cr().__iter__.return_value = ['fake-logfile.txt']
261         mock_cr().open.side_effect = [UTF8Decode(gzip.open(logfile)) for _ in range(3)]
262         args = crunchstat_summary.command.ArgumentParser().parse_args(
263             ['--job', self.fake_job['uuid']])
264         cmd = crunchstat_summary.command.Command(args)
265         cmd.run()
266
267         with open(logfile+'.report', encoding='utf-8') as f:
268             job_report = [line for line in f if not line.startswith('#!! ')]
269         expect = (
270             ['### Summary for zzzzz-8i9sb-i3e77t9z5y8j9cc (partial) (zzzzz-8i9sb-i3e77t9z5y8j9cc)\n',
271              '(no report generated)\n',
272              '\n'] +
273             ['### Summary for bar (zzzzz-8i9sb-000000000000001)\n'] +
274             job_report + ['\n'] +
275             ['### Summary for baz (zzzzz-8i9sb-000000000000002)\n'] +
276             job_report + ['\n'] +
277             ['### Summary for foo (zzzzz-8i9sb-000000000000000)\n'] +
278             job_report + ['\n'] +
279             ['### Summary for unfinished-job (partial) (zzzzz-8i9sb-xxxxxxxxxxxxxxx)\n',
280              '(no report generated)\n']
281         )
282         self.diff_report(cmd, expect)
283         mock_cr.assert_has_calls(
284             [
285                 mock.call('fake-log-pdh-0'),
286                 mock.call('fake-log-pdh-1'),
287                 mock.call('fake-log-pdh-2'),
288             ], any_order=True)
289         mock_cr().open.assert_called_with('fake-logfile.txt')