mirror of https://github.com/mongodb/mongo
307 lines
13 KiB
Python
Executable File
307 lines
13 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2021 MongoDB Inc.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
#
|
|
"""Unittests for the graph analyzer."""
|
|
|
|
import json
|
|
import sys
|
|
import unittest
|
|
|
|
import networkx
|
|
|
|
import libdeps.analyzer
|
|
from libdeps.graph import DependsReportTypes, LibdepsGraph, EdgeProps, LinterTypes, NodeProps, CountTypes
|
|
from generate_test_graphs import get_double_diamond_mock_graph, get_basic_mock_graph
|
|
|
|
|
|
class Tests(unittest.TestCase):
|
|
"""Common unittest for the libdeps graph analyzer module."""
|
|
|
|
def run_analysis(self, expected, graph, algo, *args):
|
|
"""Check results of analysis generically."""
|
|
|
|
analysis = [algo(graph, *args)]
|
|
ga = libdeps.analyzer.LibdepsGraphAnalysis(analysis)
|
|
printer = libdeps.analyzer.GaJsonPrinter(ga)
|
|
result = json.loads(printer.get_json())
|
|
self.assertEqual(result, expected)
|
|
|
|
def run_counts(self, expected, graph):
|
|
"""Check results of counts generically."""
|
|
|
|
analysis = libdeps.analyzer.counter_factory(
|
|
graph,
|
|
[name[0] for name in CountTypes.__members__.items() if name[0] != CountTypes.ALL.name])
|
|
ga = libdeps.analyzer.LibdepsGraphAnalysis(analysis)
|
|
printer = libdeps.analyzer.GaJsonPrinter(ga)
|
|
result = json.loads(printer.get_json())
|
|
self.assertEqual(result, expected)
|
|
|
|
def test_graph_paths_basic(self):
|
|
"""Test for the GraphPaths analyzer on a basic graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_basic_mock_graph())
|
|
|
|
expected_result = {
|
|
"GRAPH_PATHS": {
|
|
"('lib1.so', 'lib6.so')": [["lib1.so", "lib2.so", "lib3.so", "lib6.so"],
|
|
["lib1.so", "lib2.so", "lib4.so", "lib6.so"]]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib1.so',
|
|
'lib6.so')
|
|
|
|
expected_result = {"GRAPH_PATHS": {"('lib4.so', 'lib5.so')": []}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib4.so',
|
|
'lib5.so')
|
|
|
|
expected_result = {
|
|
"GRAPH_PATHS": {"('lib2.so', 'lib5.so')": [['lib2.so', 'lib3.so', 'lib5.so']]}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib2.so',
|
|
'lib5.so')
|
|
|
|
def test_graph_paths_double_diamond(self):
|
|
"""Test path algorithm on the double diamond graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph())
|
|
|
|
expected_result = {
|
|
"GRAPH_PATHS": {
|
|
"('lib1.so', 'lib9.so')":
|
|
[["lib1.so", "lib2.so", "lib3.so", "lib5.so", "lib6.so", "lib7.so", "lib9.so"],
|
|
["lib1.so", "lib2.so", "lib3.so", "lib5.so", "lib6.so", "lib8.so", "lib9.so"],
|
|
["lib1.so", "lib2.so", "lib4.so", "lib5.so", "lib6.so", "lib7.so", "lib9.so"],
|
|
["lib1.so", "lib2.so", "lib4.so", "lib5.so", "lib6.so", "lib8.so", "lib9.so"]]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib1.so',
|
|
'lib9.so')
|
|
|
|
expected_result = {
|
|
"GRAPH_PATHS": {
|
|
"('lib5.so', 'lib9.so')": [["lib5.so", "lib6.so", "lib7.so", "lib9.so"],
|
|
["lib5.so", "lib6.so", "lib8.so", "lib9.so"]]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib5.so',
|
|
'lib9.so')
|
|
|
|
expected_result = {
|
|
"GRAPH_PATHS": {
|
|
"('lib2.so', 'lib6.so')": [["lib2.so", "lib3.so", "lib5.so", "lib6.so"],
|
|
["lib2.so", "lib4.so", "lib5.so", "lib6.so"]]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib2.so',
|
|
'lib6.so')
|
|
|
|
def test_critical_paths_basic(self):
|
|
"""Test for the CriticalPaths for basic graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_basic_mock_graph())
|
|
|
|
expected_result = {"CRITICAL_EDGES": {"('lib1.so', 'lib6.so')": [["lib1.so", "lib2.so"]]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib1.so',
|
|
'lib6.so')
|
|
|
|
expected_result = {"CRITICAL_EDGES": {"('lib1.so', 'lib5.so')": [["lib1.so", "lib2.so"]]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib1.so',
|
|
'lib5.so')
|
|
|
|
expected_result = {"CRITICAL_EDGES": {"('lib5.so', 'lib6.so')": []}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib5.so',
|
|
'lib6.so')
|
|
|
|
def test_critical_paths_double_diamond(self):
|
|
"""Test for the CriticalPaths for double diamond graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph())
|
|
|
|
expected_result = {"CRITICAL_EDGES": {"('lib1.so', 'lib9.so')": [["lib1.so", "lib2.so"]]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib1.so',
|
|
'lib9.so')
|
|
|
|
expected_result = {"CRITICAL_EDGES": {"('lib2.so', 'lib9.so')": [["lib5.so", "lib6.so"]]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib2.so',
|
|
'lib9.so')
|
|
|
|
expected_result = {"CRITICAL_EDGES": {"('lib7.so', 'lib8.so')": []}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib7.so',
|
|
'lib8.so')
|
|
|
|
def test_direct_depends_basic(self):
|
|
"""Test for the DirectDependents for basic graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_basic_mock_graph())
|
|
|
|
expected_result = {"DIRECT_DEPENDS": {"lib6.so": ["lib3.so", "lib4.so"]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents,
|
|
'lib6.so')
|
|
|
|
expected_result = {'DIRECT_DEPENDS': {'lib1.so': []}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents,
|
|
'lib1.so')
|
|
|
|
def test_direct_depends_double_diamond(self):
|
|
"""Test for the DirectDependents for double diamond graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph())
|
|
|
|
expected_result = {"DIRECT_DEPENDS": {"lib9.so": ["lib7.so", "lib8.so"]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents,
|
|
'lib9.so')
|
|
|
|
expected_result = {"DIRECT_DEPENDS": {"lib6.so": ["lib5.so"]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents,
|
|
'lib6.so')
|
|
|
|
def test_common_depends_basic(self):
|
|
"""Test for the CommonDependents for basic graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_basic_mock_graph())
|
|
|
|
expected_result = {
|
|
"COMMON_DEPENDS": {
|
|
"('lib6.so', 'lib5.so')": ["lib1.so", "lib2.so", "lib3.so", "lib4.so"]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents,
|
|
['lib6.so', 'lib5.so'])
|
|
|
|
expected_result = {
|
|
"COMMON_DEPENDS": {
|
|
"('lib5.so', 'lib6.so')": ["lib1.so", "lib2.so", "lib3.so", "lib4.so"]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents,
|
|
['lib5.so', 'lib6.so'])
|
|
|
|
expected_result = {"COMMON_DEPENDS": {"('lib5.so', 'lib6.so', 'lib2.so')": ["lib1.so"]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents,
|
|
['lib5.so', 'lib6.so', 'lib2.so'])
|
|
|
|
def test_common_depends_double_diamond(self):
|
|
"""Test for the CommonDependents for double diamond graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph())
|
|
|
|
expected_result = {
|
|
"COMMON_DEPENDS": {
|
|
"('lib9.so',)": [
|
|
"lib1.so", "lib2.so", "lib3.so", "lib4.so", "lib5.so", "lib6.so", "lib7.so",
|
|
"lib8.so"
|
|
]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents,
|
|
['lib9.so'])
|
|
|
|
expected_result = {"COMMON_DEPENDS": {"('lib9.so', 'lib2.so')": ["lib1.so"]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents,
|
|
['lib9.so', 'lib2.so'])
|
|
|
|
expected_result = {"COMMON_DEPENDS": {"('lib1.so', 'lib4.so', 'lib3.so')": []}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents,
|
|
['lib1.so', 'lib4.so', 'lib3.so'])
|
|
|
|
def test_exclude_depends_basic(self):
|
|
"""Test for the ExcludeDependents for basic graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_basic_mock_graph())
|
|
|
|
expected_result = {"EXCLUDE_DEPENDS": {"('lib6.so', 'lib5.so')": []}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents,
|
|
['lib6.so', 'lib5.so'])
|
|
|
|
expected_result = {"EXCLUDE_DEPENDS": {"('lib3.so', 'lib1.so')": ["lib1.so", "lib2.so"]}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents,
|
|
['lib3.so', 'lib1.so'])
|
|
|
|
expected_result = {
|
|
"EXCLUDE_DEPENDS": {
|
|
"('lib6.so', 'lib1.so', 'lib2.so')": ["lib2.so", "lib3.so", "lib4.so"]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents,
|
|
['lib6.so', 'lib1.so', 'lib2.so'])
|
|
|
|
def test_exclude_depends_double_diamond(self):
|
|
"""Test for the ExcludeDependents for double diamond graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph())
|
|
|
|
expected_result = {
|
|
"EXCLUDE_DEPENDS": {"('lib6.so', 'lib4.so')": ["lib3.so", "lib4.so", "lib5.so"]}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents,
|
|
['lib6.so', 'lib4.so'])
|
|
|
|
expected_result = {"EXCLUDE_DEPENDS": {"('lib2.so', 'lib9.so')": []}}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents,
|
|
['lib2.so', 'lib9.so'])
|
|
|
|
expected_result = {
|
|
"EXCLUDE_DEPENDS": {
|
|
"('lib8.so', 'lib1.so', 'lib2.so', 'lib3.so', 'lib4.so', 'lib5.so')": [
|
|
"lib5.so", "lib6.so"
|
|
]
|
|
}
|
|
}
|
|
self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents,
|
|
['lib8.so', 'lib1.so', 'lib2.so', 'lib3.so', 'lib4.so', 'lib5.so'])
|
|
|
|
def test_counts_basic(self):
|
|
"""Test counts on basic graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_basic_mock_graph())
|
|
|
|
expected_result = {
|
|
"NODE": 6, "EDGE": 13, "DIR_EDGE": 7, "TRANS_EDGE": 6, "DIR_PUB_EDGE": 6,
|
|
"PUB_EDGE": 12, "PRIV_EDGE": 1, "IF_EDGE": 0, "PROG": 0, "LIB": 6
|
|
}
|
|
self.run_counts(expected_result, libdeps_graph)
|
|
|
|
def test_counts_double_diamond(self):
|
|
"""Test counts on double diamond graph."""
|
|
|
|
libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph())
|
|
|
|
expected_result = {
|
|
"NODE": 9, "EDGE": 34, "DIR_EDGE": 10, "TRANS_EDGE": 24, "DIR_PUB_EDGE": 10,
|
|
"PUB_EDGE": 34, "PRIV_EDGE": 0, "IF_EDGE": 0, "PROG": 0, "LIB": 9
|
|
}
|
|
self.run_counts(expected_result, libdeps_graph)
|
|
|
|
def test_unqiue_report_enums(self):
|
|
"""Ensure uniqueness of enums used as keys when generating reports."""
|
|
|
|
enums = [enum.name for enum in LinterTypes]
|
|
enums += [enum.name for enum in DependsReportTypes]
|
|
enums_unique = set(enums)
|
|
self.assertEqual(len(enums), len(enums_unique))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|