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