Files

180 lines
5.8 KiB
Python

from __future__ import annotations
import importlib.util
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
POLICY_PATH = ROOT / "ops" / "gitea-deploy-broker" / "runner_admission_policy.py"
PROFILES_PATH = ROOT / "ops" / "gitea-deploy-broker" / "runner_profiles.py"
def _load(name: str, path: Path):
spec = importlib.util.spec_from_file_location(name, path)
assert spec and spec.loader
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
@pytest.fixture
def policy():
profiles = _load("appops_runner_profiles_for_admission_test", PROFILES_PATH)
sys.modules["runner_profiles"] = profiles
return _load("appops_runner_admission_policy_test", POLICY_PATH)
def _job(job_id: str, labels: list[str], queued_at: float):
return {"id": job_id, "labels": labels, "queued_at": queued_at}
def test_oldest_compatible_job_wins_and_profile_choice_rotates(policy):
jobs = [
_job("newer-security", ["itworx-ci-security"], 200.0),
_job("older-linux", ["self-hosted", "linux-validation"], 100.0),
]
first = policy.select_admission(
jobs,
available_profiles=["backend", "frontend", "security"],
active_claims=[],
cursor=0,
)
second = policy.select_admission(
jobs,
available_profiles=["backend", "frontend", "security"],
active_claims=[],
cursor=first.next_cursor,
)
assert (first.job_id, first.profile_id) == ("older-linux", "backend")
assert (second.job_id, second.profile_id) == ("older-linux", "frontend")
def test_enabled_legacy_slots_count_as_claims_and_can_consume_all_capacity(policy):
decision = policy.select_admission(
[_job("checks", ["itworx-ci-checks"], 1.0)],
available_profiles=["checks"],
# Two old broad Tower registrations are charged as two backend-envelope slots.
active_claims=["backend", "backend"],
)
assert decision.profile_id is None
assert decision.reason == "runner_admission_claim_limit"
def test_duplicate_legacy_claims_are_charged_against_dind_and_family_budgets(policy):
dind_limited = policy.validate_claims(["frontend", "backend"])
family_excess = policy.validate_claims(["build", "backend"])
assert dind_limited.ok
assert family_excess.reason == "runner_admission_dind_budget_exceeded"
def test_two_heavy_profiles_cannot_be_admitted_together(policy):
result = policy.validate_claims(["browser", "build"])
assert not result.ok
assert result.reason == "runner_admission_heavy_claim_limit"
def test_unmapped_enabled_registration_fails_closed(policy):
result = policy.validate_claims(["unknown-legacy-runner"])
assert not result.ok
assert result.reason == "runner_admission_profile_unmapped"
def test_candidate_is_reserved_before_it_can_be_selected(policy):
result = policy.select_admission(
[_job("build", ["itworx-ci-build"], 1.0)],
available_profiles=["build"],
active_claims=["browser"],
)
assert result.profile_id is None
assert result.reason == "runner_admission_heavy_claim_limit"
def test_unknown_required_job_label_does_not_fall_back_to_a_broad_profile(policy):
result = policy.select_admission(
[_job("mystery", ["linux-validation", "unraid-deploy"], 1.0)],
available_profiles=["backend", "frontend"],
active_claims=[],
)
assert result.profile_id is None
assert result.reason == "runner_admission_no_compatible_queue"
def test_legacy_docker_alias_keeps_heavy_reservation_and_budget_gates(policy):
selected = policy.select_admission(
[_job("docker", ["docker-validation"], 1.0)],
available_profiles=["build"], active_claims=[],
)
assert selected.profile_id == "build"
blocked = policy.select_admission(
[_job("docker", ["docker-validation"], 1.0)],
available_profiles=["build"], active_claims=["browser"],
)
assert blocked.profile_id is None
assert blocked.reason == "runner_admission_heavy_claim_limit"
def test_malformed_queue_row_fails_closed(policy):
with pytest.raises(policy.RunnerAdmissionPolicyError):
policy.select_admission(
[{"id": "bad", "labels": ["itworx-ci-checks"], "queued_at": "now"}],
available_profiles=["checks"],
active_claims=[],
)
def test_lease_yields_to_the_oldest_eligible_other_profile_without_stealing_same_profile_work(
policy,
):
queue = [
_job("older-build", ["itworx-ci-build"], 100.0),
_job("newer-backend", ["linux-validation"], 200.0),
]
decision = policy.select_lease_yield(
queue,
leased_profile="backend",
available_profiles=["checks", "security", "browser", "build"],
active_claims=["backend", "frontend"],
cursor=0,
)
assert (decision.profile_id, decision.job_id) == ("build", "older-build")
same_profile_is_oldest = policy.select_lease_yield(
[
_job("older-backend", ["linux-validation"], 100.0),
_job("newer-build", ["itworx-ci-build"], 200.0),
],
leased_profile="backend",
available_profiles=["checks", "security", "browser", "build"],
active_claims=["backend", "frontend"],
cursor=0,
)
assert same_profile_is_oldest.profile_id is None
assert same_profile_is_oldest.reason == "runner_admission_lease_retained"
def test_lease_does_not_yield_when_current_claims_can_admit_queued_work(policy):
decision = policy.select_lease_yield(
[_job("checks", ["itworx-ci-checks"], 100.0)],
leased_profile="backend",
available_profiles=["checks"],
active_claims=["backend"],
cursor=0,
)
assert decision.profile_id is None
assert decision.reason == "runner_admission_lease_not_needed"