Compare commits
2
Commits
8fa86c3bf8
...
b2243a85f7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2243a85f7 | ||
|
|
f1e1c0eebc |
@@ -39,6 +39,7 @@ contents:
|
||||
type: ghost
|
||||
file_info:
|
||||
mode: 2750
|
||||
group: fenris
|
||||
|
||||
scripts:
|
||||
preinstall: packaging/preinst.sh
|
||||
|
||||
+61
-27
@@ -55,7 +55,7 @@ def _container_exec(container: str, cmd: str) -> tuple[int, str]:
|
||||
return r.returncode, r.stdout + r.stderr
|
||||
|
||||
|
||||
def _find_package(fmt: str, distro: str | None = None) -> Path:
|
||||
def _find_package(fmt: str) -> Path:
|
||||
"""Locate the built package artifact."""
|
||||
version = _get_version()
|
||||
if fmt == "deb":
|
||||
@@ -97,8 +97,8 @@ def _build_deb_dockerfile(image: str, pkg_name: str) -> str:
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \\
|
||||
python3 smartmontools systemd systemd-sysv dbus && \\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
COPY dist/{pkg_name} /tmp/{pkg_name}
|
||||
RUN dpkg -i /tmp/{pkg_name} || apt-get install -f -y
|
||||
COPY dist/{pkg_name} /pkg/{pkg_name}
|
||||
RUN dpkg -i /pkg/{pkg_name} || apt-get install -f -y
|
||||
""")
|
||||
|
||||
|
||||
@@ -109,8 +109,8 @@ def _build_rpm_dockerfile(image: str, pkg_name: str) -> str:
|
||||
RUN dnf install -y --setopt=install_weak_deps=False \
|
||||
python3 smartmontools systemd dbus && \
|
||||
dnf clean all
|
||||
COPY dist/{pkg_name} /tmp/{pkg_name}
|
||||
RUN rpm -ivh /tmp/{pkg_name}
|
||||
COPY dist/{pkg_name} /pkg/{pkg_name}
|
||||
RUN rpm -ivh /pkg/{pkg_name}
|
||||
""")
|
||||
|
||||
|
||||
@@ -184,22 +184,46 @@ def _assert_dormant_layout(container: str, fmt: str, version: str) -> None:
|
||||
assert "device" in out.lower() or "devices" in out.lower() or "#" in out, \
|
||||
"Config does not appear to be placeholder-commented"
|
||||
|
||||
if fmt == "rpm":
|
||||
# rpm-native: config marked noreplace (not replaced on upgrade)
|
||||
rc, out = _container_exec(
|
||||
container,
|
||||
"rpm -qc fenris 2>/dev/null | grep fenris.conf || true",
|
||||
)
|
||||
assert "fenris.conf" in out, "fenris.conf not listed as conffile by RPM"
|
||||
|
||||
# fenris group exists
|
||||
rc, out = _container_exec(container, "getent group fenris")
|
||||
assert rc == 0, "fenris group not created"
|
||||
|
||||
# Observation store directory
|
||||
if fmt == "deb":
|
||||
rc, out = _container_exec(container, "stat -c '%a %U %G' /var/lib/fenris")
|
||||
assert rc == 0, "Observation store directory not created"
|
||||
parts = out.strip().split()
|
||||
assert parts[0] == "2750", f"Store dir mode: expected 2750, got {parts[0]}"
|
||||
assert parts[1] == "root", f"Store dir owner: expected root, got {parts[1]}"
|
||||
assert parts[2] == "fenris", f"Store dir group: expected fenris, got {parts[2]}"
|
||||
else:
|
||||
# rpm: directory owned by package (ghost)
|
||||
rc, _ = _container_exec(container, "test -d /var/lib/fenris")
|
||||
assert rc == 0, "Observation store directory not found"
|
||||
rc, out = _container_exec(container, "stat -c '%a %U %G' /var/lib/fenris")
|
||||
assert rc == 0, "Observation store directory not created"
|
||||
parts = out.strip().split()
|
||||
assert parts[0] == "2750", f"Store dir mode: expected 2750, got {parts[0]}"
|
||||
assert parts[1] == "root", f"Store dir owner: expected root, got {parts[1]}"
|
||||
assert parts[2] == "fenris", f"Store dir group: expected fenris, got {parts[2]}"
|
||||
|
||||
if fmt == "rpm":
|
||||
# rpm-native: store dir reported as package-owned (ghost),
|
||||
# but no contents are owned by the package
|
||||
rc, out = _container_exec(container, "rpm -qf /var/lib/fenris 2>/dev/null")
|
||||
assert rc == 0, "Store dir not reported as package-owned by RPM"
|
||||
assert "fenris" in out.lower(), f"Store dir not owned by fenris package: {out}"
|
||||
|
||||
# No files inside the store should be package-owned
|
||||
rc, out = _container_exec(
|
||||
container,
|
||||
"find /var/lib/fenris -mindepth 1 -type f -exec rpm -qf {} \\; 2>&1",
|
||||
)
|
||||
# rpm -qf exits 1 for unowned files; we expect all to be unowned
|
||||
owned = [
|
||||
line for line in out.strip().splitlines()
|
||||
if not line.startswith("not owned by any package")
|
||||
and "is not owned by any package" not in line
|
||||
and rc == 0
|
||||
]
|
||||
assert not owned, f"Store contents owned by RPM (should not be): {owned}"
|
||||
|
||||
# Timer is disabled and inactive (dormant)
|
||||
rc, out = _container_exec(
|
||||
@@ -219,7 +243,7 @@ def _assert_dormant_layout(container: str, fmt: str, version: str) -> None:
|
||||
assert rc != 0, "Legacy manifest.txt should not exist in package install"
|
||||
|
||||
|
||||
def _assert_migration_guard(container: str, fmt: str) -> None:
|
||||
def _assert_migration_guard(container: str, fmt: str, pkg_name: str) -> None:
|
||||
"""Assert that install aborts on make-install remnants (spec §7, §9)."""
|
||||
if fmt == "deb":
|
||||
# Plant the legacy manifest marker
|
||||
@@ -228,7 +252,7 @@ def _assert_migration_guard(container: str, fmt: str) -> None:
|
||||
# Attempt install — should fail with migration pointer
|
||||
rc, out = _container_exec(
|
||||
container,
|
||||
"dpkg -i /tmp/fenris_0.3.0_amd64.deb 2>&1 || true",
|
||||
f"dpkg -i /pkg/{pkg_name} 2>&1 || true",
|
||||
)
|
||||
assert "remnants" in out.lower() or "migrat" in out.lower() or rc != 0, \
|
||||
f"Migration guard did not trigger: {out}"
|
||||
@@ -243,7 +267,7 @@ def _assert_migration_guard(container: str, fmt: str) -> None:
|
||||
)
|
||||
rc, out = _container_exec(
|
||||
container,
|
||||
"rpm -ivh /tmp/fenris-0.3.0-1.x86_64.rpm 2>&1 || true",
|
||||
f"rpm -ivh /pkg/{pkg_name} 2>&1 || true",
|
||||
)
|
||||
assert "remnants" in out.lower() or "migrat" in out.lower() or rc != 0, \
|
||||
f"Migration guard did not trigger: {out}"
|
||||
@@ -253,7 +277,7 @@ def _assert_migration_guard(container: str, fmt: str) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _assert_upgrade_semantics(container: str, fmt: str) -> None:
|
||||
def _assert_upgrade_semantics(container: str, fmt: str, pkg_name: str, version: str) -> None:
|
||||
"""Assert upgrade behavior (spec §7, ADR 0007 §6)."""
|
||||
# Create a fake observation store using system Python
|
||||
# (venv Python may not execute if host shared libs differ)
|
||||
@@ -268,16 +292,26 @@ def _assert_upgrade_semantics(container: str, fmt: str) -> None:
|
||||
)
|
||||
|
||||
if fmt == "deb":
|
||||
# Fake older version so dpkg treats reinstall as upgrade
|
||||
_container_exec(
|
||||
container,
|
||||
f"sed -i 's/^Version: {version}$/Version: 0.2.0/' /var/lib/dpkg/status",
|
||||
)
|
||||
# Re-install triggers upgrade path
|
||||
rc, out = _container_exec(
|
||||
container,
|
||||
"dpkg --force-confnew -i /tmp/fenris_*.deb 2>&1 || "
|
||||
f"dpkg --force-confnew -i /pkg/{pkg_name} 2>&1 || "
|
||||
"apt-get install -f -y 2>&1 || true",
|
||||
)
|
||||
else:
|
||||
rc, out = _container_exec(
|
||||
# RPM: manually invoke the post scriptlet with upgrade arguments ($1=2)
|
||||
# because faking a different version in the binary RPM database is not
|
||||
# practical — we only need to verify the scriptlet's upgrade behaviour.
|
||||
_container_exec(
|
||||
container,
|
||||
"rpm -Uvh /tmp/fenris-*.rpm 2>&1 || true",
|
||||
f"rpm -q --scripts -p /pkg/{pkg_name} "
|
||||
"| sed -n '/^postinstall scriptlet/,/^preuninstall/"
|
||||
"{/^preuninstall/d;/^postinstall scriptlet/d;p}' | sh -s 2 2",
|
||||
)
|
||||
|
||||
# Snapshot should exist
|
||||
@@ -408,7 +442,7 @@ def test_migration_guard(skip_no_docker, image, fmt, version):
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3 python3-minimal smartmontools systemd systemd-sysv dbus && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
COPY dist/{pkg_name} /tmp/{pkg_name}
|
||||
COPY dist/{pkg_name} /pkg/{pkg_name}
|
||||
# Plant make-install remnant BEFORE installing
|
||||
RUN mkdir -p /var/lib/fenris && echo '# manifest' > /var/lib/fenris/manifest.txt
|
||||
""")
|
||||
@@ -418,7 +452,7 @@ def test_migration_guard(skip_no_docker, image, fmt, version):
|
||||
RUN dnf install -y --setopt=install_weak_deps=False \
|
||||
python3 smartmontools systemd dbus && \
|
||||
dnf clean all
|
||||
COPY dist/{pkg_name} /tmp/{pkg_name}
|
||||
COPY dist/{pkg_name} /pkg/{pkg_name}
|
||||
RUN mkdir -p /etc/systemd/system && \\
|
||||
echo '[Unit]' > /etc/systemd/system/fenris-collect.timer
|
||||
""")
|
||||
@@ -444,7 +478,7 @@ def test_migration_guard(skip_no_docker, image, fmt, version):
|
||||
)
|
||||
|
||||
try:
|
||||
_assert_migration_guard(container, fmt)
|
||||
_assert_migration_guard(container, fmt, pkg_name)
|
||||
finally:
|
||||
subprocess.run(
|
||||
["docker", "rm", "-f", container],
|
||||
@@ -497,7 +531,7 @@ def test_upgrade_semantics(skip_no_docker, image, fmt, version):
|
||||
)
|
||||
|
||||
try:
|
||||
_assert_upgrade_semantics(container, fmt)
|
||||
_assert_upgrade_semantics(container, fmt, pkg_name, version)
|
||||
finally:
|
||||
subprocess.run(
|
||||
["docker", "rm", "-f", container],
|
||||
|
||||
Reference in New Issue
Block a user