#!/usr/bin/env python3 # # Copyright (C) 2021 The Android Open Source Project # # 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. """Tests for bp2build-progress.""" import bp2build_progress import collections import dependency_analysis import queryview_xml import soong_module_json import unittest import unittest.mock _queryview_graph = queryview_xml.make_graph([ queryview_xml.make_module( '//pkg:a', 'a', 'type1', dep_names=['//pkg:b', '//other:c']), queryview_xml.make_module('//pkg:b', 'b', 'type2', dep_names=['//pkg:d']), queryview_xml.make_module('//pkg:d', 'd', 'type2'), queryview_xml.make_module( '//other:c', 'c', 'type2', dep_names=['//other:e']), queryview_xml.make_module('//other:e', 'e', 'type3'), queryview_xml.make_module('//pkg2:f', 'f', 'type4'), queryview_xml.make_module('//pkg3:g', 'g', 'type5'), ]) _soong_module_graph = [ soong_module_json.make_module( 'a', 'type1', blueprint='pkg/Android.bp', deps=[soong_module_json.make_dep('b'), soong_module_json.make_dep('c')]), soong_module_json.make_module( 'b', 'type2', blueprint='pkg/Android.bp', deps=[soong_module_json.make_dep('d')]), soong_module_json.make_module('d', 'type2', blueprint='pkg/Android.bp'), soong_module_json.make_module( 'c', 'type2', blueprint='other/Android.bp', deps=[soong_module_json.make_dep('e')]), soong_module_json.make_module('e', 'type3', blueprint='other/Android.bp'), soong_module_json.make_module('f', 'type4', blueprint='pkg2/Android.bp'), soong_module_json.make_module('g', 'type5', blueprint='pkg3/Android.bp'), ] _soong_module_graph_created_by_no_loop = [ soong_module_json.make_module( 'a', 'type1', blueprint='pkg/Android.bp', created_by='b'), soong_module_json.make_module('b', 'type2', blueprint='pkg/Android.bp'), ] _soong_module_graph_created_by_loop = [ soong_module_json.make_module( 'a', 'type1', deps=[soong_module_json.make_dep('b')], blueprint='pkg/Android.bp'), soong_module_json.make_module( 'b', 'type2', blueprint='pkg/Android.bp', created_by='a'), ] class Bp2BuildProgressTest(unittest.TestCase): @unittest.mock.patch( 'dependency_analysis.get_queryview_module_info', autospec=True, return_value=_queryview_graph) def test_get_module_adjacency_list_queryview_transitive_deps(self, _): adjacency_dict = bp2build_progress.get_module_adjacency_list( ['a', 'f'], True, set(), False, True, False ) a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) c = bp2build_progress.ModuleInfo( name='c', kind='type2', dirname='other', num_deps=1, created_by=None) d = bp2build_progress.ModuleInfo( name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) e = bp2build_progress.ModuleInfo( name='e', kind='type3', dirname='other', num_deps=0, created_by=None) f = bp2build_progress.ModuleInfo( name='f', kind='type4', dirname='pkg2', num_deps=0, created_by=None) expected_adjacency_dict = collections.defaultdict(set) expected_adjacency_dict[a] = set([b, c, d, e]) expected_adjacency_dict[b] = set([d]) expected_adjacency_dict[c] = set([e]) expected_adjacency_dict[d].update(set()) expected_adjacency_dict[e].update(set()) expected_adjacency_dict[f].update(set()) self.assertDictEqual(adjacency_dict, expected_adjacency_dict) @unittest.mock.patch( 'dependency_analysis.get_queryview_module_info', autospec=True, return_value=_queryview_graph) def test_get_module_adjacency_list_queryview_direct_deps(self, _): adjacency_dict = bp2build_progress.get_module_adjacency_list( ['a', 'f'], True, set(), False, False ) a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) c = bp2build_progress.ModuleInfo( name='c', kind='type2', dirname='other', num_deps=1, created_by=None) d = bp2build_progress.ModuleInfo( name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) e = bp2build_progress.ModuleInfo( name='e', kind='type3', dirname='other', num_deps=0, created_by=None) f = bp2build_progress.ModuleInfo( name='f', kind='type4', dirname='pkg2', num_deps=0, created_by=None) expected_adjacency_dict = collections.defaultdict(set) expected_adjacency_dict[a] = set([b, c]) expected_adjacency_dict[b] = set([d]) expected_adjacency_dict[c] = set([e]) expected_adjacency_dict[d].update(set()) expected_adjacency_dict[e].update(set()) expected_adjacency_dict[f].update(set()) self.assertDictEqual(adjacency_dict, expected_adjacency_dict) @unittest.mock.patch( 'dependency_analysis.get_json_module_info', autospec=True, return_value=_soong_module_graph) def test_get_module_adjacency_list_soong_module_transitive_deps(self, _): adjacency_dict = bp2build_progress.get_module_adjacency_list( ['a', 'f'], False, set(), False, True, False ) a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=2, created_by='') b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by='') c = bp2build_progress.ModuleInfo( name='c', kind='type2', dirname='other', num_deps=1, created_by='') d = bp2build_progress.ModuleInfo( name='d', kind='type2', dirname='pkg', num_deps=0, created_by='') e = bp2build_progress.ModuleInfo( name='e', kind='type3', dirname='other', num_deps=0, created_by='') f = bp2build_progress.ModuleInfo( name='f', kind='type4', dirname='pkg2', num_deps=0, created_by='') expected_adjacency_dict = collections.defaultdict(set) expected_adjacency_dict[a] = set([b, c, d, e]) expected_adjacency_dict[b] = set([d]) expected_adjacency_dict[c] = set([e]) expected_adjacency_dict[d].update(set()) expected_adjacency_dict[e].update(set()) expected_adjacency_dict[f].update(set()) self.assertDictEqual(adjacency_dict, expected_adjacency_dict) @unittest.mock.patch( 'dependency_analysis.get_json_module_info', autospec=True, return_value=_soong_module_graph) def test_get_module_adjacency_list_soong_module_direct_deps(self, _): adjacency_dict = bp2build_progress.get_module_adjacency_list(['a', 'f'], False, set(), False, False) a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=2, created_by='') b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by='') c = bp2build_progress.ModuleInfo( name='c', kind='type2', dirname='other', num_deps=1, created_by='') d = bp2build_progress.ModuleInfo( name='d', kind='type2', dirname='pkg', num_deps=0, created_by='') e = bp2build_progress.ModuleInfo( name='e', kind='type3', dirname='other', num_deps=0, created_by='') f = bp2build_progress.ModuleInfo( name='f', kind='type4', dirname='pkg2', num_deps=0, created_by='') expected_adjacency_dict = collections.defaultdict(set) expected_adjacency_dict[a] = set([b, c]) expected_adjacency_dict[b] = set([d]) expected_adjacency_dict[c] = set([e]) expected_adjacency_dict[d].update(set()) expected_adjacency_dict[e].update(set()) expected_adjacency_dict[f].update(set()) self.assertDictEqual(adjacency_dict, expected_adjacency_dict) @unittest.mock.patch( 'dependency_analysis.get_json_module_info', autospec=True, return_value=_soong_module_graph_created_by_no_loop) def test_get_module_adjacency_list_soong_module_created_by(self, _): adjacency_dict = bp2build_progress.get_module_adjacency_list(['a', 'f'], False, set(), True, False) a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=1, created_by='b') b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=0, created_by='') expected_adjacency_dict = collections.defaultdict(set) expected_adjacency_dict[a].update(set([b])) expected_adjacency_dict[b].update(set()) self.assertDictEqual(adjacency_dict, expected_adjacency_dict) @unittest.mock.patch( 'dependency_analysis.get_json_module_info', autospec=True, return_value=_soong_module_graph_created_by_loop) def test_get_module_adjacency_list_soong_module_created_by_loop(self, _): adjacency_dict = bp2build_progress.get_module_adjacency_list(['a', 'f'], False, set(), True, False) a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=1, created_by='') b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by='a') expected_adjacency_dict = collections.defaultdict(set) expected_adjacency_dict[a].update(set([b])) expected_adjacency_dict[b].update(set()) self.assertDictEqual(adjacency_dict, expected_adjacency_dict) def test_generate_report_data(self): a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=4, created_by=None) b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) c = bp2build_progress.ModuleInfo( name='c', kind='type2', dirname='other', num_deps=1, created_by=None) d = bp2build_progress.ModuleInfo( name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) e = bp2build_progress.ModuleInfo( name='e', kind='type3', dirname='other', num_deps=0, created_by=None) f = bp2build_progress.ModuleInfo( name='f', kind='type4', dirname='pkg2', num_deps=2, created_by=None) g = bp2build_progress.ModuleInfo( name='g', kind='type4', dirname='pkg2', num_deps=2, created_by=None) module_graph = collections.defaultdict(set) module_graph[a] = set([b, c, d, e]) module_graph[b] = set([d]) module_graph[c] = set([e]) module_graph[d].update(set()) module_graph[e].update(set()) module_graph[f].update(set([b, g])) module_graph[g].update(set()) report_data = bp2build_progress.generate_report_data( module_graph, {'d', 'e', 'g'}, {'a', 'f'}) all_unconverted_modules = collections.defaultdict(set) all_unconverted_modules['b'].update({a, f}) all_unconverted_modules['c'].update({a}) blocked_modules = collections.defaultdict(set) blocked_modules[a].update({'b', 'c'}) blocked_modules[b].update(set()) blocked_modules[c].update(set()) blocked_modules[f].update(set({'b'})) expected_report_data = bp2build_progress.ReportData( input_modules={ bp2build_progress.InputModule(a, 4, 2), bp2build_progress.InputModule(f, 2, 1) }, total_deps={b, c, d, e, g}, unconverted_deps={'b', 'c'}, all_unconverted_modules=all_unconverted_modules, blocked_modules=blocked_modules, dirs_with_unconverted_modules={'pkg', 'other', 'pkg2'}, kind_of_unconverted_modules={'type1', 'type2', 'type4'}, converted={'d', 'e', 'g'}, show_converted=False, ) self.assertEqual(report_data, expected_report_data) def test_generate_report_data_show_converted(self): a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg2', num_deps=0, created_by=None, converted=True) c = bp2build_progress.ModuleInfo( name='c', kind='type3', dirname='other', num_deps=0, created_by=None) module_graph = collections.defaultdict(set) module_graph[a] = set([b, c]) module_graph[b].update(set()) module_graph[c].update(set()) report_data = bp2build_progress.generate_report_data( module_graph, {'b'}, {'a'}, show_converted=True) all_unconverted_modules = collections.defaultdict(set) all_unconverted_modules['c'].update({a}) blocked_modules = collections.defaultdict(set) blocked_modules[a].update({'b (c)', 'c'}) blocked_modules[b].update(set()) blocked_modules[c].update(set()) expected_report_data = bp2build_progress.ReportData( input_modules={ bp2build_progress.InputModule(a, 2, 1), }, total_deps={b, c}, unconverted_deps={'c'}, all_unconverted_modules=all_unconverted_modules, blocked_modules=blocked_modules, dirs_with_unconverted_modules={'pkg', 'other'}, kind_of_unconverted_modules={'type1', 'type3'}, converted={'b'}, show_converted=True, ) self.assertEqual(report_data, expected_report_data) def test_generate_dot_file(self): self.maxDiff = None a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) c = bp2build_progress.ModuleInfo( name='c', kind='type2', dirname='other', num_deps=1, created_by=None) d = bp2build_progress.ModuleInfo( name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) e = bp2build_progress.ModuleInfo( name='e', kind='type2', dirname='other', num_deps=0, created_by=None) module_graph = collections.defaultdict(set) module_graph[a] = set([b, c]) module_graph[b] = set([d]) module_graph[c] = set([e]) module_graph[d] = set([]) module_graph[e] = set([]) dot_graph = bp2build_progress.generate_dot_file(module_graph, {'e'}, False) expected_dot_graph = """ digraph mygraph {{ node [shape=box]; "a" [label="a\\ntype1" color=black, style=filled, fillcolor=tomato] "a" -> "b" "a" -> "c" "b" [label="b\\ntype2" color=black, style=filled, fillcolor=tomato] "b" -> "d" "c" [label="c\\ntype2" color=black, style=filled, fillcolor=yellow] "d" [label="d\\ntype2" color=black, style=filled, fillcolor=yellow] }} """ self.assertEqual(dot_graph, expected_dot_graph) def test_generate_dot_file_show_converted(self): self.maxDiff = None a = bp2build_progress.ModuleInfo( name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) b = bp2build_progress.ModuleInfo( name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) c = bp2build_progress.ModuleInfo( name='c', kind='type2', dirname='other', num_deps=1, created_by=None) d = bp2build_progress.ModuleInfo( name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) e = bp2build_progress.ModuleInfo( name='e', kind='type2', dirname='other', num_deps=0, created_by=None) module_graph = collections.defaultdict(set) module_graph[a] = set([b, c]) module_graph[b] = set([d]) module_graph[c] = set([e]) module_graph[d] = set([]) module_graph[e] = set([]) dot_graph = bp2build_progress.generate_dot_file(module_graph, {'e'}, True) expected_dot_graph = """ digraph mygraph {{ node [shape=box]; "a" [label="a\\ntype1" color=black, style=filled, fillcolor=tomato] "a" -> "b" "a" -> "c" "b" [label="b\\ntype2" color=black, style=filled, fillcolor=tomato] "b" -> "d" "c" [label="c\\ntype2" color=black, style=filled, fillcolor=yellow] "c" -> "e" "d" [label="d\\ntype2" color=black, style=filled, fillcolor=yellow] "e" [label="e\\ntype2" color=black, style=filled, fillcolor=dodgerblue] }} """ self.assertEqual(dot_graph, expected_dot_graph) if __name__ == '__main__': unittest.main()