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