add ability to partition tree before calculationn

This commit is contained in:
2023-08-27 01:12:12 +03:00
parent 9fa6722eaa
commit 3cac53ac11
13 changed files with 393 additions and 45 deletions

View File

@ -1,6 +1,7 @@
import argparse
from pytest_mock import MockerFixture
from unittest.mock import call as MockCall
from ahriman.application.handlers import Structure
from ahriman.core.configuration import Configuration
@ -8,19 +9,40 @@ from ahriman.core.repository import Repository
from ahriman.models.package import Package
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
"""
default arguments for these test cases
Args:
args(argparse.Namespace): command line arguments fixture
Returns:
argparse.Namespace: generated arguments for these test cases
"""
args.partitions = 1
return args
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run command
"""
args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
packages_mock = mocker.patch("ahriman.core.tree.Tree.partition", return_value=[[package_ahriman]])
application_mock = mocker.patch("ahriman.core.tree.Tree.resolve", return_value=[[package_ahriman]])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Structure.run(args, "x86_64", configuration, report=False)
packages_mock.assert_called_once_with([package_ahriman], count=args.partitions)
application_mock.assert_called_once_with([package_ahriman])
print_mock.assert_called_once_with(verbose=True, separator=" ")
print_mock.assert_has_calls([
MockCall(verbose=False),
MockCall(verbose=True, separator=" "),
MockCall(verbose=False),
])
def test_disallow_auto_architecture_run() -> None:

View File

@ -600,6 +600,16 @@ def test_subparsers_repo_tree_architecture(parser: argparse.ArgumentParser) -> N
assert args.architecture == ["x86_64"]
def test_subparsers_repo_tree_option_partitions(parser: argparse.ArgumentParser) -> None:
"""
must convert partitions option to int instance
"""
args = parser.parse_args(["repo-tree"])
assert isinstance(args.partitions, int)
args = parser.parse_args(["repo-tree", "--partitions", "42"])
assert isinstance(args.partitions, int)
def test_subparsers_repo_triggers_architecture(parser: argparse.ArgumentParser) -> None:
"""
repo-triggers command must correctly parse architecture list

View File

@ -1,6 +1,11 @@
import pytest
from ahriman.core.exceptions import PartitionError
from ahriman.core.tree import Leaf, Tree
from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription
from ahriman.models.package_source import PackageSource
from ahriman.models.remote_source import RemoteSource
def test_leaf_is_root_empty(leaf_ahriman: Leaf) -> None:
@ -33,15 +38,100 @@ def test_leaf_is_root_true(leaf_ahriman: Leaf, leaf_python_schedule: Leaf) -> No
assert not leaf_ahriman.is_root([leaf_python_schedule])
def test_tree_balance() -> None:
"""
must balance partitions
"""
leaf1 = Leaf(
Package(
base="package1",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package1": PackageDescription(depends=[])},
)
)
leaf2 = Leaf(
Package(
base="package2",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package2": PackageDescription(depends=[])},
)
)
leaf3 = Leaf(
Package(
base="package3",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package3": PackageDescription(depends=["package1"])},
)
)
leaf4 = Leaf(
Package(
base="package4",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package4": PackageDescription(depends=[])},
)
)
leaf5 = Leaf(
Package(
base="package5",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package5": PackageDescription(depends=[])},
)
)
first, second, third = Tree.balance([[leaf4], [leaf1, leaf2, leaf3], [leaf5]])
assert first == [leaf4, leaf2]
assert second == [leaf1, leaf3]
assert third == [leaf5]
def test_tree_partition(package_ahriman: Package, package_python_schedule: Package) -> None:
"""
must partition dependencies tree
"""
partitions = Tree.partition([package_ahriman, package_python_schedule], count=1)
assert len(partitions) == 1
assert len(partitions[0]) == 2
partitions = Tree.partition([package_ahriman, package_python_schedule], count=2)
assert len(partitions) == 2
assert all(len(partition) < 2 for partition in partitions)
partitions = Tree.partition([package_ahriman, package_python_schedule], count=3)
assert len(partitions) == 2
assert all(len(partition) < 2 for partition in partitions)
def test_tree_partition_invalid_count() -> None:
"""
must raise PartitionError exception if count is invalid
"""
with pytest.raises(PartitionError):
Tree.partition([], count=0)
with pytest.raises(PartitionError):
Tree.partition([], count=-1)
def test_tree_resolve(package_ahriman: Package, package_python_schedule: Package) -> None:
"""
must resolve denendecnies tree
must resolve dependencies tree
"""
tree = Tree.resolve([package_ahriman, package_python_schedule])
assert len(tree) == 1
assert len(tree[0]) == 2
def test_tree_sort(leaf_ahriman: Leaf, leaf_python_schedule: Leaf) -> None:
"""
must sort leaves and return packages
"""
assert Tree.sort([[leaf_python_schedule, leaf_ahriman]]) == [[leaf_ahriman.package, leaf_python_schedule.package]]
def test_tree_levels(leaf_ahriman: Leaf, leaf_python_schedule: Leaf) -> None:
"""
must generate correct levels in the simples case
@ -62,32 +152,32 @@ def test_tree_levels_sorted() -> None:
Package(
base="package1",
version="1.0.0",
remote=None,
packages={"package1": PackageDescription(depends=[])}
remote=RemoteSource(source=PackageSource.AUR),
packages={"package1": PackageDescription(depends=[])},
)
)
leaf2 = Leaf(
Package(
base="package2",
version="1.0.0",
remote=None,
packages={"package2": PackageDescription(depends=["package1"])}
remote=RemoteSource(source=PackageSource.AUR),
packages={"package2": PackageDescription(depends=["package1"])},
)
)
leaf3 = Leaf(
Package(
base="package3",
version="1.0.0",
remote=None,
packages={"package3": PackageDescription(depends=["package1"])}
remote=RemoteSource(source=PackageSource.AUR),
packages={"package3": PackageDescription(depends=["package1"])},
)
)
leaf4 = Leaf(
Package(
base="package4",
version="1.0.0",
remote=None,
packages={"package4": PackageDescription(depends=["package3"])}
remote=RemoteSource(source=PackageSource.AUR),
packages={"package4": PackageDescription(depends=["package3"])},
)
)
@ -96,3 +186,54 @@ def test_tree_levels_sorted() -> None:
assert first == [leaf1.package]
assert second == [leaf3.package]
assert third == [leaf2.package, leaf4.package]
def test_tree_partitions() -> None:
"""
must divide tree into partitions
"""
leaf1 = Leaf(
Package(
base="package1",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package1": PackageDescription(depends=[])},
)
)
leaf2 = Leaf(
Package(
base="package2",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package2": PackageDescription(depends=["package1"])},
)
)
leaf3 = Leaf(
Package(
base="package3",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package3": PackageDescription(depends=["package1"])},
)
)
leaf4 = Leaf(
Package(
base="package4",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package4": PackageDescription(depends=[])},
)
)
leaf5 = Leaf(
Package(
base="package5",
version="1.0.0",
remote=RemoteSource(source=PackageSource.AUR),
packages={"package5": PackageDescription(depends=["package2"])},
)
)
tree = Tree([leaf1, leaf2, leaf3, leaf4, leaf5])
first, second = tree.partitions(count=3)
assert first == [leaf1.package, leaf2.package, leaf3.package, leaf5.package]
assert second == [leaf4.package]

View File

@ -2,16 +2,15 @@ import datetime
import logging
import os
import pytest
import requests
from pathlib import Path
from pytest_mock import MockerFixture
from typing import Any
from unittest.mock import MagicMock, call as MockCall
from unittest.mock import call as MockCall
from ahriman.core.exceptions import BuildError, CalledProcessError, OptionError, UnsafeRunError
from ahriman.core.util import check_output, check_user, dataclass_view, enum_values, extract_user, filter_json, \
full_version, package_like, parse_version, partition, pretty_datetime, pretty_size, safe_filename, \
full_version, minmax, package_like, parse_version, partition, pretty_datetime, pretty_size, safe_filename, \
srcinfo_property, srcinfo_property_list, trim_package, utcnow, walk
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
@ -204,6 +203,15 @@ def test_dataclass_view_without_none(package_ahriman: Package) -> None:
assert Package.from_json(result) == package_ahriman
def test_enum_values() -> None:
"""
must correctly generate choices from enumeration classes
"""
values = enum_values(PackageSource)
for value in values:
assert PackageSource(value).value == value
def test_extract_user() -> None:
"""
must extract user from system environment
@ -241,15 +249,6 @@ def test_filter_json_empty_value(package_ahriman: Package) -> None:
assert "base" not in filter_json(probe, probe.keys())
def test_enum_values() -> None:
"""
must correctly generate choices from enumeration classes
"""
values = enum_values(PackageSource)
for value in values:
assert PackageSource(value).value == value
def test_full_version() -> None:
"""
must construct full version
@ -260,6 +259,14 @@ def test_full_version() -> None:
assert full_version(1, "0.12.1", "1") == "1:0.12.1-1"
def test_minmax() -> None:
"""
must correctly define minimal and maximal value
"""
assert minmax([1, 4, 3, 2]) == (1, 4)
assert minmax([[1, 2, 3], [4, 5], [6, 7, 8, 9]], key=len) == ([4, 5], [6, 7, 8, 9])
def test_package_like(package_ahriman: Package) -> None:
"""
package_like must return true for archives