• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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