mirror of https://github.com/mongodb/mongo
401 lines
14 KiB
Python
Executable File
401 lines
14 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 unittest
|
|
|
|
import libdeps.analyzer
|
|
from generate_test_graphs import get_basic_mock_graph, get_double_diamond_mock_graph
|
|
from libdeps.graph import (
|
|
CountTypes,
|
|
DependsReportTypes,
|
|
LibdepsGraph,
|
|
LinterTypes,
|
|
)
|
|
|
|
|
|
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()
|