| # Copyright 2019 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Unittests for the dependency.py module.""" |
| |
| import pytest |
| |
| from chromite.lib import build_target_lib |
| from chromite.lib import cros_test_lib |
| from chromite.lib import dependency_graph |
| from chromite.lib import dependency_lib |
| from chromite.lib import depgraph |
| from chromite.lib.parser import package_info |
| from chromite.service import dependency |
| |
| |
| pytestmark = cros_test_lib.pytestmark_inside_only |
| |
| |
| class DependencyTests(cros_test_lib.MockTestCase): |
| """General unittests for dependency module.""" |
| |
| def _build_sysroot_depgraph(self, sysroot="/build/target"): |
| """Build a DependencyGraph to test against.""" |
| |
| virtual = package_info.parse("virtual/target-foo-1.2.3") |
| dep1 = package_info.parse("cat/dep-1.0.0-r1") |
| dep2 = package_info.parse("cat/dep-2.0.0-r1") |
| virtual_dep = package_info.parse("virtual/depdep-1.0") |
| depdep = package_info.parse("cat/depdep-2.0.1-r5") |
| |
| virtual_node = dependency_graph.PackageNode( |
| virtual, sysroot, src_paths=["/virtual/foo"] |
| ) |
| dep1_node = dependency_graph.PackageNode( |
| dep1, sysroot, src_paths=["/cat/dep/one"] |
| ) |
| dep2_node = dependency_graph.PackageNode( |
| dep2, sysroot, src_paths=["/cat/dep/two"] |
| ) |
| virtual_dep_node = dependency_graph.PackageNode( |
| virtual_dep, sysroot, src_paths=["/virtual/depdep"] |
| ) |
| depdep_node = dependency_graph.PackageNode( |
| depdep, sysroot, src_paths=["/cat/depdep", "/other/depdep"] |
| ) |
| |
| virtual_node.add_dependency(dep1_node) |
| virtual_node.add_dependency(dep2_node) |
| dep1_node.add_dependency(virtual_dep_node) |
| virtual_dep_node.add_dependency(depdep_node) |
| |
| nodes = ( |
| virtual_node, |
| dep1_node, |
| dep2_node, |
| virtual_dep_node, |
| depdep_node, |
| ) |
| |
| return dependency_graph.DependencyGraph(nodes, sysroot, [virtual]) |
| |
| def setUp(self) -> None: |
| self.json_deps = { |
| "target_board": "deathstar", |
| "sysroot_path": "/build/deathstar", |
| "package_deps": { |
| "commander/darthvader-1.49.3.3": { |
| "action": "merge", |
| "category": "commander", |
| "cpes": [], |
| "deps": ["troop/clone", "troop/robot"], |
| "rev_deps": [], |
| "full_name": "commander/darthvader-1.49.3.3", |
| "name": "darthvader", |
| "version": "1.49.3.3", |
| }, |
| "troop/clone-1.2.3": { |
| "action": "merge", |
| "category": "troop", |
| "cpes": [], |
| "deps": ["equipment/jetpack"], |
| "rev_deps": ["commander/darthvader"], |
| "full_name": "troop/clone-1.2.3", |
| "name": "clone", |
| "version": "1.2.3", |
| }, |
| "troop/robot-2.3.4": { |
| "action": "merge", |
| "category": "troop", |
| "cpes": [], |
| "deps": [], |
| "rev_deps": ["commander/darthvader"], |
| "full_name": "troop/robot-2.3.4", |
| "name": "robot", |
| "version": "2.3.4", |
| }, |
| "equipment/jetpack-3.4.5": { |
| "action": "merge", |
| "category": "equipment", |
| "cpes": [], |
| "deps": [], |
| "rev_deps": ["commander/darthvader"], |
| "full_name": "equipment/jetpack-3.4.5", |
| "name": "jetpack", |
| "version": "3.4.5", |
| }, |
| }, |
| "source_path_mapping": { |
| "commander/darthvader-1.49.3.3": ["/control/room"], |
| "troop/clone-1.2.3": ["/bunker"], |
| "troop/robot-2.3.4": ["/factory"], |
| "equipment/jetpack-3.4.5": ["/factory"], |
| }, |
| } |
| |
| def testDeterminePackageRelevanceNotRelevant(self) -> None: |
| """Test determine_package_relevance with no matching paths.""" |
| src_paths = ["foo/bar/baz", "foo/bar/b", "foo/bar", "bar/foo"] |
| dep_src_paths = ["foo/bar/ba"] |
| self.assertFalse( |
| dependency.determine_package_relevance(dep_src_paths, src_paths) |
| ) |
| |
| def testDeterminePackageRelevanceExactMatch(self) -> None: |
| """Test determine_package_relevance given an exact match.""" |
| src_paths = ["foo/bar/baz"] |
| dep_src_paths = ["foo/bar/baz"] |
| self.assertTrue( |
| dependency.determine_package_relevance(dep_src_paths, src_paths) |
| ) |
| |
| def testDeterminePackageRelevanceDirectoryMatch(self) -> None: |
| """Test determine_package_relevance given a directory match.""" |
| src_paths = ["foo/bar/baz"] |
| dep_src_paths = ["foo/bar"] |
| self.assertTrue( |
| dependency.determine_package_relevance(dep_src_paths, src_paths) |
| ) |
| |
| def testGetDependenciesWithDefaultArgs(self) -> None: |
| """Test GetDependencies using the default args.""" |
| self.PatchObject( |
| depgraph, |
| "get_sysroot_dependency_graph", |
| return_value=(self._build_sysroot_depgraph()), |
| ) |
| sysroot_path = "/build/target" |
| actual_deps = dependency.GetDependencies(sysroot_path) |
| dep1 = package_info.parse("cat/dep-1.0.0-r1") |
| dep2 = package_info.parse("cat/dep-2.0.0-r1") |
| virtual = package_info.parse("virtual/target-foo-1.2.3") |
| virtual_depdep = package_info.parse("virtual/depdep-1.0") |
| depdep = package_info.parse("cat/depdep-2.0.1-r5") |
| |
| expected_deps = [dep1, dep2, virtual, virtual_depdep, depdep] |
| self.assertEqual(set(expected_deps), set(actual_deps)) |
| |
| def testGetDependenciesWithSdkSysroot(self) -> None: |
| """Test GetDependencies with the SDK depgraph.""" |
| self.PatchObject( |
| depgraph, |
| "get_sdk_dependency_graph", |
| return_value=( |
| self._build_sysroot_depgraph( |
| sysroot=build_target_lib.get_sdk_sysroot_path() |
| ) |
| ), |
| ) |
| sysroot_path = build_target_lib.get_sdk_sysroot_path() |
| actual_deps = dependency.GetDependencies(sysroot_path) |
| dep1 = package_info.parse("cat/dep-1.0.0-r1") |
| dep2 = package_info.parse("cat/dep-2.0.0-r1") |
| virtual = package_info.parse("virtual/target-foo-1.2.3") |
| virtual_depdep = package_info.parse("virtual/depdep-1.0") |
| depdep = package_info.parse("cat/depdep-2.0.1-r5") |
| |
| expected_deps = [dep1, dep2, virtual, virtual_depdep, depdep] |
| self.assertEqual(set(expected_deps), set(actual_deps)) |
| |
| def testGetDependenciesWithSrcPaths(self) -> None: |
| """Test GetDependencies given a list of paths.""" |
| self.PatchObject( |
| depgraph, |
| "get_sysroot_dependency_graph", |
| return_value=(self._build_sysroot_depgraph()), |
| ) |
| sysroot_path = "/build/target" |
| src_paths = ["/cat/dep/one"] |
| actual_deps = dependency.GetDependencies(sysroot_path, src_paths) |
| dep = package_info.parse("cat/dep-1.0.0-r1") |
| self.assertCountEqual([dep], actual_deps) |
| |
| def testGetDependenciesWithSrcPathsAndReverseDeps(self) -> None: |
| """Test GetDependencies given a list of paths.""" |
| self.PatchObject( |
| depgraph, |
| "get_sysroot_dependency_graph", |
| return_value=(self._build_sysroot_depgraph()), |
| ) |
| sysroot_path = "/build/target" |
| src_paths = ["/cat/dep/one"] |
| actual_deps = dependency.GetDependencies( |
| sysroot_path, src_paths, include_rev_dependencies=True |
| ) |
| |
| revdep = package_info.parse("virtual/target-foo-1.2.3") |
| dep = package_info.parse("cat/dep-1.0.0-r1") |
| self.assertEqual({dep, revdep}, actual_deps) |
| |
| def testGetDependenciesAffectedPackagesVirtualRedirect(self) -> None: |
| """Test include_affected_pkgs traverses redirection virtuals.""" |
| self.PatchObject( |
| depgraph, |
| "get_sysroot_dependency_graph", |
| return_value=(self._build_sysroot_depgraph()), |
| ) |
| sysroot_path = "/build/target" |
| src_paths = ["/cat/depdep"] |
| |
| actual_deps = dependency.GetDependencies( |
| sysroot_path, |
| src_paths, |
| include_affected_pkgs=True, |
| ) |
| |
| expected = { |
| package_info.parse("cat/depdep-2.0.1-r5"), |
| package_info.parse("virtual/depdep-1.0"), |
| package_info.parse("cat/dep-1.0.0-r1"), |
| } |
| |
| self.assertEqual(expected, actual_deps) |
| |
| def testGetDependenciesAffectedPackagesVirtualParent(self) -> None: |
| """Test include_affected_pkgs does not include virtual parents.""" |
| self.PatchObject( |
| depgraph, |
| "get_sysroot_dependency_graph", |
| return_value=(self._build_sysroot_depgraph()), |
| ) |
| sysroot_path = "/build/target" |
| src_paths = ["/cat/dep/one"] |
| actual_deps = dependency.GetDependencies( |
| sysroot_path, |
| src_paths, |
| include_affected_pkgs=True, |
| ) |
| |
| dep = package_info.parse("cat/dep-1.0.0-r1") |
| self.assertEqual({dep}, actual_deps) |
| |
| |
| def test_generate_source_path_mapping_sdk(monkeypatch) -> None: |
| """Test GenerateSourcePathMapping sdk argument.""" |
| |
| def gspm_patch(_packages, sysroot_path, board, *_args, **_kwargs) -> None: |
| assert sysroot_path == "/" |
| assert board is None |
| |
| monkeypatch.setattr(dependency_lib, "get_source_path_mapping", gspm_patch) |
| dependency.GenerateSourcePathMapping(["cat/pkg"], sdk=True) |
| |
| |
| def test_generate_source_path_mapping_sdk_only() -> None: |
| """Test GenerateSourcePathMapping argument handling when setting sdk.""" |
| # Board. |
| with pytest.raises(AssertionError): |
| dependency.GenerateSourcePathMapping( |
| ["cat/pkg"], sdk=True, board="board" |
| ) |
| # Sysroot. |
| with pytest.raises(AssertionError): |
| dependency.GenerateSourcePathMapping( |
| ["cat/pkg"], sdk=True, sysroot_path="/build/board" |
| ) |
| # Board and sysroot. |
| with pytest.raises(AssertionError): |
| dependency.GenerateSourcePathMapping( |
| ["cat/pkg"], sdk=True, board="board", sysroot_path="/build/board" |
| ) |
| |
| |
| def test_generate_source_path_mapping_sdk_sysroot(monkeypatch) -> None: |
| """Test GenerateSourcePathMapping with the sdk's sysroot.""" |
| |
| def gspm_patch(_packages, sysroot_path, board, *_args, **_kwargs) -> None: |
| assert sysroot_path == "/" |
| assert board is None |
| |
| monkeypatch.setattr(dependency_lib, "get_source_path_mapping", gspm_patch) |
| dependency.GenerateSourcePathMapping(["cat/pkg"], sysroot_path="/") |
| |
| |
| def test_generate_source_path_mapping_board_sysroot(monkeypatch) -> None: |
| """Test GenerateSourcePathMapping with a board's sysroot.""" |
| |
| def gspm_patch(_packages, sysroot_path, board, *_args, **_kwargs) -> None: |
| assert sysroot_path == "/build/board" |
| assert board == "board" |
| |
| monkeypatch.setattr(dependency_lib, "get_source_path_mapping", gspm_patch) |
| dependency.GenerateSourcePathMapping( |
| ["cat/pkg"], sysroot_path="/build/board" |
| ) |
| |
| |
| def test_generate_source_path_mapping_board(monkeypatch) -> None: |
| """Test GenerateSourcePathMapping with a board.""" |
| |
| def gspm_patch(_packages, sysroot_path, board, *_args, **_kwargs) -> None: |
| assert sysroot_path == "/build/board" |
| assert board == "board" |
| |
| monkeypatch.setattr(dependency_lib, "get_source_path_mapping", gspm_patch) |
| dependency.GenerateSourcePathMapping(["cat/pkg"], board="board") |
| |
| |
| def test_generate_source_path_mapping_board_and_sysroot(monkeypatch) -> None: |
| """Test GenerateSourcePathMapping with a board and custom sysroot.""" |
| |
| def gspm_patch(_packages, sysroot_path, board, *_args, **_kwargs) -> None: |
| assert sysroot_path == "/some/sysroot" |
| assert board == "board" |
| |
| monkeypatch.setattr(dependency_lib, "get_source_path_mapping", gspm_patch) |
| dependency.GenerateSourcePathMapping( |
| ["cat/pkg"], board="board", sysroot_path="/some/sysroot" |
| ) |