| # Copyright 2017 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # pylint: disable=invalid-name |
| # pylint complains about the assertXXX methods and the usage of short variables |
| # m/a/b/d in the tests. |
| |
| import types |
| import unittest |
| |
| import cStringIO as StringIO |
| |
| from collections import OrderedDict |
| |
| from blinkpy.common.system.filesystem_mock import FileSystemTestCase, MockFileSystem |
| from blinkpy.web_tests import merge_results |
| |
| |
| class JSONMergerTests(unittest.TestCase): |
| |
| def test_type_match(self): |
| self.assertTrue( |
| merge_results.TypeMatch(types.DictType)(dict())) |
| self.assertFalse( |
| merge_results.TypeMatch(types.ListType, types.TupleType)(dict())) |
| self.assertTrue( |
| merge_results.TypeMatch(types.ListType, types.TupleType)(list())) |
| self.assertTrue( |
| merge_results.TypeMatch(types.ListType, types.TupleType)(tuple())) |
| |
| def test_merge_listlike(self): |
| m = merge_results.JSONMerger() |
| |
| tests = [ |
| # expected, (inputa, inputb) |
| ([1, 2], ([1], [2])), |
| ([2, 1], ([2], [1])), |
| ([1, 2, 3], ([], [1, 2, 3])), |
| ([1, 2, 3], ([1], [2, 3])), |
| ([1, 2, 3], ([1, 2], [3])), |
| ([1, 2, 3], ([1, 2, 3], [])), |
| ] |
| |
| for expected, (inputa, inputb) in tests: |
| self.assertListEqual( |
| expected, m.merge_listlike([inputa, inputb])) |
| self.assertListEqual( |
| expected, m.merge([inputa, inputb])) |
| self.assertSequenceEqual( |
| expected, |
| m.merge_listlike([tuple(inputa), tuple(inputb)]), |
| types.TupleType) |
| self.assertSequenceEqual( |
| expected, |
| m.merge([tuple(inputa), tuple(inputb)]), |
| types.TupleType) |
| |
| def test_merge_simple_dict(self): |
| m = merge_results.JSONMerger() |
| m.fallback_matcher = m.merge_equal |
| |
| tests = [ |
| # expected, (inputa, inputb) |
| ({'a': 1}, ({'a': 1}, {'a': 1})), |
| |
| ({'a': 1, 'b': 2}, ({'a': 1, 'b': 2}, {})), |
| ({'a': 1, 'b': 2}, ({}, {'a': 1, 'b': 2})), |
| ({'a': 1, 'b': 2}, ({'a': 1}, {'b': 2})), |
| |
| ({'a': 1, 'b': 2, 'c': 3}, ({'a': 1, 'b': 2, 'c': 3}, {})), |
| ({'a': 1, 'b': 2, 'c': 3}, ({'a': 1, 'b': 2}, {'c': 3})), |
| ({'a': 1, 'b': 2, 'c': 3}, ({'a': 1}, {'b': 2, 'c': 3})), |
| ({'a': 1, 'b': 2, 'c': 3}, ({}, {'a': 1, 'b': 2, 'c': 3})), |
| ] |
| |
| for expected, (inputa, inputb) in tests: |
| self.assertDictEqual(expected, m.merge_dictlike([inputa, inputb])) |
| |
| with self.assertRaises(merge_results.MergeFailure): |
| m.merge_dictlike([{'a': 1}, {'a': 2}]) |
| |
| def test_merge_compound_dict(self): |
| m = merge_results.JSONMerger() |
| |
| tests = [ |
| # expected, (inputa, inputb) |
| ({'a': [1, 2]}, ({'a': [1]}, {'a': [2]})), |
| ({'a': [1, 'c', 3]}, ({'a': [1]}, {'a': ['c', 3]})), |
| ({'a': [1], 'b': [2]}, ({'a': [1]}, {'b': [2]})), |
| ({'a': {'b': 1, 'c': 2}}, ({'a': {'b': 1}}, {'a': {'c': 2}})), |
| ] |
| for expected, (inputa, inputb) in tests: |
| self.assertDictEqual(expected, m.merge_dictlike([inputa, inputb])) |
| |
| def test_merge(self): |
| m = merge_results.JSONMerger() |
| m.fallback_matcher = m.merge_equal |
| |
| tests = [ |
| # expected, (inputa, inputb) |
| (None, (None, None)), |
| ({'a': 1}, ({'a': 1}, None)), |
| ({'b': 2}, (None, {'b': 2})), |
| |
| ({'a': 1}, ({'a': 1}, {'a': 1})), |
| |
| # "Left side" value is None |
| ({'a': None, 'b': 2}, ({'a': None, 'b': 2}, {})), |
| ({'a': None, 'b': 2}, ({}, {'a': None, 'b': 2})), |
| ({'a': None, 'b': 2}, ({'a': None}, {'b': 2})), |
| |
| ({'a': None, 'b': 2, 'c': 3}, ({'a': None, 'b': 2, 'c': 3}, {})), |
| ({'a': None, 'b': 2, 'c': 3}, ({'a': None, 'b': 2}, {'c': 3})), |
| ({'a': None, 'b': 2, 'c': 3}, ({'a': None}, {'b': 2, 'c': 3})), |
| ({'a': None, 'b': 2, 'c': 3}, ({}, {'a': None, 'b': 2, 'c': 3})), |
| |
| # "Right side" value is None |
| ({'a': 1, 'b': None}, ({'a': 1, 'b': None}, {})), |
| ({'a': 1, 'b': None}, ({}, {'a': 1, 'b': None})), |
| ({'a': 1, 'b': None}, ({'a': 1}, {'b': None})), |
| |
| ({'a': 1, 'b': None, 'c': 3}, ({'a': 1, 'b': None, 'c': 3}, {})), |
| ({'a': 1, 'b': None, 'c': 3}, ({'a': 1, 'b': None}, {'c': 3})), |
| ({'a': 1, 'b': None, 'c': 3}, ({'a': 1}, {'b': None, 'c': 3})), |
| ({'a': 1, 'b': None, 'c': 3}, ({}, {'a': 1, 'b': None, 'c': 3})), |
| |
| # Both values non-None |
| ({'a': 1, 'b': 2}, ({'a': 1, 'b': 2}, {})), |
| ({'a': 1, 'b': 2}, ({}, {'a': 1, 'b': 2})), |
| ({'a': 1, 'b': 2}, ({'a': 1}, {'b': 2})), |
| |
| ({'a': 1, 'b': 2, 'c': 3}, ({'a': 1, 'b': 2, 'c': 3}, {})), |
| ({'a': 1, 'b': 2, 'c': 3}, ({'a': 1, 'b': 2}, {'c': 3})), |
| ({'a': 1, 'b': 2, 'c': 3}, ({'a': 1}, {'b': 2, 'c': 3})), |
| ({'a': 1, 'b': 2, 'c': 3}, ({}, {'a': 1, 'b': 2, 'c': 3})), |
| |
| # Complex values |
| ({'a': [1, 2]}, ({'a': [1]}, {'a': [2]})), |
| ({'a': [1, 'c', 3]}, ({'a': [1]}, {'a': ['c', 3]})), |
| ({'a': [1], 'b': [2]}, ({'a': [1]}, {'b': [2]})), |
| ({'a': {'b': 1, 'c': 2}}, ({'a': {'b': 1}}, {'a': {'c': 2}})), |
| ] |
| |
| for expected, (inputa, inputb) in tests: |
| self.assertEqual(expected, m.merge([inputa, inputb])) |
| |
| with self.assertRaises(merge_results.MergeFailure): |
| m.merge([{'a': 1}, {'a': 2}]) |
| |
| # Ordered values |
| a = OrderedDict({'a': 1}) |
| b = OrderedDict({'b': 2}) |
| |
| a_before_b = OrderedDict() |
| a_before_b['a'] = 1 |
| a_before_b['b'] = 2 |
| |
| b_before_a = OrderedDict() |
| b_before_a['b'] = 2 |
| b_before_a['a'] = 1 |
| |
| r1 = m.merge([a, b]) |
| self.assertSequenceEqual(a_before_b.items(), r1.items()) |
| self.assertIsInstance(r1, OrderedDict) |
| |
| r2 = m.merge([b, a]) |
| self.assertSequenceEqual(b_before_a.items(), r2.items()) |
| self.assertIsInstance(r2, OrderedDict) |
| |
| def test_custom_match_on_name(self): |
| m = merge_results.JSONMerger() |
| m.add_helper( |
| merge_results.NameRegexMatch('a'), |
| lambda o, name=None: sum(o)) |
| |
| self.assertDictEqual({'a': 3}, m.merge([{'a': 1}, {'a': 2}])) |
| with self.assertRaises(merge_results.MergeFailure): |
| m.merge([{'b': 1}, {'b': 2}]) |
| |
| # Test that helpers that are added later have precedence. |
| m.add_helper( |
| merge_results.NameRegexMatch('b'), |
| lambda o, name=None: sum(o)) |
| m.add_helper( |
| merge_results.NameRegexMatch('b'), |
| lambda o, name=None: o[0] - o[1]) |
| self.assertDictEqual({'b': -1}, m.merge([{'b': 1}, {'b': 2}])) |
| |
| def test_custom_match_on_obj_type(self): |
| m = merge_results.JSONMerger() |
| m.add_helper( |
| merge_results.TypeMatch(int), |
| lambda o, name=None: sum(o)) |
| self.assertDictEqual({'a': 3}, m.merge([{'a': 1}, {'a': 2}])) |
| self.assertDictEqual({'b': 3}, m.merge([{'b': 1}, {'b': 2}])) |
| |
| def test_custom_match_on_obj_value(self): |
| m = merge_results.JSONMerger() |
| m.add_helper( |
| merge_results.ValueMatch(3), |
| lambda o, name=None: sum(o)) |
| self.assertDictEqual({'a': 6}, m.merge([{'a': 3}, {'a': 3}])) |
| self.assertDictEqual({'a': 5}, m.merge([{'a': 2}, {'a': 3}])) |
| self.assertDictEqual({'a': 7}, m.merge([{'a': 3}, {'a': 4}])) |
| with self.assertRaises(merge_results.MergeFailure): |
| m.merge([{'a': 1}, {'a': 2}]) |
| |
| |
| class MergeFilesOneTests(FileSystemTestCase): |
| def test(self): |
| mock_filesystem = MockFileSystem({'/s/file1': '1', '/s/file2': '2'}, dirs=['/output']) |
| |
| merger = merge_results.MergeFilesOne(mock_filesystem) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/file1': '1'}): |
| merger('/output/file1', ['/s/file1']) |
| |
| with self.assertRaises(AssertionError): |
| merger('/output/file1', ['/s/file1', '/s/file2']) |
| |
| |
| class MergeFilesMatchingContentsTests(FileSystemTestCase): |
| def test(self): |
| mock_filesystem = MockFileSystem({'/s/file1': '1', '/s/file2': '2', '/s/file3': '1'}, dirs=['/output']) |
| |
| merger = merge_results.MergeFilesMatchingContents(mock_filesystem) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out1': '1'}): |
| merger('/output/out1', ['/s/file1']) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out2': '2'}): |
| merger('/output/out2', ['/s/file2']) |
| |
| with self.assertRaises(merge_results.MergeFailure): |
| merger('/output/out3', ['/s/file1', '/s/file2']) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out4': '1'}): |
| merger('/output/out4', ['/s/file1', '/s/file3']) |
| |
| |
| class MergeFilesLinesSortedTests(FileSystemTestCase): |
| def test(self): |
| mock_filesystem = MockFileSystem({'/s/file1': 'A\nC\n', '/s/file2': 'B\n', '/s/file3': 'A\nB\n'}, dirs=['/output']) |
| |
| merger = merge_results.MergeFilesLinesSorted(mock_filesystem) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out1': 'A\nC\n'}): |
| merger('/output/out1', ['/s/file1']) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out2': 'B\n'}): |
| merger('/output/out2', ['/s/file2']) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out3': 'A\nB\nC\n'}): |
| merger('/output/out3', ['/s/file1', '/s/file2']) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out4': 'A\nB\nB\n'}): |
| merger('/output/out4', ['/s/file2', '/s/file3']) |
| |
| |
| class MergeFilesKeepFilesTests(FileSystemTestCase): |
| |
| def test(self): |
| mock_filesystem = MockFileSystem({'/s1/file1': 'a', '/s2/file1': 'b', '/s3/file1': 'c'}, dirs=['/output']) |
| |
| merger = merge_results.MergeFilesKeepFiles(mock_filesystem) |
| |
| with self.assertFilesAdded(mock_filesystem, {'/output/out_0': 'a', '/output/out_1': 'b', '/output/out_2': 'c'}): |
| merger('/output/out', ['/s1/file1', '/s2/file1', '/s3/file1']) |
| |
| |
| class DirMergerTests(FileSystemTestCase): |
| |
| def test_success_no_overlapping_files(self): |
| mock_filesystem = MockFileSystem({'/shard0/file1': '1', '/shard1/file2': '2'}) |
| d = merge_results.DirMerger(mock_filesystem) |
| with self.assertFilesAdded(mock_filesystem, {'/output/file1': '1', '/output/file2': '2'}): |
| d.merge('/output', ['/shard0', '/shard1']) |
| |
| def test_success_no_overlapping_files_but_matching_contents(self): |
| mock_filesystem = MockFileSystem({'/shard0/file1': '1', '/shard1/file2': '1'}) |
| d = merge_results.DirMerger(mock_filesystem) |
| with self.assertFilesAdded(mock_filesystem, {'/output/file1': '1', '/output/file2': '1'}): |
| d.merge('/output', ['/shard0', '/shard1']) |
| |
| def test_success_same_file_but_matching_contents(self): |
| mock_filesystem = MockFileSystem({'/shard0/file1': '1', '/shard1/file1': '1'}) |
| d = merge_results.DirMerger(mock_filesystem) |
| with self.assertFilesAdded(mock_filesystem, {'/output/file1': '1'}): |
| d.merge('/output', ['/shard0', '/shard1']) |
| |
| def test_failure_same_file_but_contents_differ(self): |
| mock_filesystem = MockFileSystem({'/shard0/file1': '1', '/shard1/file1': '2'}) |
| d = merge_results.DirMerger(mock_filesystem) |
| with self.assertRaises(merge_results.MergeFailure): |
| d.merge('/output', ['/shard0', '/shard1']) |
| |
| |
| class MergeFilesJSONPTests(FileSystemTestCase): |
| |
| def assertLoad(self, fd, expected_before, expected_json, expected_after): |
| before, json_data, after = merge_results.MergeFilesJSONP.load_jsonp(fd) |
| self.assertEqual(expected_before, before) |
| self.assertDictEqual(expected_json, json_data) |
| self.assertEqual(expected_after, after) |
| |
| def assertDump(self, before, json, after, expected_data): |
| fd = StringIO.StringIO() |
| merge_results.MergeFilesJSONP.dump_jsonp(fd, before, json, after) |
| self.assertMultiLineEqual(fd.getvalue(), expected_data) |
| |
| def test_load(self): |
| fdcls = StringIO.StringIO |
| self.assertLoad(fdcls('{"a": 1}'), '', {'a': 1}, '') |
| self.assertLoad(fdcls('f({"a": 1});'), 'f(', {'a': 1}, ');') |
| self.assertLoad(fdcls('var o = {"a": 1}'), 'var o = ', {'a': 1}, '') |
| self.assertLoad(fdcls('while(1); // {"a": 1}'), 'while(1); // ', {'a': 1}, '') |
| self.assertLoad(fdcls('/* {"a": 1} */'), '/* ', {'a': 1}, ' */') |
| |
| def test_dump(self): |
| self.assertDump('', {}, '', '{}') |
| self.assertDump('f(', {}, ');', 'f({});') |
| self.assertDump('var o = ', {}, '', 'var o = {}') |
| self.assertDump('while(1); // ', {}, '', 'while(1); // {}') |
| self.assertDump('/* ', {}, ' */', '/* {} */') |
| |
| self.assertDump('', {'a': 1}, '', """\ |
| { |
| "a": 1 |
| }""") |
| self.assertDump('', {'a': [1, 'c', 3], 'b': 2}, '', """\ |
| { |
| "a": [ |
| 1, |
| "c", |
| 3 |
| ], |
| "b": 2 |
| }""") |
| |
| def assertMergeResults(self, mock_filesystem_contents, inputargs, filesystem_contains, json_data_merger=None): |
| mock_filesystem = MockFileSystem(mock_filesystem_contents, dirs=['/output']) |
| |
| file_merger = merge_results.MergeFilesJSONP(mock_filesystem, json_data_merger) |
| with self.assertFilesAdded(mock_filesystem, filesystem_contains): |
| file_merger(*inputargs) |
| |
| def assertMergeRaises(self, mock_filesystem_contents, inputargs): |
| mock_filesystem = MockFileSystem(mock_filesystem_contents, dirs=['/output']) |
| |
| file_merger = merge_results.MergeFilesJSONP(mock_filesystem) |
| with self.assertRaises(merge_results.MergeFailure): |
| file_merger(*inputargs) |
| |
| def test_single_file(self): |
| self.assertMergeResults( |
| {'/s/filea': '{"a": 1}'}, |
| ('/output/out1', ['/s/filea']), |
| {'/output/out1': """\ |
| { |
| "a": 1 |
| }"""}) |
| |
| self.assertMergeResults( |
| {'/s/filef1a': 'f1({"a": 1})'}, |
| ('/output/outf1', ['/s/filef1a']), |
| {'/output/outf1': """\ |
| f1({ |
| "a": 1 |
| })"""}) |
| |
| self.assertMergeResults( |
| {'/s/fileb1': '{"b": 2}'}, |
| ('/output/out2', ['/s/fileb1']), |
| {'/output/out2': """\ |
| { |
| "b": 2 |
| }"""}) |
| |
| self.assertMergeResults( |
| {'/s/filef1b1': 'f1({"b": 2})'}, |
| ('/output/outf2', ['/s/filef1b1']), |
| {'/output/outf2': """\ |
| f1({ |
| "b": 2 |
| })"""}) |
| |
| def test_two_files_nonconflicting_values(self): |
| self.assertMergeResults( |
| { |
| '/s/filea': '{"a": 1}', |
| '/s/fileb1': '{"b": 2}', |
| }, |
| ('/output/out3', ['/s/filea', '/s/fileb1']), |
| { |
| '/output/out3': """\ |
| { |
| "a": 1, |
| "b": 2 |
| }"""}) |
| |
| self.assertMergeResults( |
| { |
| '/s/filef1a': 'f1({"a": 1})', |
| '/s/filef1b1': 'f1({"b": 2})', |
| }, |
| ('/output/outf3', ['/s/filef1a', '/s/filef1b1']), |
| { |
| '/output/outf3': """\ |
| f1({ |
| "a": 1, |
| "b": 2 |
| })"""}) |
| |
| def test_two_files_identical_values_fails_by_default(self): |
| self.assertMergeRaises( |
| { |
| '/s/fileb1': '{"b": 2}', |
| '/s/fileb2': '{"b": 2}', |
| }, |
| ('/output/out4', ['/s/fileb1', '/s/fileb2'])) |
| |
| self.assertMergeRaises( |
| { |
| '/s/filef1b1': 'f1({"b": 2})', |
| '/s/filef1b2': 'f1({"b": 2})', |
| }, |
| ('/output/outf4', ['/s/filef1b1', '/s/filef1b2'])) |
| |
| def test_two_files_identical_values_works_with_custom_merger(self): |
| json_data_merger = merge_results.JSONMerger() |
| json_data_merger.fallback_matcher = json_data_merger.merge_equal |
| |
| self.assertMergeResults( |
| { |
| '/s/fileb1': '{"b": 2}', |
| '/s/fileb2': '{"b": 2}', |
| }, |
| ('/output/out4', ['/s/fileb1', '/s/fileb2']), |
| { |
| '/output/out4': """\ |
| { |
| "b": 2 |
| }"""}, |
| json_data_merger=json_data_merger) |
| |
| self.assertMergeResults( |
| { |
| '/s/filef1b1': 'f1({"b": 2})', |
| '/s/filef1b2': 'f1({"b": 2})', |
| }, |
| ('/output/outf4', ['/s/filef1b1', '/s/filef1b2']), |
| { |
| '/output/outf4': """\ |
| f1({ |
| "b": 2 |
| })"""}, |
| json_data_merger=json_data_merger) |
| |
| def test_two_files_conflicting_values(self): |
| self.assertMergeRaises( |
| { |
| '/s/fileb1': '{"b": 2}', |
| '/s/fileb3': '{"b": 3}', |
| }, |
| ('/output/outff1', ['/s/fileb1', '/s/fileb3'])) |
| self.assertMergeRaises( |
| { |
| '/s/filef1b1': 'f1({"b": 2})', |
| '/s/filef1b3': 'f1({"b": 3})', |
| }, |
| ('/output/outff2', ['/s/filef1b1', '/s/filef1b3'])) |
| |
| def test_two_files_conflicting_function_names(self): |
| self.assertMergeRaises( |
| { |
| '/s/filef1a': 'f1({"a": 1})', |
| '/s/filef2a': 'f2({"a": 1})', |
| }, |
| ('/output/outff3', ['/s/filef1a', '/s/filef2a'])) |
| |
| def test_two_files_mixed_json_and_jsonp(self): |
| self.assertMergeRaises( |
| { |
| '/s/filea': '{"a": 1}', |
| '/s/filef1a': 'f1({"a": 1})', |
| }, |
| ('/output/outff4', ['/s/filea', '/s/filef1a'])) |
| |
| |
| class JSONTestResultsMerger(unittest.TestCase): |
| |
| def test_allow_unknown_if_matching(self): |
| merger = merge_results.JSONTestResultsMerger(allow_unknown_if_matching=False) |
| self.assertEqual( |
| {'version': 3.0}, |
| merger.merge([{'version': 3.0}, {'version': 3.0}])) |
| |
| with self.assertRaises(merge_results.MergeFailure): |
| merger.merge([{'random': 'hello'}, {'random': 'hello'}]) |
| |
| merger = merge_results.JSONTestResultsMerger(allow_unknown_if_matching=True) |
| self.assertEqual( |
| {'random': 'hello'}, |
| merger.merge([{'random': 'hello'}, {'random': 'hello'}])) |
| |
| def test_summable(self): |
| merger = merge_results.JSONTestResultsMerger() |
| self.assertEqual( |
| {'fixable': 5}, |
| merger.merge([{'fixable': 2}, {'fixable': 3}])) |
| self.assertEqual( |
| {'num_failures_by_type': {'A': 4, 'B': 3, 'C': 2}}, |
| merger.merge([ |
| {'num_failures_by_type': {'A': 3, 'B': 1}}, |
| {'num_failures_by_type': {'A': 1, 'B': 2, 'C': 2}}, |
| ])) |
| |
| def test_interrupted(self): |
| merger = merge_results.JSONTestResultsMerger() |
| self.assertEqual( |
| {'interrupted': False}, |
| merger.merge([{'interrupted': False}, {'interrupted': False}])) |
| self.assertEqual( |
| {'interrupted': True}, |
| merger.merge([{'interrupted': True}, {'interrupted': False}])) |
| self.assertEqual( |
| {'interrupted': True}, |
| merger.merge([{'interrupted': False}, {'interrupted': True}])) |
| |
| def test_seconds_since_epoch(self): |
| merger = merge_results.JSONTestResultsMerger() |
| self.assertEqual( |
| {'seconds_since_epoch': 2}, |
| merger.merge([{'seconds_since_epoch': 3}, {'seconds_since_epoch': 2}])) |
| self.assertEqual( |
| {'seconds_since_epoch': 2}, |
| merger.merge([{'seconds_since_epoch': 2}, {'seconds_since_epoch': 3}])) |
| self.assertEqual( |
| {'seconds_since_epoch': 12}, |
| merger.merge([{'seconds_since_epoch': 12}, {}])) |
| |
| |
| class WebTestDirMergerTests(unittest.TestCase): |
| |
| # JSON files for shard 1 |
| # Shard1 has the following tests; |
| # testdir1/test1.html |
| # testdir1/test2.html |
| # testdir2/testdir2.1/test3.html |
| shard0_output_json = """\ |
| { |
| "build_number": "DUMMY_BUILD_NUMBER", |
| "builder_name": "abc", |
| "chromium_revision": "123", |
| "fixable": 1, |
| "interrupted": false, |
| "layout_tests_dir": "/b/s/w/irJ1McdS/third_party/blink/web_tests", |
| "num_failures_by_type": { |
| "AUDIO": 2, |
| "CRASH": 3 |
| }, |
| "num_flaky": 4, |
| "num_passes": 5, |
| "num_regressions": 6, |
| "path_delimiter": "/", |
| "random_order_seed": 4, |
| "seconds_since_epoch": 1488435717, |
| "skipped": 8, |
| "tests": { |
| "testdir1": { |
| "test1.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": false, |
| "time": 0.3 |
| }, |
| "test2.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": false, |
| "time": 0.3 |
| } |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": false, |
| "time": 0.3 |
| } |
| } |
| } |
| }, |
| "version": 3 |
| }""" |
| |
| shard0_archived_results_json = """\ |
| ADD_RESULTS({ |
| "result_links": [ |
| "results.html" |
| ], |
| "tests": { |
| "testdir1": { |
| "test1.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| }, |
| "test2.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| } |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| } |
| } |
| } |
| } |
| });""" |
| |
| shard0_stats_json = """\ |
| { |
| "testdir1": { |
| "test1.html": { |
| "results": [1, 2, 3, 4, 5] |
| }, |
| "test2.html": { |
| "results": [6, 7, 8, 9, 10] |
| } |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": { |
| "results": [11, 12, 13, 14, 15] |
| } |
| } |
| } |
| } |
| """ |
| shard0_times_ms_json = """{ |
| "testdir1": { |
| "test1.html": 263, |
| "test2.html": 32 |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": 77 |
| } |
| } |
| }""" |
| |
| # Logs for shard 1 |
| shard0_access_log = """\ |
| 127.0.0.1 - - [01/Mar/2017:22:20:10 -0800] "GET /testdir1/test1.html HTTP/1.1" 200 594 |
| 127.0.0.1 - - [01/Mar/2017:22:20:10 -0800] "GET /testdir1/test2.html HTTP/1.1" 200 251 |
| """ |
| shard0_error_log = """\ |
| [Wed Mar 01 22:20:07.392108 2017] [ssl:warn] [pid 15009] AH01909: RSA certificate configured for 127.0.0.1:443 does NOT include an ID which matches the server name |
| """ |
| |
| # JSON files for shard 2 |
| # Shard1 has the following tests; |
| # testdir2/testdir2.1/test4.html |
| # testdir3/testt.html |
| shard1_output_json = """\ |
| { |
| "build_number": "DUMMY_BUILD_NUMBER", |
| "builder_name": "abc", |
| "chromium_revision": "123", |
| "fixable": 9, |
| "interrupted": false, |
| "layout_tests_dir": "/b/s/w/sadfa124/third_party/blink/web_tests", |
| "num_failures_by_type": { |
| "AUDIO": 10, |
| "CRASH": 11 |
| }, |
| "num_flaky": 12, |
| "num_passes": 13, |
| "num_regressions": 14, |
| "path_delimiter": "/", |
| "random_order_seed": 4, |
| "seconds_since_epoch": 1488435717, |
| "skipped": 15, |
| "tests": { |
| "testdir2": { |
| "testdir2.1": { |
| "test4.html": { |
| "actual": "FAIL", |
| "expected": "PASS", |
| "has_stderr": true, |
| "time": 0.3 |
| } |
| } |
| }, |
| "testdir3": { |
| "test5.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": true, |
| "time": 0.3 |
| } |
| } |
| }, |
| "version": 3 |
| }""" |
| |
| shard1_archived_results_json = """\ |
| ADD_RESULTS({ |
| "result_links": [ |
| "results.html" |
| ], |
| "tests": { |
| "testdir2": { |
| "testdir2.1": { |
| "test4.html": { |
| "archived_results": [ |
| "FAIL" |
| ] |
| } |
| } |
| }, |
| "testdir3": { |
| "test5.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| } |
| } |
| } |
| });""" |
| |
| shard1_stats_json = """\ |
| { |
| "testdir2": { |
| "testdir2.1": { |
| "test4.html": { |
| "results": [16, 17, 18, 19, 20] |
| } |
| } |
| }, |
| "testdir3": { |
| "test5.html": { |
| "results": [21, 22, 23, 24, 25] |
| } |
| } |
| } |
| """ |
| shard1_times_ms_json = """{ |
| "testdir2": { |
| "testdir2.1": { |
| "test4.html": 99 |
| } |
| }, |
| "testdir3": { |
| "test5.html": 11 |
| } |
| }""" |
| |
| # Logs for shard 2 |
| shard1_access_log = """\ |
| 127.0.0.1 - - [01/Mar/2017:22:20:10 -0800] "GET /resource.html HTTP/1.1" 200 594 |
| """ |
| shard1_error_log = """\ |
| [Wed Mar 01 22:20:07.400802 2017] [ssl:warn] [pid 15010] AH01909: RSA certificate configured for 127.0.0.1:443 does NOT include an ID which matches the server name |
| """ |
| |
| web_test_filesystem = { |
| # Files for shard0 |
| '/shards/0/layout-test-results/access_log.txt': shard0_access_log, |
| '/shards/0/layout-test-results/archived_results.json': shard0_archived_results_json, |
| '/shards/0/layout-test-results/error_log.txt': shard0_error_log, |
| '/shards/0/layout-test-results/failing_results.json': "ADD_RESULTS(" + shard0_output_json + ");", |
| '/shards/0/layout-test-results/full_results.json': shard0_output_json, |
| '/shards/0/layout-test-results/stats.json': shard0_stats_json, |
| '/shards/0/layout-test-results/testdir1/test1-actual.png': '1ap', |
| '/shards/0/layout-test-results/testdir1/test1-diff.png': '1dp', |
| '/shards/0/layout-test-results/testdir1/test1-diffs.html': '1dh', |
| '/shards/0/layout-test-results/testdir1/test1-expected-stderr.txt': '1est', |
| '/shards/0/layout-test-results/testdir1/test1-expected.png': '1ep', |
| '/shards/0/layout-test-results/testdir1/test2-actual.png': '2ap', |
| '/shards/0/layout-test-results/testdir1/test2-diff.png': '2dp', |
| '/shards/0/layout-test-results/testdir1/test2-diffs.html': '2dh', |
| '/shards/0/layout-test-results/testdir1/test2-expected-stderr.txt': '2est', |
| '/shards/0/layout-test-results/testdir1/test2-expected.png': '2ep', |
| '/shards/0/layout-test-results/testdir2/testdir2.1/test3-actual.png': '3ap', |
| '/shards/0/layout-test-results/testdir2/testdir2.1/test3-diff.png': '3dp', |
| '/shards/0/layout-test-results/testdir2/testdir2.1/test3-diffs.html': '3dh', |
| '/shards/0/layout-test-results/testdir2/testdir2.1/test3-expected-stderr.txt': '3est', |
| '/shards/0/layout-test-results/testdir2/testdir2.1/test3-expected.png': '3ep', |
| '/shards/0/layout-test-results/times_ms.json': shard0_times_ms_json, |
| '/shards/0/output.json': shard0_output_json, |
| # Files for shard1 |
| '/shards/1/layout-test-results/access_log.txt': shard1_access_log, |
| '/shards/1/layout-test-results/archived_results.json': shard1_archived_results_json, |
| '/shards/1/layout-test-results/error_log.txt': shard1_error_log, |
| '/shards/1/layout-test-results/failing_results.json': "ADD_RESULTS(" + shard1_output_json + ");", |
| '/shards/1/layout-test-results/full_results.json': shard1_output_json, |
| '/shards/1/layout-test-results/stats.json': shard1_stats_json, |
| '/shards/1/layout-test-results/testdir2/testdir2.1/test4-actual.png': '4ap', |
| '/shards/1/layout-test-results/testdir2/testdir2.1/test4-diff.png': '4dp', |
| '/shards/1/layout-test-results/testdir2/testdir2.1/test4-diffs.html': '4dh', |
| '/shards/1/layout-test-results/testdir2/testdir2.1/test4-expected-stderr.txt': '4est', |
| '/shards/1/layout-test-results/testdir2/testdir2.1/test4-expected.png': '4ep', |
| '/shards/1/layout-test-results/testdir3/test5-actual.png': '5ap', |
| '/shards/1/layout-test-results/testdir3/test5-diff.png': '5dp', |
| '/shards/1/layout-test-results/testdir3/test5-diffs.html': '5dh', |
| '/shards/1/layout-test-results/testdir3/test5-expected-stderr.txt': '5est', |
| '/shards/1/layout-test-results/testdir3/test5-expected.png': '5ep', |
| '/shards/1/layout-test-results/times_ms.json': shard1_times_ms_json, |
| '/shards/1/output.json': shard1_output_json, |
| } |
| |
| # Combined JSON files |
| output_output_json = """\ |
| { |
| "build_number": "DUMMY_BUILD_NUMBER", |
| "builder_name": "abc", |
| "chromium_revision": "123", |
| "fixable": 10, |
| "interrupted": false, |
| "layout_tests_dir": "src", |
| "num_failures_by_type": { |
| "AUDIO": 12, |
| "CRASH": 14 |
| }, |
| "num_flaky": 16, |
| "num_passes": 18, |
| "num_regressions": 20, |
| "path_delimiter": "/", |
| "random_order_seed": 4, |
| "seconds_since_epoch": 1488435717, |
| "skipped": 23, |
| "tests": { |
| "testdir1": { |
| "test1.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": false, |
| "time": 0.3 |
| }, |
| "test2.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": false, |
| "time": 0.3 |
| } |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": false, |
| "time": 0.3 |
| }, |
| "test4.html": { |
| "actual": "FAIL", |
| "expected": "PASS", |
| "has_stderr": true, |
| "time": 0.3 |
| } |
| } |
| }, |
| "testdir3": { |
| "test5.html": { |
| "actual": "PASS", |
| "expected": "PASS", |
| "has_stderr": true, |
| "time": 0.3 |
| } |
| } |
| }, |
| "version": 3 |
| }""" |
| |
| output_archived_results_json = """\ |
| ADD_RESULTS({ |
| "result_links": [ |
| "results.html", |
| "results.html" |
| ], |
| "tests": { |
| "testdir1": { |
| "test1.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| }, |
| "test2.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| } |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| }, |
| "test4.html": { |
| "archived_results": [ |
| "FAIL" |
| ] |
| } |
| } |
| }, |
| "testdir3": { |
| "test5.html": { |
| "archived_results": [ |
| "PASS" |
| ] |
| } |
| } |
| } |
| });""" |
| |
| output_stats_json = """\ |
| { |
| "testdir1": { |
| "test1.html": { |
| "results": [ |
| 1, |
| 2, |
| 3, |
| 4, |
| 5 |
| ] |
| }, |
| "test2.html": { |
| "results": [ |
| 6, |
| 7, |
| 8, |
| 9, |
| 10 |
| ] |
| } |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": { |
| "results": [ |
| 11, |
| 12, |
| 13, |
| 14, |
| 15 |
| ] |
| }, |
| "test4.html": { |
| "results": [ |
| 16, |
| 17, |
| 18, |
| 19, |
| 20 |
| ] |
| } |
| } |
| }, |
| "testdir3": { |
| "test5.html": { |
| "results": [ |
| 21, |
| 22, |
| 23, |
| 24, |
| 25 |
| ] |
| } |
| } |
| } |
| """ |
| output_times_ms_json = """{ |
| "testdir1": { |
| "test1.html": 263, |
| "test2.html": 32 |
| }, |
| "testdir2": { |
| "testdir2.1": { |
| "test3.html": 77, |
| "test4.html": 99 |
| } |
| }, |
| "testdir3": { |
| "test5.html": 11 |
| } |
| }""" |
| |
| # Combined Logs |
| output_access_log = """\ |
| 127.0.0.1 - - [01/Mar/2017:22:20:10 -0800] "GET /resource.html HTTP/1.1" 200 594 |
| 127.0.0.1 - - [01/Mar/2017:22:20:10 -0800] "GET /testdir1/test1.html HTTP/1.1" 200 594 |
| 127.0.0.1 - - [01/Mar/2017:22:20:10 -0800] "GET /testdir1/test2.html HTTP/1.1" 200 251 |
| """ |
| output_error_log = """\ |
| [Wed Mar 01 22:20:07.392108 2017] [ssl:warn] [pid 15009] AH01909: RSA certificate configured for 127.0.0.1:443 does NOT include an ID which matches the server name |
| [Wed Mar 01 22:20:07.400802 2017] [ssl:warn] [pid 15010] AH01909: RSA certificate configured for 127.0.0.1:443 does NOT include an ID which matches the server name |
| """ |
| |
| web_test_output_filesystem = { |
| '/out/layout-test-results/access_log.txt': output_access_log, |
| '/out/layout-test-results/archived_results.json': output_archived_results_json, |
| '/out/layout-test-results/error_log.txt': output_error_log, |
| '/out/layout-test-results/failing_results.json': "ADD_RESULTS(" + output_output_json + ");", |
| '/out/layout-test-results/full_results.json': output_output_json, |
| '/out/layout-test-results/stats.json': output_stats_json, |
| '/out/layout-test-results/testdir1/test1-actual.png': '1ap', |
| '/out/layout-test-results/testdir1/test1-diff.png': '1dp', |
| '/out/layout-test-results/testdir1/test1-diffs.html': '1dh', |
| '/out/layout-test-results/testdir1/test1-expected-stderr.txt': '1est', |
| '/out/layout-test-results/testdir1/test1-expected.png': '1ep', |
| '/out/layout-test-results/testdir2/testdir2.1/test3-actual.png': '3ap', |
| '/out/layout-test-results/testdir2/testdir2.1/test3-diff.png': '3dp', |
| '/out/layout-test-results/testdir2/testdir2.1/test3-diffs.html': '3dh', |
| '/out/layout-test-results/testdir2/testdir2.1/test3-expected-stderr.txt': '3est', |
| '/out/layout-test-results/testdir2/testdir2.1/test3-expected.png': '3ep', |
| '/out/layout-test-results/testdir2/testdir2.1/test4-actual.png': '4ap', |
| '/out/layout-test-results/testdir2/testdir2.1/test4-diff.png': '4dp', |
| '/out/layout-test-results/testdir2/testdir2.1/test4-diffs.html': '4dh', |
| '/out/layout-test-results/testdir2/testdir2.1/test4-expected-stderr.txt': '4est', |
| '/out/layout-test-results/testdir2/testdir2.1/test4-expected.png': '4ep', |
| '/out/layout-test-results/testdir3/test5-actual.png': '5ap', |
| '/out/layout-test-results/testdir3/test5-diff.png': '5dp', |
| '/out/layout-test-results/testdir3/test5-diffs.html': '5dh', |
| '/out/layout-test-results/testdir3/test5-expected-stderr.txt': '5est', |
| '/out/layout-test-results/testdir3/test5-expected.png': '5ep', |
| '/out/layout-test-results/times_ms.json': output_times_ms_json, |
| '/out/output.json': output_output_json, |
| } |
| |
| def test(self): |
| fs = MockFileSystem(self.web_test_filesystem) |
| |
| merger = merge_results.WebTestDirMerger(fs, results_json_value_overrides={'layout_tests_dir': 'src'}) |
| merger.merge('/out', ['/shards/0', '/shards/1']) |
| |
| for fname, contents in self.web_test_output_filesystem.items(): |
| self.assertIn(fname, fs.files) |
| self.assertMultiLineEqual(contents, fs.files[fname]) |