| # Lint as: python2, python3 |
| # pylint: disable=g-direct-third-party-import |
| # Copyright 2018 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import os |
| import unittest |
| # Do not edit this line. Copybara replaces it with PY2 migration helper. |
| from third_party.py import mock |
| import six |
| from src.main.protobuf import analysis_v2_pb2 |
| from tools.aquery_differ import aquery_differ |
| |
| # pylint: disable=g-import-not-at-top |
| if six.PY2: |
| from cStringIO import StringIO |
| else: |
| from io import StringIO |
| # pylint: enable=g-import-not-at-top |
| |
| |
| def make_aquery_output(action_objs, artifact_objs, path_fragment_objs): |
| action_graph = analysis_v2_pb2.ActionGraphContainer() |
| |
| for path_fragment_obj in path_fragment_objs: |
| path_fragment = action_graph.path_fragments.add() |
| path_fragment.id = path_fragment_obj["id"] |
| path_fragment.label = path_fragment_obj["label"] |
| if "parent_id" in path_fragment_obj: |
| path_fragment.parent_id = path_fragment_obj["parent_id"] |
| |
| for artifact_obj in artifact_objs: |
| artifact = action_graph.artifacts.add() |
| artifact.id = artifact_obj["id"] |
| artifact.path_fragment_id = artifact_obj["path_fragment_id"] |
| |
| for action_obj in action_objs: |
| action = action_graph.actions.add() |
| action.output_ids.extend(action_obj["output_ids"]) |
| action.arguments.extend(action_obj["arguments"]) |
| |
| if "input_dep_set_ids" in action_obj: |
| action.input_dep_set_ids.extend(action_obj["input_dep_set_ids"]) |
| |
| return action_graph |
| |
| |
| def make_aquery_output_with_dep_set(action_objs, artifact_objs, |
| path_fragment_objs, dep_set_objs): |
| action_graph = make_aquery_output(action_objs, artifact_objs, |
| path_fragment_objs) |
| |
| for ds in dep_set_objs: |
| dep_set = action_graph.dep_set_of_files.add() |
| dep_set.id = ds["id"] |
| dep_set.direct_artifact_ids.extend(ds["direct_artifact_ids"]) |
| dep_set.transitive_dep_set_ids.extend(ds["transitive_dep_set_ids"]) |
| |
| return action_graph |
| |
| |
| class CmdLineDifferTest(unittest.TestCase): |
| |
| def test_no_difference(self): |
| action_graph = make_aquery_output( |
| action_objs=[ |
| { |
| "arguments": ["-a", "-b"], |
| "output_ids": [1, 2] |
| }, |
| { |
| "arguments": ["-c"], |
| "output_ids": [3] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }, { |
| "id": 3, |
| "path_fragment_id": 4 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| { |
| "id": 4, |
| "label": "baz", |
| "parent_id": 1 |
| }, |
| ]) |
| mock_stdout = StringIO() |
| attrs = ["cmdline"] |
| with mock.patch("sys.stdout", mock_stdout): |
| aquery_differ._aquery_diff(action_graph, action_graph, attrs, "before", |
| "after") |
| self.assertEqual(mock_stdout.getvalue(), "No difference\n") |
| |
| def test_no_difference_different_output_files_order(self): |
| first = make_aquery_output( |
| action_objs=[ |
| { |
| "arguments": ["-a", "-b"], |
| "output_ids": [1, 2] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| ]) |
| |
| second = make_aquery_output( |
| action_objs=[ |
| { |
| "arguments": ["-a", "-b"], |
| "output_ids": [2, 1] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| ]) |
| |
| mock_stdout = StringIO() |
| attrs = ["cmdline"] |
| with mock.patch("sys.stdout", mock_stdout): |
| aquery_differ._aquery_diff(first, second, attrs, "before", "after") |
| self.assertEqual(mock_stdout.getvalue(), "No difference\n") |
| |
| def test_first_has_extra_output_files(self): |
| first = make_aquery_output( |
| action_objs=[ |
| { |
| "arguments": ["-a", "-b"], |
| "output_ids": [1, 2] |
| }, |
| { |
| "arguments": ["-c"], |
| "output_ids": [3] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }, { |
| "id": 3, |
| "path_fragment_id": 4 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| { |
| "id": 4, |
| "label": "baz", |
| "parent_id": 1 |
| }, |
| ]) |
| second = make_aquery_output( |
| action_objs=[ |
| { |
| "arguments": ["-a", "-b"], |
| "output_ids": [1, 2] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }], |
| path_fragment_objs=[{ |
| "id": 1, |
| "label": "root" |
| }, { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }]) |
| |
| baz_path = os.path.join("root", "baz") |
| expected_error = ("Aquery output 'before' change contains an action " |
| "that generates the following outputs that aquery " |
| "output 'after' change doesn't:\n{}\n\n".format(baz_path)) |
| mock_stdout = StringIO() |
| attrs = ["cmdline"] |
| with mock.patch("sys.stdout", mock_stdout): |
| aquery_differ._aquery_diff(first, second, attrs, "before", "after") |
| self.assertEqual(mock_stdout.getvalue(), expected_error) |
| |
| def test_different_command_lines(self): |
| first = make_aquery_output( |
| action_objs=[ |
| { |
| "arguments": ["-a", "-d"], |
| "output_ids": [1, 2] |
| }, |
| { |
| "arguments": ["-c"], |
| "output_ids": [3] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }, { |
| "id": 3, |
| "path_fragment_id": 4 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| { |
| "id": 4, |
| "label": "baz", |
| "parent_id": 1 |
| }, |
| ]) |
| second = make_aquery_output( |
| action_objs=[ |
| { |
| "arguments": ["-a", "-b"], |
| "output_ids": [1, 2] |
| }, |
| { |
| "arguments": ["-c", "-d"], |
| "output_ids": [3] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }, { |
| "id": 3, |
| "path_fragment_id": 4 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| { |
| "id": 4, |
| "label": "baz", |
| "parent_id": 1 |
| }, |
| ]) |
| |
| foo_path = os.path.join("root", "foo") |
| bar_path = os.path.join("root", "bar") |
| baz_path = os.path.join("root", "baz") |
| |
| expected_error_one = "\n".join([ |
| "Difference in the action that generates the following output(s):", |
| "\t{}".format(baz_path), "--- before", "+++ after", "@@ -1 +1,2 @@", |
| " -c", "+-d", "\n" |
| ]) |
| expected_error_two = "\n".join([ |
| "Difference in the action that generates the following output(s):", |
| "\t{}".format(bar_path), "\t{}".format(foo_path), "--- before", |
| "+++ after", "@@ -1,2 +1,2 @@", " -a", "--d", "+-b", "\n" |
| ]) |
| attrs = ["cmdline"] |
| |
| mock_stdout = StringIO() |
| with mock.patch("sys.stdout", mock_stdout): |
| aquery_differ._aquery_diff(first, second, attrs, "before", "after") |
| self.assertIn(expected_error_one, mock_stdout.getvalue()) |
| self.assertIn(expected_error_two, mock_stdout.getvalue()) |
| |
| def test_different_inputs(self): |
| first = make_aquery_output_with_dep_set( |
| action_objs=[{ |
| "arguments": [], |
| "output_ids": [1, 2], |
| "input_dep_set_ids": [2] |
| }], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| ], |
| dep_set_objs=[{ |
| "id": 1, |
| "transitive_dep_set_ids": [], |
| "direct_artifact_ids": [1] |
| }, { |
| "id": 2, |
| "transitive_dep_set_ids": [1], |
| "direct_artifact_ids": [2] |
| }]) |
| second = make_aquery_output_with_dep_set( |
| action_objs=[ |
| { |
| "arguments": [], |
| "output_ids": [1, 2], |
| "input_dep_set_ids": [1] |
| }, |
| ], |
| artifact_objs=[{ |
| "id": 1, |
| "path_fragment_id": 2 |
| }, { |
| "id": 2, |
| "path_fragment_id": 3 |
| }], |
| path_fragment_objs=[ |
| { |
| "id": 1, |
| "label": "root" |
| }, |
| { |
| "id": 2, |
| "label": "foo", |
| "parent_id": 1 |
| }, |
| { |
| "id": 3, |
| "label": "bar", |
| "parent_id": 1 |
| }, |
| ], |
| dep_set_objs=[{ |
| "id": 1, |
| "transitive_dep_set_ids": [], |
| "direct_artifact_ids": [1] |
| }]) |
| |
| foo_path = os.path.join("root", "foo") |
| bar_path = os.path.join("root", "bar") |
| expected_error_one = "\n".join([ |
| "Difference in the action that generates the following output(s):", |
| "\t{}".format(bar_path), "\t{}".format(foo_path), "--- before", |
| "+++ after", "@@ -1,2 +1 @@", "-{}".format(bar_path), |
| " {}".format(foo_path), "\n" |
| ]) |
| attrs = ["inputs"] |
| |
| mock_stdout = StringIO() |
| with mock.patch("sys.stdout", mock_stdout): |
| aquery_differ._aquery_diff(first, second, attrs, "before", "after") |
| self.assertIn(expected_error_one, mock_stdout.getvalue()) |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |