1#!/usr/bin/env python3 2# 3# Copyright (C) 2021 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16"""Tests for bp2build-progress.""" 17 18import bp2build_progress 19import collections 20import dependency_analysis 21import queryview_xml 22import soong_module_json 23import unittest 24import unittest.mock 25 26_queryview_graph = queryview_xml.make_graph([ 27 queryview_xml.make_module( 28 '//pkg:a', 'a', 'type1', dep_names=['//pkg:b', '//other:c']), 29 queryview_xml.make_module('//pkg:b', 'b', 'type2', dep_names=['//pkg:d']), 30 queryview_xml.make_module('//pkg:d', 'd', 'type2'), 31 queryview_xml.make_module( 32 '//other:c', 'c', 'type2', dep_names=['//other:e']), 33 queryview_xml.make_module('//other:e', 'e', 'type3'), 34 queryview_xml.make_module('//pkg2:f', 'f', 'type4'), 35 queryview_xml.make_module('//pkg3:g', 'g', 'type5'), 36]) 37 38_soong_module_graph = [ 39 soong_module_json.make_module( 40 'a', 41 'type1', 42 blueprint='pkg/Android.bp', 43 deps=[soong_module_json.make_dep('b'), 44 soong_module_json.make_dep('c')]), 45 soong_module_json.make_module( 46 'b', 47 'type2', 48 blueprint='pkg/Android.bp', 49 deps=[soong_module_json.make_dep('d')]), 50 soong_module_json.make_module('d', 'type2', blueprint='pkg/Android.bp'), 51 soong_module_json.make_module( 52 'c', 53 'type2', 54 blueprint='other/Android.bp', 55 deps=[soong_module_json.make_dep('e')]), 56 soong_module_json.make_module('e', 'type3', blueprint='other/Android.bp'), 57 soong_module_json.make_module('f', 'type4', blueprint='pkg2/Android.bp'), 58 soong_module_json.make_module('g', 'type5', blueprint='pkg3/Android.bp'), 59] 60 61_soong_module_graph_created_by_no_loop = [ 62 soong_module_json.make_module( 63 'a', 'type1', blueprint='pkg/Android.bp', created_by='b'), 64 soong_module_json.make_module('b', 'type2', blueprint='pkg/Android.bp'), 65] 66 67_soong_module_graph_created_by_loop = [ 68 soong_module_json.make_module( 69 'a', 70 'type1', 71 deps=[soong_module_json.make_dep('b')], 72 blueprint='pkg/Android.bp'), 73 soong_module_json.make_module( 74 'b', 'type2', blueprint='pkg/Android.bp', created_by='a'), 75] 76 77 78class Bp2BuildProgressTest(unittest.TestCase): 79 80 @unittest.mock.patch( 81 'dependency_analysis.get_queryview_module_info', 82 autospec=True, 83 return_value=_queryview_graph) 84 def test_get_module_adjacency_list_queryview_transitive_deps(self, _): 85 adjacency_dict = bp2build_progress.get_module_adjacency_list( 86 ['a', 'f'], True, set(), False, True, False 87 ) 88 89 a = bp2build_progress.ModuleInfo( 90 name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) 91 b = bp2build_progress.ModuleInfo( 92 name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) 93 c = bp2build_progress.ModuleInfo( 94 name='c', kind='type2', dirname='other', num_deps=1, created_by=None) 95 d = bp2build_progress.ModuleInfo( 96 name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) 97 e = bp2build_progress.ModuleInfo( 98 name='e', kind='type3', dirname='other', num_deps=0, created_by=None) 99 f = bp2build_progress.ModuleInfo( 100 name='f', kind='type4', dirname='pkg2', num_deps=0, created_by=None) 101 expected_adjacency_dict = collections.defaultdict(set) 102 expected_adjacency_dict[a] = set([b, c, d, e]) 103 expected_adjacency_dict[b] = set([d]) 104 expected_adjacency_dict[c] = set([e]) 105 expected_adjacency_dict[d].update(set()) 106 expected_adjacency_dict[e].update(set()) 107 expected_adjacency_dict[f].update(set()) 108 self.assertDictEqual(adjacency_dict, expected_adjacency_dict) 109 110 @unittest.mock.patch( 111 'dependency_analysis.get_queryview_module_info', 112 autospec=True, 113 return_value=_queryview_graph) 114 def test_get_module_adjacency_list_queryview_direct_deps(self, _): 115 adjacency_dict = bp2build_progress.get_module_adjacency_list( 116 ['a', 'f'], True, set(), False, False 117 ) 118 119 a = bp2build_progress.ModuleInfo( 120 name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) 121 b = bp2build_progress.ModuleInfo( 122 name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) 123 c = bp2build_progress.ModuleInfo( 124 name='c', kind='type2', dirname='other', num_deps=1, created_by=None) 125 d = bp2build_progress.ModuleInfo( 126 name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) 127 e = bp2build_progress.ModuleInfo( 128 name='e', kind='type3', dirname='other', num_deps=0, created_by=None) 129 f = bp2build_progress.ModuleInfo( 130 name='f', kind='type4', dirname='pkg2', num_deps=0, created_by=None) 131 132 expected_adjacency_dict = collections.defaultdict(set) 133 expected_adjacency_dict[a] = set([b, c]) 134 expected_adjacency_dict[b] = set([d]) 135 expected_adjacency_dict[c] = set([e]) 136 expected_adjacency_dict[d].update(set()) 137 expected_adjacency_dict[e].update(set()) 138 expected_adjacency_dict[f].update(set()) 139 self.assertDictEqual(adjacency_dict, expected_adjacency_dict) 140 141 @unittest.mock.patch( 142 'dependency_analysis.get_json_module_info', 143 autospec=True, 144 return_value=_soong_module_graph) 145 def test_get_module_adjacency_list_soong_module_transitive_deps(self, _): 146 adjacency_dict = bp2build_progress.get_module_adjacency_list( 147 ['a', 'f'], False, set(), False, True, False 148 ) 149 150 a = bp2build_progress.ModuleInfo( 151 name='a', kind='type1', dirname='pkg', num_deps=2, created_by='') 152 b = bp2build_progress.ModuleInfo( 153 name='b', kind='type2', dirname='pkg', num_deps=1, created_by='') 154 c = bp2build_progress.ModuleInfo( 155 name='c', kind='type2', dirname='other', num_deps=1, created_by='') 156 d = bp2build_progress.ModuleInfo( 157 name='d', kind='type2', dirname='pkg', num_deps=0, created_by='') 158 e = bp2build_progress.ModuleInfo( 159 name='e', kind='type3', dirname='other', num_deps=0, created_by='') 160 f = bp2build_progress.ModuleInfo( 161 name='f', kind='type4', dirname='pkg2', num_deps=0, created_by='') 162 163 expected_adjacency_dict = collections.defaultdict(set) 164 expected_adjacency_dict[a] = set([b, c, d, e]) 165 expected_adjacency_dict[b] = set([d]) 166 expected_adjacency_dict[c] = set([e]) 167 expected_adjacency_dict[d].update(set()) 168 expected_adjacency_dict[e].update(set()) 169 expected_adjacency_dict[f].update(set()) 170 self.assertDictEqual(adjacency_dict, expected_adjacency_dict) 171 172 @unittest.mock.patch( 173 'dependency_analysis.get_json_module_info', 174 autospec=True, 175 return_value=_soong_module_graph) 176 def test_get_module_adjacency_list_soong_module_direct_deps(self, _): 177 adjacency_dict = bp2build_progress.get_module_adjacency_list(['a', 'f'], 178 False, set(), 179 False, False) 180 181 a = bp2build_progress.ModuleInfo( 182 name='a', kind='type1', dirname='pkg', num_deps=2, created_by='') 183 b = bp2build_progress.ModuleInfo( 184 name='b', kind='type2', dirname='pkg', num_deps=1, created_by='') 185 c = bp2build_progress.ModuleInfo( 186 name='c', kind='type2', dirname='other', num_deps=1, created_by='') 187 d = bp2build_progress.ModuleInfo( 188 name='d', kind='type2', dirname='pkg', num_deps=0, created_by='') 189 e = bp2build_progress.ModuleInfo( 190 name='e', kind='type3', dirname='other', num_deps=0, created_by='') 191 f = bp2build_progress.ModuleInfo( 192 name='f', kind='type4', dirname='pkg2', num_deps=0, created_by='') 193 194 expected_adjacency_dict = collections.defaultdict(set) 195 expected_adjacency_dict[a] = set([b, c]) 196 expected_adjacency_dict[b] = set([d]) 197 expected_adjacency_dict[c] = set([e]) 198 expected_adjacency_dict[d].update(set()) 199 expected_adjacency_dict[e].update(set()) 200 expected_adjacency_dict[f].update(set()) 201 self.assertDictEqual(adjacency_dict, expected_adjacency_dict) 202 203 @unittest.mock.patch( 204 'dependency_analysis.get_json_module_info', 205 autospec=True, 206 return_value=_soong_module_graph_created_by_no_loop) 207 def test_get_module_adjacency_list_soong_module_created_by(self, _): 208 adjacency_dict = bp2build_progress.get_module_adjacency_list(['a', 'f'], 209 False, set(), 210 True, False) 211 212 a = bp2build_progress.ModuleInfo( 213 name='a', kind='type1', dirname='pkg', num_deps=1, created_by='b') 214 b = bp2build_progress.ModuleInfo( 215 name='b', kind='type2', dirname='pkg', num_deps=0, created_by='') 216 217 expected_adjacency_dict = collections.defaultdict(set) 218 expected_adjacency_dict[a].update(set([b])) 219 expected_adjacency_dict[b].update(set()) 220 self.assertDictEqual(adjacency_dict, expected_adjacency_dict) 221 222 @unittest.mock.patch( 223 'dependency_analysis.get_json_module_info', 224 autospec=True, 225 return_value=_soong_module_graph_created_by_loop) 226 def test_get_module_adjacency_list_soong_module_created_by_loop(self, _): 227 adjacency_dict = bp2build_progress.get_module_adjacency_list(['a', 'f'], 228 False, set(), 229 True, False) 230 231 a = bp2build_progress.ModuleInfo( 232 name='a', kind='type1', dirname='pkg', num_deps=1, created_by='') 233 b = bp2build_progress.ModuleInfo( 234 name='b', kind='type2', dirname='pkg', num_deps=1, created_by='a') 235 236 expected_adjacency_dict = collections.defaultdict(set) 237 expected_adjacency_dict[a].update(set([b])) 238 expected_adjacency_dict[b].update(set()) 239 self.assertDictEqual(adjacency_dict, expected_adjacency_dict) 240 241 def test_generate_report_data(self): 242 a = bp2build_progress.ModuleInfo( 243 name='a', kind='type1', dirname='pkg', num_deps=4, created_by=None) 244 b = bp2build_progress.ModuleInfo( 245 name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) 246 c = bp2build_progress.ModuleInfo( 247 name='c', kind='type2', dirname='other', num_deps=1, created_by=None) 248 d = bp2build_progress.ModuleInfo( 249 name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) 250 e = bp2build_progress.ModuleInfo( 251 name='e', kind='type3', dirname='other', num_deps=0, created_by=None) 252 f = bp2build_progress.ModuleInfo( 253 name='f', kind='type4', dirname='pkg2', num_deps=2, created_by=None) 254 g = bp2build_progress.ModuleInfo( 255 name='g', kind='type4', dirname='pkg2', num_deps=2, created_by=None) 256 257 module_graph = collections.defaultdict(set) 258 module_graph[a] = set([b, c, d, e]) 259 module_graph[b] = set([d]) 260 module_graph[c] = set([e]) 261 module_graph[d].update(set()) 262 module_graph[e].update(set()) 263 module_graph[f].update(set([b, g])) 264 module_graph[g].update(set()) 265 266 report_data = bp2build_progress.generate_report_data( 267 module_graph, {'d', 'e', 'g'}, {'a', 'f'}) 268 269 all_unconverted_modules = collections.defaultdict(set) 270 all_unconverted_modules['b'].update({a, f}) 271 all_unconverted_modules['c'].update({a}) 272 273 blocked_modules = collections.defaultdict(set) 274 blocked_modules[a].update({'b', 'c'}) 275 blocked_modules[b].update(set()) 276 blocked_modules[c].update(set()) 277 blocked_modules[f].update(set({'b'})) 278 279 expected_report_data = bp2build_progress.ReportData( 280 input_modules={ 281 bp2build_progress.InputModule(a, 4, 2), 282 bp2build_progress.InputModule(f, 2, 1) 283 }, 284 total_deps={b, c, d, e, g}, 285 unconverted_deps={'b', 'c'}, 286 all_unconverted_modules=all_unconverted_modules, 287 blocked_modules=blocked_modules, 288 dirs_with_unconverted_modules={'pkg', 'other', 'pkg2'}, 289 kind_of_unconverted_modules={'type1', 'type2', 'type4'}, 290 converted={'d', 'e', 'g'}, 291 show_converted=False, 292 ) 293 294 self.assertEqual(report_data, expected_report_data) 295 296 def test_generate_report_data_show_converted(self): 297 a = bp2build_progress.ModuleInfo( 298 name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) 299 b = bp2build_progress.ModuleInfo( 300 name='b', kind='type2', dirname='pkg2', num_deps=0, created_by=None, converted=True) 301 c = bp2build_progress.ModuleInfo( 302 name='c', kind='type3', dirname='other', num_deps=0, created_by=None) 303 304 module_graph = collections.defaultdict(set) 305 module_graph[a] = set([b, c]) 306 module_graph[b].update(set()) 307 module_graph[c].update(set()) 308 309 report_data = bp2build_progress.generate_report_data( 310 module_graph, {'b'}, {'a'}, show_converted=True) 311 312 all_unconverted_modules = collections.defaultdict(set) 313 all_unconverted_modules['c'].update({a}) 314 315 blocked_modules = collections.defaultdict(set) 316 blocked_modules[a].update({'b (c)', 'c'}) 317 blocked_modules[b].update(set()) 318 blocked_modules[c].update(set()) 319 320 expected_report_data = bp2build_progress.ReportData( 321 input_modules={ 322 bp2build_progress.InputModule(a, 2, 1), 323 }, 324 total_deps={b, c}, 325 unconverted_deps={'c'}, 326 all_unconverted_modules=all_unconverted_modules, 327 blocked_modules=blocked_modules, 328 dirs_with_unconverted_modules={'pkg', 'other'}, 329 kind_of_unconverted_modules={'type1', 'type3'}, 330 converted={'b'}, 331 show_converted=True, 332 ) 333 334 self.assertEqual(report_data, expected_report_data) 335 336 def test_generate_dot_file(self): 337 self.maxDiff = None 338 a = bp2build_progress.ModuleInfo( 339 name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) 340 b = bp2build_progress.ModuleInfo( 341 name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) 342 c = bp2build_progress.ModuleInfo( 343 name='c', kind='type2', dirname='other', num_deps=1, created_by=None) 344 d = bp2build_progress.ModuleInfo( 345 name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) 346 e = bp2build_progress.ModuleInfo( 347 name='e', kind='type2', dirname='other', num_deps=0, created_by=None) 348 349 module_graph = collections.defaultdict(set) 350 module_graph[a] = set([b, c]) 351 module_graph[b] = set([d]) 352 module_graph[c] = set([e]) 353 module_graph[d] = set([]) 354 module_graph[e] = set([]) 355 356 dot_graph = bp2build_progress.generate_dot_file(module_graph, {'e'}, False) 357 358 expected_dot_graph = """ 359digraph mygraph {{ 360 node [shape=box]; 361 362 "a" [label="a\\ntype1" color=black, style=filled, fillcolor=tomato] 363 "a" -> "b" 364 "a" -> "c" 365 "b" [label="b\\ntype2" color=black, style=filled, fillcolor=tomato] 366 "b" -> "d" 367 "c" [label="c\\ntype2" color=black, style=filled, fillcolor=yellow] 368 "d" [label="d\\ntype2" color=black, style=filled, fillcolor=yellow] 369}} 370""" 371 self.assertEqual(dot_graph, expected_dot_graph) 372 373 def test_generate_dot_file_show_converted(self): 374 self.maxDiff = None 375 a = bp2build_progress.ModuleInfo( 376 name='a', kind='type1', dirname='pkg', num_deps=2, created_by=None) 377 b = bp2build_progress.ModuleInfo( 378 name='b', kind='type2', dirname='pkg', num_deps=1, created_by=None) 379 c = bp2build_progress.ModuleInfo( 380 name='c', kind='type2', dirname='other', num_deps=1, created_by=None) 381 d = bp2build_progress.ModuleInfo( 382 name='d', kind='type2', dirname='pkg', num_deps=0, created_by=None) 383 e = bp2build_progress.ModuleInfo( 384 name='e', kind='type2', dirname='other', num_deps=0, created_by=None) 385 386 module_graph = collections.defaultdict(set) 387 module_graph[a] = set([b, c]) 388 module_graph[b] = set([d]) 389 module_graph[c] = set([e]) 390 module_graph[d] = set([]) 391 module_graph[e] = set([]) 392 393 dot_graph = bp2build_progress.generate_dot_file(module_graph, {'e'}, True) 394 395 expected_dot_graph = """ 396digraph mygraph {{ 397 node [shape=box]; 398 399 "a" [label="a\\ntype1" color=black, style=filled, fillcolor=tomato] 400 "a" -> "b" 401 "a" -> "c" 402 "b" [label="b\\ntype2" color=black, style=filled, fillcolor=tomato] 403 "b" -> "d" 404 "c" [label="c\\ntype2" color=black, style=filled, fillcolor=yellow] 405 "c" -> "e" 406 "d" [label="d\\ntype2" color=black, style=filled, fillcolor=yellow] 407 "e" [label="e\\ntype2" color=black, style=filled, fillcolor=dodgerblue] 408}} 409""" 410 self.assertEqual(dot_graph, expected_dot_graph) 411 412 413if __name__ == '__main__': 414 unittest.main() 415