Upload upstream chromium 76.0.3809.146
[platform/framework/web/chromium-efl.git] / testing / merge_scripts / standard_gtest_merge_test.py
1 #!/usr/bin/env vpython
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 import cStringIO
7 import json
8 import logging
9 import os
10 import shutil
11 import sys
12 import tempfile
13 import unittest
14
15 import common_merge_script_tests
16
17 THIS_DIR = os.path.dirname(os.path.abspath(__file__))
18
19 # For 'standard_gtest_merge.py'.
20 sys.path.insert(
21     0, os.path.abspath(os.path.join(THIS_DIR, '..', 'resources')))
22
23 import mock
24
25 import standard_gtest_merge
26
27
28 # gtest json output for successfully finished shard #0.
29 GOOD_GTEST_JSON_0 = {
30   'all_tests': [
31     'AlignedMemoryTest.DynamicAllocation',
32     'AlignedMemoryTest.ScopedDynamicAllocation',
33     'AlignedMemoryTest.StackAlignment',
34     'AlignedMemoryTest.StaticAlignment',
35   ],
36   'disabled_tests': [
37     'ConditionVariableTest.TimeoutAcrossSetTimeOfDay',
38     'FileTest.TouchGetInfo',
39     'MessageLoopTestTypeDefault.EnsureDeletion',
40   ],
41   'global_tags': ['CPU_64_BITS', 'MODE_DEBUG', 'OS_LINUX', 'OS_POSIX'],
42   'per_iteration_data': [{
43     'AlignedMemoryTest.DynamicAllocation': [{
44       'elapsed_time_ms': 0,
45       'losless_snippet': True,
46       'output_snippet': 'blah\\n',
47       'output_snippet_base64': 'YmxhaAo=',
48       'status': 'SUCCESS',
49     }],
50     'AlignedMemoryTest.ScopedDynamicAllocation': [{
51       'elapsed_time_ms': 0,
52       'losless_snippet': True,
53       'output_snippet': 'blah\\n',
54       'output_snippet_base64': 'YmxhaAo=',
55       'status': 'SUCCESS',
56     }],
57   }],
58   'test_locations': {
59     'AlignedMemoryTest.DynamicAllocation': {
60       'file': 'foo/bar/allocation_test.cc',
61       'line': 123,
62     },
63     'AlignedMemoryTest.ScopedDynamicAllocation': {
64       'file': 'foo/bar/allocation_test.cc',
65       'line': 456,
66     },
67     # This is a test from a different shard, but this happens in practice and we
68     # should not fail if information is repeated.
69     'AlignedMemoryTest.StaticAlignment': {
70       'file': 'foo/bar/allocation_test.cc',
71       'line': 12,
72     },
73   },
74 }
75
76
77 # gtest json output for successfully finished shard #1.
78 GOOD_GTEST_JSON_1 = {
79   'all_tests': [
80     'AlignedMemoryTest.DynamicAllocation',
81     'AlignedMemoryTest.ScopedDynamicAllocation',
82     'AlignedMemoryTest.StackAlignment',
83     'AlignedMemoryTest.StaticAlignment',
84   ],
85   'disabled_tests': [
86     'ConditionVariableTest.TimeoutAcrossSetTimeOfDay',
87     'FileTest.TouchGetInfo',
88     'MessageLoopTestTypeDefault.EnsureDeletion',
89   ],
90   'global_tags': ['CPU_64_BITS', 'MODE_DEBUG', 'OS_LINUX', 'OS_POSIX'],
91   'per_iteration_data': [{
92     'AlignedMemoryTest.StackAlignment': [{
93       'elapsed_time_ms': 0,
94       'losless_snippet': True,
95       'output_snippet': 'blah\\n',
96       'output_snippet_base64': 'YmxhaAo=',
97       'status': 'SUCCESS',
98     }],
99     'AlignedMemoryTest.StaticAlignment': [{
100       'elapsed_time_ms': 0,
101       'losless_snippet': True,
102       'output_snippet': 'blah\\n',
103       'output_snippet_base64': 'YmxhaAo=',
104       'status': 'SUCCESS',
105     }],
106   }],
107   'test_locations': {
108     'AlignedMemoryTest.StackAlignment': {
109       'file': 'foo/bar/allocation_test.cc',
110       'line': 789,
111     },
112     'AlignedMemoryTest.StaticAlignment': {
113       'file': 'foo/bar/allocation_test.cc',
114       'line': 12,
115     },
116   },
117 }
118
119
120 TIMED_OUT_GTEST_JSON_1 = {
121   'disabled_tests': [],
122   'global_tags': [],
123   'all_tests': [
124     'AlignedMemoryTest.DynamicAllocation',
125     'AlignedMemoryTest.ScopedDynamicAllocation',
126     'AlignedMemoryTest.StackAlignment',
127     'AlignedMemoryTest.StaticAlignment',
128   ],
129   'per_iteration_data': [{
130     'AlignedMemoryTest.StackAlignment': [{
131       'elapsed_time_ms': 54000,
132       'losless_snippet': True,
133       'output_snippet': 'timed out',
134       'output_snippet_base64': '',
135       'status': 'FAILURE',
136     }],
137     'AlignedMemoryTest.StaticAlignment': [{
138       'elapsed_time_ms': 0,
139       'losless_snippet': True,
140       'output_snippet': '',
141       'output_snippet_base64': '',
142       'status': 'NOTRUN',
143     }],
144   }],
145   'test_locations': {
146     'AlignedMemoryTest.StackAlignment': {
147       'file': 'foo/bar/allocation_test.cc',
148       'line': 789,
149     },
150     'AlignedMemoryTest.StaticAlignment': {
151       'file': 'foo/bar/allocation_test.cc',
152       'line': 12,
153     },
154   },
155 }
156
157 # GOOD_GTEST_JSON_0 and GOOD_GTEST_JSON_1 merged.
158 GOOD_GTEST_JSON_MERGED = {
159   'all_tests': [
160     'AlignedMemoryTest.DynamicAllocation',
161     'AlignedMemoryTest.ScopedDynamicAllocation',
162     'AlignedMemoryTest.StackAlignment',
163     'AlignedMemoryTest.StaticAlignment',
164   ],
165   'disabled_tests': [
166     'ConditionVariableTest.TimeoutAcrossSetTimeOfDay',
167     'FileTest.TouchGetInfo',
168     'MessageLoopTestTypeDefault.EnsureDeletion',
169   ],
170   'global_tags': ['CPU_64_BITS', 'MODE_DEBUG', 'OS_LINUX', 'OS_POSIX'],
171   'missing_shards': [],
172   'per_iteration_data': [{
173     'AlignedMemoryTest.DynamicAllocation': [{
174       'elapsed_time_ms': 0,
175       'losless_snippet': True,
176       'output_snippet': 'blah\\n',
177       'output_snippet_base64': 'YmxhaAo=',
178       'status': 'SUCCESS',
179     }],
180     'AlignedMemoryTest.ScopedDynamicAllocation': [{
181       'elapsed_time_ms': 0,
182       'losless_snippet': True,
183       'output_snippet': 'blah\\n',
184       'output_snippet_base64': 'YmxhaAo=',
185       'status': 'SUCCESS',
186     }],
187     'AlignedMemoryTest.StackAlignment': [{
188       'elapsed_time_ms': 0,
189       'losless_snippet': True,
190       'output_snippet': 'blah\\n',
191       'output_snippet_base64': 'YmxhaAo=',
192       'status': 'SUCCESS',
193     }],
194     'AlignedMemoryTest.StaticAlignment': [{
195       'elapsed_time_ms': 0,
196       'losless_snippet': True,
197       'output_snippet': 'blah\\n',
198       'output_snippet_base64': 'YmxhaAo=',
199       'status': 'SUCCESS',
200     }],
201   }],
202   'swarming_summary': {
203     u'shards': [
204       {
205         u'state': u'COMPLETED',
206         u'outputs_ref': {
207           u'view_url': u'blah',
208         },
209       }
210       ],
211   },
212   'test_locations': {
213     'AlignedMemoryTest.StackAlignment': {
214       'file': 'foo/bar/allocation_test.cc',
215       'line': 789,
216     },
217     'AlignedMemoryTest.StaticAlignment': {
218       'file': 'foo/bar/allocation_test.cc',
219       'line': 12,
220     },
221     'AlignedMemoryTest.DynamicAllocation': {
222       'file': 'foo/bar/allocation_test.cc',
223       'line': 123,
224     },
225     'AlignedMemoryTest.ScopedDynamicAllocation': {
226       'file': 'foo/bar/allocation_test.cc',
227       'line': 456,
228     },
229   },
230 }
231
232
233 # Only shard #1 finished. UNRELIABLE_RESULTS is set.
234 BAD_GTEST_JSON_ONLY_1_SHARD = {
235   'all_tests': [
236     'AlignedMemoryTest.DynamicAllocation',
237     'AlignedMemoryTest.ScopedDynamicAllocation',
238     'AlignedMemoryTest.StackAlignment',
239     'AlignedMemoryTest.StaticAlignment',
240   ],
241   'disabled_tests': [
242     'ConditionVariableTest.TimeoutAcrossSetTimeOfDay',
243     'FileTest.TouchGetInfo',
244     'MessageLoopTestTypeDefault.EnsureDeletion',
245   ],
246   'global_tags': [
247     'CPU_64_BITS',
248     'MODE_DEBUG',
249     'OS_LINUX',
250     'OS_POSIX',
251     'UNRELIABLE_RESULTS',
252   ],
253   'missing_shards': [0],
254   'per_iteration_data': [{
255     'AlignedMemoryTest.StackAlignment': [{
256       'elapsed_time_ms': 0,
257       'losless_snippet': True,
258       'output_snippet': 'blah\\n',
259       'output_snippet_base64': 'YmxhaAo=',
260       'status': 'SUCCESS',
261     }],
262     'AlignedMemoryTest.StaticAlignment': [{
263       'elapsed_time_ms': 0,
264       'losless_snippet': True,
265       'output_snippet': 'blah\\n',
266       'output_snippet_base64': 'YmxhaAo=',
267       'status': 'SUCCESS',
268     }],
269   }],
270   'test_locations': {
271     'AlignedMemoryTest.StackAlignment': {
272       'file': 'foo/bar/allocation_test.cc',
273       'line': 789,
274     },
275     'AlignedMemoryTest.StaticAlignment': {
276       'file': 'foo/bar/allocation_test.cc',
277       'line': 12,
278     },
279   },
280 }
281
282
283 # GOOD_GTEST_JSON_0 and TIMED_OUT_GTEST_JSON_1 merged.
284 TIMED_OUT_GTEST_JSON_MERGED = {
285   'all_tests': [
286     'AlignedMemoryTest.DynamicAllocation',
287     'AlignedMemoryTest.ScopedDynamicAllocation',
288     'AlignedMemoryTest.StackAlignment',
289     'AlignedMemoryTest.StaticAlignment',
290   ],
291   'disabled_tests': [
292     'ConditionVariableTest.TimeoutAcrossSetTimeOfDay',
293     'FileTest.TouchGetInfo',
294     'MessageLoopTestTypeDefault.EnsureDeletion',
295   ],
296   'global_tags': ['CPU_64_BITS', 'MODE_DEBUG', 'OS_LINUX', 'OS_POSIX'],
297   'missing_shards': [],
298   'per_iteration_data': [{
299     'AlignedMemoryTest.DynamicAllocation': [{
300       'elapsed_time_ms': 0,
301       'losless_snippet': True,
302       'output_snippet': 'blah\\n',
303       'output_snippet_base64': 'YmxhaAo=',
304       'status': 'SUCCESS',
305     }],
306     'AlignedMemoryTest.ScopedDynamicAllocation': [{
307       'elapsed_time_ms': 0,
308       'losless_snippet': True,
309       'output_snippet': 'blah\\n',
310       'output_snippet_base64': 'YmxhaAo=',
311       'status': 'SUCCESS',
312     }],
313     'AlignedMemoryTest.StackAlignment': [{
314       'elapsed_time_ms': 54000,
315       'losless_snippet': True,
316       'output_snippet': 'timed out',
317       'output_snippet_base64': '',
318       'status': 'FAILURE',
319     }],
320     'AlignedMemoryTest.StaticAlignment': [{
321       'elapsed_time_ms': 0,
322       'losless_snippet': True,
323       'output_snippet': '',
324       'output_snippet_base64': '',
325       'status': 'NOTRUN',
326     }],
327   }],
328   'swarming_summary': {
329     u'shards': [
330       {
331         u'state': u'COMPLETED',
332       },
333       {
334         u'state': u'TIMED_OUT',
335       },
336       ],
337   },
338   'test_locations': {
339     'AlignedMemoryTest.StackAlignment': {
340       'file': 'foo/bar/allocation_test.cc',
341       'line': 789,
342     },
343     'AlignedMemoryTest.StaticAlignment': {
344       'file': 'foo/bar/allocation_test.cc',
345       'line': 12,
346     },
347     'AlignedMemoryTest.DynamicAllocation': {
348       'file': 'foo/bar/allocation_test.cc',
349       'line': 123,
350     },
351     'AlignedMemoryTest.ScopedDynamicAllocation': {
352       'file': 'foo/bar/allocation_test.cc',
353       'line': 456,
354     },
355   },
356 }
357
358
359 class _StandardGtestMergeTest(unittest.TestCase):
360
361   def setUp(self):
362     self.temp_dir = tempfile.mkdtemp()
363
364   def tearDown(self):
365     shutil.rmtree(self.temp_dir)
366
367   def _write_temp_file(self, path, content):
368     abs_path = os.path.join(self.temp_dir, path.replace('/', os.sep))
369     if not os.path.exists(os.path.dirname(abs_path)):
370       os.makedirs(os.path.dirname(abs_path))
371     with open(abs_path, 'w') as f:
372       if isinstance(content, dict):
373         json.dump(content, f)
374       else:
375         assert isinstance(content, str)
376         f.write(content)
377     return abs_path
378
379
380 class LoadShardJsonTest(_StandardGtestMergeTest):
381
382   def test_double_digit_jsons(self):
383     jsons_to_merge = []
384     for i in xrange(15):
385       json_dir = os.path.join(self.temp_dir, str(i))
386       json_path = os.path.join(json_dir, 'output.json')
387       if not os.path.exists(json_dir):
388         os.makedirs(json_dir)
389       with open(json_path, 'w') as f:
390         json.dump({'all_tests': ['LoadShardJsonTest.test%d' % i]}, f)
391       jsons_to_merge.append(json_path)
392
393     content, err = standard_gtest_merge.load_shard_json(
394       0, None, jsons_to_merge)
395     self.assertEqual({'all_tests': ['LoadShardJsonTest.test0']}, content)
396     self.assertIsNone(err)
397
398     content, err = standard_gtest_merge.load_shard_json(
399       12, None, jsons_to_merge)
400     self.assertEqual({'all_tests': ['LoadShardJsonTest.test12']}, content)
401     self.assertIsNone(err)
402
403   def test_double_task_id_jsons(self):
404     jsons_to_merge = []
405     for i in xrange(15):
406       json_dir = os.path.join(self.temp_dir, 'deadbeef%d' % i)
407       json_path = os.path.join(json_dir, 'output.json')
408       if not os.path.exists(json_dir):
409         os.makedirs(json_dir)
410       with open(json_path, 'w') as f:
411         json.dump({'all_tests': ['LoadShardJsonTest.test%d' % i]}, f)
412       jsons_to_merge.append(json_path)
413
414     content, err = standard_gtest_merge.load_shard_json(
415       0, 'deadbeef0', jsons_to_merge)
416     self.assertEqual({'all_tests': ['LoadShardJsonTest.test0']},
417                      content)
418     self.assertIsNone(err)
419
420     content, err = standard_gtest_merge.load_shard_json(
421       12, 'deadbeef12', jsons_to_merge)
422     self.assertEqual({'all_tests': ['LoadShardJsonTest.test12']},
423                      content)
424     self.assertIsNone(err)
425
426
427 class MergeShardResultsTest(_StandardGtestMergeTest):
428   """Tests for merge_shard_results function."""
429
430   def setUp(self):
431     super(MergeShardResultsTest, self).setUp()
432     self.summary = None
433     self.test_files = []
434
435   def stage(self, summary, files):
436     self.summary = self._write_temp_file('summary.json', summary)
437     for path, content in files.iteritems():
438       abs_path = self._write_temp_file(path, content)
439       self.test_files.append(abs_path)
440
441   def call(self):
442     stdout = cStringIO.StringIO()
443     with mock.patch('sys.stdout', stdout):
444       merged = standard_gtest_merge.merge_shard_results(
445           self.summary, self.test_files)
446       return merged, stdout.getvalue().strip()
447
448   def assertUnicodeEquals(self, expectation, result):
449     def convert_to_unicode(key_or_value):
450       if isinstance(key_or_value, str):
451         return unicode(key_or_value)
452       if isinstance(key_or_value, dict):
453         return {convert_to_unicode(k): convert_to_unicode(v)
454                 for k, v in key_or_value.items()}
455       if isinstance(key_or_value, list):
456         return [convert_to_unicode(x) for x in key_or_value]
457       return key_or_value
458
459     unicode_expectations = convert_to_unicode(expectation)
460     unicode_result = convert_to_unicode(result)
461     self.assertEquals(unicode_expectations, unicode_result)
462
463   def test_ok(self):
464     # Two shards, both successfully finished.
465     self.stage({
466       u'shards': [
467         {
468           u'state': u'COMPLETED',
469         },
470         {
471           u'state': u'COMPLETED',
472         },
473       ],
474     },
475     {
476       '0/output.json': GOOD_GTEST_JSON_0,
477       '1/output.json': GOOD_GTEST_JSON_1,
478     })
479     merged, stdout = self.call()
480     merged['swarming_summary'] = {
481       'shards': [
482         {
483           u'state': u'COMPLETED',
484           u'outputs_ref': {
485             u'view_url': u'blah',
486           },
487         }
488       ],
489     }
490     self.assertUnicodeEquals(GOOD_GTEST_JSON_MERGED, merged)
491     self.assertEqual('', stdout)
492
493   def test_timed_out(self):
494     # Two shards, both successfully finished.
495     self.stage({
496       'shards': [
497         {
498           'state': 'COMPLETED',
499         },
500         {
501           'state': 'TIMED_OUT',
502         },
503       ],
504     },
505     {
506       '0/output.json': GOOD_GTEST_JSON_0,
507       '1/output.json': TIMED_OUT_GTEST_JSON_1,
508     })
509     merged, stdout = self.call()
510
511     self.assertUnicodeEquals(TIMED_OUT_GTEST_JSON_MERGED, merged)
512     self.assertIn(
513         'Test runtime exceeded allocated time\n', stdout)
514
515   def test_missing_summary_json(self):
516     # summary.json is missing, should return None and emit warning.
517     self.summary = os.path.join(self.temp_dir, 'summary.json')
518     merged, output = self.call()
519     self.assertEqual(None, merged)
520     self.assertIn('@@@STEP_WARNINGS@@@', output)
521     self.assertIn('summary.json is missing or can not be read', output)
522
523   def test_unfinished_shards(self):
524     # Only one shard (#1) finished. Shard #0 did not.
525     self.stage({
526       u'shards': [
527         None,
528         {
529           u'state': u'COMPLETED',
530         },
531       ],
532     },
533     {
534       u'1/output.json': GOOD_GTEST_JSON_1,
535     })
536     merged, stdout = self.call()
537     merged.pop('swarming_summary')
538     self.assertUnicodeEquals(BAD_GTEST_JSON_ONLY_1_SHARD, merged)
539     self.assertIn(
540         '@@@STEP_WARNINGS@@@\nsome shards did not complete: 0\n', stdout)
541     self.assertIn(
542         '@@@STEP_LOG_LINE@some shards did not complete: 0@'
543         'Missing results from the following shard(s): 0@@@\n', stdout)
544
545   def test_missing_output_json(self):
546     # Shard #0 output json is missing.
547     self.stage({
548       u'shards': [
549         {
550           u'state': u'COMPLETED',
551         },
552         {
553           u'state': u'COMPLETED',
554         },
555       ],
556     },
557     {
558       u'1/output.json': GOOD_GTEST_JSON_1,
559     })
560     merged, stdout = self.call()
561     merged.pop('swarming_summary')
562     self.assertUnicodeEquals(BAD_GTEST_JSON_ONLY_1_SHARD, merged)
563     self.assertIn(
564         'No result was found: '
565         'shard 0 test output was missing', stdout)
566
567   def test_large_output_json(self):
568     # a shard is too large.
569     self.stage({
570       u'shards': [
571         {
572           u'state': u'COMPLETED',
573         },
574         {
575           u'state': u'COMPLETED',
576         },
577       ],
578     },
579     {
580       '0/output.json': GOOD_GTEST_JSON_0,
581       '1/output.json': GOOD_GTEST_JSON_1,
582     })
583     old_json_limit = standard_gtest_merge.OUTPUT_JSON_SIZE_LIMIT
584     len0 = len(json.dumps(GOOD_GTEST_JSON_0))
585     len1 = len(json.dumps(GOOD_GTEST_JSON_1))
586     large_shard = "0" if len0 > len1 else "1"
587     try:
588       # Override max output.json size just for this test.
589       standard_gtest_merge.OUTPUT_JSON_SIZE_LIMIT = min(len0,len1)
590       merged, stdout = self.call()
591       merged.pop('swarming_summary')
592       self.assertUnicodeEquals(BAD_GTEST_JSON_ONLY_1_SHARD, merged)
593       self.assertIn(
594           'No result was found: '
595           'shard %s test output exceeded the size limit' % large_shard, stdout)
596     finally:
597       standard_gtest_merge.OUTPUT_JSON_SIZE_LIMIT = old_json_limit
598
599
600 class CommandLineTest(common_merge_script_tests.CommandLineTest):
601
602   def __init__(self, methodName='runTest'):
603     super(CommandLineTest, self).__init__(methodName, standard_gtest_merge)
604
605
606 if __name__ == '__main__':
607   logging.basicConfig(
608       level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
609   if '-v' in sys.argv:
610     unittest.TestCase.maxDiff = None
611   unittest.main()