1#!/usr/bin/env vpython3 2# Copyright 2016 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 6import copy 7import unittest 8 9import six 10 11import results_merger 12 13GOOD_JSON_TEST_RESULT_0 = { 14 'tests': { 15 'car': { 16 'honda': { 17 'expected': 'PASS', 18 'actual': 'PASS' 19 }, 20 'toyota': { 21 'expected': 'FAIL', 22 'actual': 'FAIL' 23 } 24 }, 25 'computer': { 26 'dell': { 27 'expected': 'PASS', 28 'actual': 'PASS' 29 } 30 }, 31 }, 32 'interrupted': False, 33 'version': 3, 34 'seconds_since_epoch': 1406662289.76, 35 'num_failures_by_type': { 36 'FAIL': 0, 37 'PASS': 2 38 }, 39 'layout_tests_dir': 'abc' 40} 41 42GOOD_JSON_TEST_RESULT_1 = { 43 'tests': { 44 'car': { 45 'tesla': { 46 'expected': 'PASS', 47 'actual': 'PASS' 48 }, 49 }, 50 'burger': { 51 'mcdonald': { 52 'expected': 'PASS', 53 'actual': 'PASS' 54 } 55 }, 56 }, 57 'interrupted': False, 58 'version': 3, 59 'seconds_since_epoch': 1406662283.11, 60 'num_failures_by_type': { 61 'FAIL': 0, 62 'PASS': 2 63 }, 64 'layout_tests_dir': '123' 65} 66 67GOOD_JSON_TEST_RESULT_2 = { 68 'tests': { 69 'car': { 70 'mercedes': { 71 'expected': 'PASS', 72 'actual': 'FAIL' 73 }, 74 }, 75 'burger': { 76 'in n out': { 77 'expected': 'PASS', 78 'actual': 'PASS' 79 } 80 }, 81 }, 82 'interrupted': True, 83 'version': 3, 84 'seconds_since_epoch': 1406662200.01, 85 'num_failures_by_type': { 86 'FAIL': 1, 87 'PASS': 1 88 } 89} 90 91GOOD_JSON_TEST_RESULT_MERGED = { 92 'tests': { 93 'car': { 94 'tesla': { 95 'expected': 'PASS', 96 'actual': 'PASS' 97 }, 98 'mercedes': { 99 'expected': 'PASS', 100 'actual': 'FAIL' 101 }, 102 'honda': { 103 'expected': 'PASS', 104 'actual': 'PASS' 105 }, 106 'toyota': { 107 'expected': 'FAIL', 108 'actual': 'FAIL' 109 } 110 }, 111 'computer': { 112 'dell': { 113 'expected': 'PASS', 114 'actual': 'PASS' 115 } 116 }, 117 'burger': { 118 'mcdonald': { 119 'expected': 'PASS', 120 'actual': 'PASS' 121 }, 122 'in n out': { 123 'expected': 'PASS', 124 'actual': 'PASS' 125 } 126 } 127 }, 128 'interrupted': True, 129 'version': 3, 130 'seconds_since_epoch': 1406662200.01, 131 'num_failures_by_type': { 132 'FAIL': 1, 133 'PASS': 5 134 }, 135 'layout_tests_dir': '123' 136} 137 138 139def extend(initial, add): 140 out = copy.deepcopy(initial) 141 out.update(add) 142 return out 143 144 145def remove(initial, keys): 146 out = copy.deepcopy(initial) 147 for k in keys: 148 del out[k] 149 return out 150 151 152# These unittests are run in PRESUBMIT, but not by recipe_simulation_test, hence 153# to avoid false alert on missing coverage by recipe_simulation_test, we mark 154# these code as no cover. 155class MergingTest(unittest.TestCase): # pragma: no cover 156 maxDiff = None # Show full diff if assertion fail 157 158 def test_merge_tries(self): 159 self.assertEqual({ 160 'a': 'A', 161 'b': { 162 'c': 'C' 163 } 164 }, results_merger.merge_tries({ 165 'a': 'A', 166 'b': {} 167 }, {'b': { 168 'c': 'C' 169 }})) 170 171 def test_merge_tries_unmergable(self): 172 with six.assertRaisesRegex(self, results_merger.MergeException, 'a:b'): 173 results_merger.merge_tries({'a': {'b': 'A'}}, {'a': {'b': 'C'}}) 174 175 def test_merge_metadata(self): 176 metadata1 = {'metadata': {'tags': ['foo', 'bar']}} 177 metadata2 = {'metadata': {'tags': ['foo', 'bat']}} 178 merged_results = results_merger.merge_test_results([ 179 extend(GOOD_JSON_TEST_RESULT_0, metadata1), 180 extend(GOOD_JSON_TEST_RESULT_1, metadata2) 181 ]) 182 self.assertEqual(merged_results['metadata']['tags'], ['foo', 'bat']) 183 184 def test_merge_json_test_results_nop(self): 185 good_json_results = (GOOD_JSON_TEST_RESULT_0, GOOD_JSON_TEST_RESULT_1, 186 GOOD_JSON_TEST_RESULT_2, GOOD_JSON_TEST_RESULT_MERGED) 187 for j in good_json_results: 188 # Clone so we can check the input dictionaries are not modified 189 a = copy.deepcopy(j) 190 self.assertEqual(results_merger.merge_test_results([a]), j) 191 self.assertEqual(a, j) 192 193 def test_merge_json_test_results_invalid_version(self): 194 with self.assertRaises(results_merger.MergeException): 195 results_merger.merge_test_results([ 196 extend(GOOD_JSON_TEST_RESULT_0, {'version': 5}), 197 ]) 198 199 with self.assertRaises(results_merger.MergeException): 200 results_merger.merge_test_results([ 201 GOOD_JSON_TEST_RESULT_0, 202 extend(GOOD_JSON_TEST_RESULT_1, {'version': 5}), 203 ]) 204 205 def test_merge_json_test_results_missing_version(self): 206 with self.assertRaises(results_merger.MergeException): 207 results_merger.merge_test_results([ 208 remove(GOOD_JSON_TEST_RESULT_0, ['version']), 209 ]) 210 211 with self.assertRaises(results_merger.MergeException): 212 results_merger.merge_test_results([ 213 GOOD_JSON_TEST_RESULT_0, 214 remove(GOOD_JSON_TEST_RESULT_1, ['version']), 215 ]) 216 217 def test_merge_json_test_results_invalid_extra(self): 218 with self.assertRaises(results_merger.MergeException): 219 results_merger.merge_test_results([ 220 extend(GOOD_JSON_TEST_RESULT_0, {'extra': True}), 221 ]) 222 223 with self.assertRaises(results_merger.MergeException): 224 results_merger.merge_test_results([ 225 GOOD_JSON_TEST_RESULT_0, 226 extend(GOOD_JSON_TEST_RESULT_1, {'extra': True}), 227 ]) 228 229 def test_merge_json_test_results_missing_required(self): 230 with self.assertRaises(results_merger.MergeException): 231 results_merger.merge_test_results([ 232 remove(GOOD_JSON_TEST_RESULT_0, ['interrupted']), 233 ]) 234 235 with self.assertRaises(results_merger.MergeException): 236 results_merger.merge_test_results([ 237 GOOD_JSON_TEST_RESULT_0, 238 remove(GOOD_JSON_TEST_RESULT_1, ['interrupted']), 239 ]) 240 241 def test_merge_json_test_results_multiple(self): 242 self.assertEqual( 243 results_merger.merge_test_results([ 244 GOOD_JSON_TEST_RESULT_0, 245 GOOD_JSON_TEST_RESULT_1, 246 GOOD_JSON_TEST_RESULT_2, 247 ]), GOOD_JSON_TEST_RESULT_MERGED) 248 249 def test_merge_json_test_results_optional_matches(self): 250 self.assertEqual( 251 results_merger.merge_test_results([ 252 extend(GOOD_JSON_TEST_RESULT_0, {'path_delimiter': '.'}), 253 extend(GOOD_JSON_TEST_RESULT_1, {'path_delimiter': '.'}), 254 extend(GOOD_JSON_TEST_RESULT_2, {'path_delimiter': '.'}), 255 ]), extend(GOOD_JSON_TEST_RESULT_MERGED, {'path_delimiter': '.'})) 256 257 def test_merge_json_test_results_optional_differs(self): 258 with self.assertRaises(results_merger.MergeException): 259 results_merger.merge_test_results([ 260 extend(GOOD_JSON_TEST_RESULT_0, {'path_delimiter': '.'}), 261 extend(GOOD_JSON_TEST_RESULT_1, {'path_delimiter': '.'}), 262 extend(GOOD_JSON_TEST_RESULT_2, {'path_delimiter': '/'}), 263 ]) 264 265 def test_merge_json_test_results_optional_count(self): 266 self.assertEqual( 267 results_merger.merge_test_results([ 268 extend(GOOD_JSON_TEST_RESULT_0, {'fixable': 1}), 269 extend(GOOD_JSON_TEST_RESULT_1, {'fixable': 2}), 270 extend(GOOD_JSON_TEST_RESULT_2, {'fixable': 3}), 271 ]), extend(GOOD_JSON_TEST_RESULT_MERGED, {'fixable': 6})) 272 273 def test_merge_nothing(self): 274 self.assertEqual(results_merger.merge_test_results([]), {}) 275 276 277# TODO(tansell): Make this test fail properly, currently fails with an 278# AttributeError. 279# def test_merge_test_name_conflict(self): 280# self.maxDiff = None # Show full diff if assertion fail 281# with self.assertRaises(results_merger.MergeException): 282# results_merger.merge_test_results( 283# [GOOD_JSON_TEST_RESULT_0, GOOD_JSON_TEST_RESULT_0]) 284 285if __name__ == '__main__': 286 unittest.main() # pragma: no cover 287