From 93f16a0bfa3c0b3aa5c02390534bc0ad1157aef3 Mon Sep 17 00:00:00 2001 From: Reto Gantenbein Date: Sun, 22 Mar 2026 00:08:44 +0100 Subject: [PATCH 1/2] openspec: Add e2e-github-workflow change spec --- .../e2e-github-workflow/.openspec.yaml | 2 + .../changes/e2e-github-workflow/design.md | 72 ++++++++ .../changes/e2e-github-workflow/proposal.md | 31 ++++ .../specs/e2e-github-workflow/spec.md | 44 +++++ .../specs/e2e-multi-distro/spec.md | 85 +++++++++ .../specs/e2e-testing/spec.md | 170 ++++++++++++++++++ openspec/changes/e2e-github-workflow/tasks.md | 49 +++++ 7 files changed, 453 insertions(+) create mode 100644 openspec/changes/e2e-github-workflow/.openspec.yaml create mode 100644 openspec/changes/e2e-github-workflow/design.md create mode 100644 openspec/changes/e2e-github-workflow/proposal.md create mode 100644 openspec/changes/e2e-github-workflow/specs/e2e-github-workflow/spec.md create mode 100644 openspec/changes/e2e-github-workflow/specs/e2e-multi-distro/spec.md create mode 100644 openspec/changes/e2e-github-workflow/specs/e2e-testing/spec.md create mode 100644 openspec/changes/e2e-github-workflow/tasks.md diff --git a/openspec/changes/e2e-github-workflow/.openspec.yaml b/openspec/changes/e2e-github-workflow/.openspec.yaml new file mode 100644 index 0000000..5376059 --- /dev/null +++ b/openspec/changes/e2e-github-workflow/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-21 diff --git a/openspec/changes/e2e-github-workflow/design.md b/openspec/changes/e2e-github-workflow/design.md new file mode 100644 index 0000000..70e09cd --- /dev/null +++ b/openspec/changes/e2e-github-workflow/design.md @@ -0,0 +1,72 @@ +## Context + +pkgproxy has a working e2e test suite (`test/e2e/e2e_test.go`) that validates proxying for Fedora, COPR, Debian, and Arch Linux using real containers and upstream mirrors. Currently these tests can only be run locally via `make e2e`. The test is structured as a single `TestE2E` function with subtests, sharing one pkgproxy instance. + +The goal is to run these tests in GitHub Actions on demand, expand coverage to more distributions, and expose results via a matrix strategy for clear per-distro visibility. + +## Goals / Non-Goals + +**Goals:** +- Run e2e tests in GitHub Actions via `workflow_dispatch` with a matrix strategy (one job per distro/release tuple) +- Add e2e coverage for CentOS Stream 10, AlmaLinux 10, Rocky Linux 10, and Ubuntu Noble +- Add EPEL metadata testing for non-Fedora DNF distros +- Add COPR testing for all DNF-based distros +- Parameterize the `make e2e` target with optional `DISTRO` and `RELEASE` variables +- Add `ubuntu-security` repository to pkgproxy config + +**Non-Goals:** +- Running e2e tests automatically on push or PR (manual trigger only) +- Testing multiple releases of the same distro in the initial matrix (infrastructure supports it, but not needed yet) +- Caching container images between workflow runs +- EPEL package installation testing (metadata-only, like debian-security) + +## Decisions + +### 1. One top-level test function per distro instead of subtests under TestE2E + +Each distro gets its own top-level test function (`TestFedora`, `TestDebian`, etc.) rather than subtests under a shared `TestE2E`. This enables clean `-run` filtering from the matrix without regex escaping issues, and makes each distro test self-contained with its own setup (repo files, COPR, EPEL). + +**Alternative considered:** Keeping `TestE2E` with subtests and filtering via `-run TestE2E/Fedora`. This works but couples all distros to a shared function and makes adding distro-specific setup (EPEL, different repo file patterns) messier. + +### 2. E2E_RELEASE env var for release parameterization + +Each test function reads `E2E_RELEASE` to determine the release version (e.g., `43` for Fedora, `trixie` for Debian). If unset, a sensible default is used. The matrix passes the release, and local `make e2e` works without any env vars. + +**Alternative considered:** Separate test functions per release (e.g., `TestFedora42`, `TestFedora43`). This doesn't scale and duplicates code. + +### 3. Inline matrix with explicit include entries + +The workflow matrix uses `include` with explicit objects rather than a cross-product strategy. Each entry specifies the display name, test function, and release. This is verbose but immediately readable and avoids unexpected combinations. + +### 4. Sources.list generation moves from shell script to Go test + +For apt-based distros, the Go test generates the `sources.list` file and mounts it into the container, consistent with how DNF repo files are already handled. The `test-apt.sh` script is simplified to just `apt-get update && apt-get install`. This allows the Go test to control repo prefixes (`debian` vs `ubuntu`) and security repo inclusion per distro. + +### 5. EPEL handled via additional repo file mount, metadata-only validation + +For CentOS Stream, AlmaLinux, and Rocky Linux, the Go test mounts an additional EPEL `.repo` file. The existing `dnf makecache` in `test-dnf.sh` validates that EPEL metadata is accessible. No separate package install or cache assertion is needed for EPEL (mirrors metadata, not packages). + +### 6. COPR for non-Fedora DNF distros uses epel-$releasever-$basearch pattern + +The COPR repo URL pattern for non-Fedora distros is `/copr/ganto/jo/epel-$releasever-$basearch/` (vs `/copr/ganto/jo/fedora-$releasever-$basearch/` for Fedora). + +### 7. Fully qualified container image names + +All container images use fully qualified names (`docker.io/library/fedora:43`, `quay.io/centos/centos:stream10`) to avoid dependency on container runtime defaults. This ensures consistent behavior across podman and docker. + +### 8. TestMain builds pkgproxy binary once for all test functions + +A `TestMain` function in the e2e package builds the pkgproxy binary once into a shared temporary directory and stores the path in a package-level variable. Each top-level test function reuses this pre-built binary when starting its own pkgproxy process (with its own port, cache directory, and lifecycle). This avoids rebuilding the binary 7 times when running `make e2e` locally, and costs nothing in the GitHub Actions matrix (where each job runs only one test function). + +**Alternative considered:** Building the binary in each test function (the current approach for `TestE2E`). This is simpler but wasteful when running all tests locally. + +### 9. $basearch and $releasever instead of hardcoded values + +Repo files use DNF/YUM variables (`$basearch`, `$releasever`) rather than hardcoded `x86_64` or version numbers. This allows the same tests to work on ARM64 (e.g., developer MacBooks) without modification. + +## Risks / Trade-offs + +- **Upstream mirror availability** → Tests depend on real upstream mirrors. Transient mirror failures will cause test failures. Mitigation: manual trigger only, so failures don't block CI. pkgproxy's retry configuration helps for mirrors that support it. +- **Container image pull rate limits** → Docker Hub rate limits may cause occasional failures. Mitigation: with only 7 matrix jobs on manual trigger, this is unlikely. Can add `docker login` step later if needed. +- **CentOS Stream URL structure uncertainty** → The exact mirror path for CentOS Stream 10 (`$releasever-stream/BaseOS/...`) needs validation. Mitigation: this is exactly what the e2e test will catch. +- **5-minute timeout per job** → Container image pulls + package installs on slow networks could exceed this. Mitigation: GitHub Actions runners have fast network; timeout can be bumped if needed. diff --git a/openspec/changes/e2e-github-workflow/proposal.md b/openspec/changes/e2e-github-workflow/proposal.md new file mode 100644 index 0000000..a6cc24a --- /dev/null +++ b/openspec/changes/e2e-github-workflow/proposal.md @@ -0,0 +1,31 @@ +## Why + +The e2e tests validate pkgproxy against real package managers and upstream mirrors but can only be run locally today. Adding a GitHub Actions workflow enables on-demand CI validation across all supported distributions, catches regressions from upstream mirror changes, and expands test coverage to distros not yet tested (CentOS Stream, AlmaLinux, Rocky Linux, Ubuntu). + +## What Changes + +- Add a new GitHub Actions workflow (`.github/workflows/e2e.yaml`) triggered only via `workflow_dispatch`, using a matrix strategy with one job per distro/release tuple and a 5-minute timeout per job. +- Restructure `test/e2e/e2e_test.go` from a single `TestE2E` function with subtests into separate top-level test functions per distro (`TestFedora`, `TestCentOSStream`, `TestAlmaLinux`, `TestRockyLinux`, `TestDebian`, `TestUbuntu`, `TestArch`), each parameterized by `E2E_RELEASE` env var with sensible defaults. +- Add new distro tests: CentOS Stream 10, AlmaLinux 10, Rocky Linux 10, Ubuntu Noble. +- DNF-based distros (except Fedora) include COPR (`epel-$releasever-$basearch` pattern) and EPEL repo metadata tests. Fedora includes COPR only. +- Move `sources.list` generation from `test-apt.sh` into the Go test (consistent with DNF repo file generation). Simplify `test-apt.sh` to just run `apt-get update && apt-get install`. +- Add `ubuntu-security` repository to `configs/pkgproxy.yaml`. +- Update `Makefile` with parameterized `e2e` target supporting optional `DISTRO` and `RELEASE` variables. +- Use fully qualified container image names everywhere (e.g., `docker.io/library/fedora:43`, `quay.io/centos/centos:stream10`). +- Use `$basearch` and `$releasever` variables instead of hardcoded architecture/release values. + +## Capabilities + +### New Capabilities +- `e2e-github-workflow`: GitHub Actions workflow with matrix strategy for running e2e tests per distro/release tuple on demand. +- `e2e-multi-distro`: Extended e2e test coverage for CentOS Stream, AlmaLinux, Rocky Linux, and Ubuntu, including EPEL and COPR for DNF-based distros. + +### Modified Capabilities +- `e2e-testing`: Restructure from single TestE2E into per-distro top-level test functions, parameterize by E2E_RELEASE env var, move apt sources.list generation into Go test, support DISTRO/RELEASE make parameters. + +## Impact + +- **New file**: `.github/workflows/e2e.yaml` +- **Modified files**: `test/e2e/e2e_test.go`, `test/e2e/test-apt.sh`, `configs/pkgproxy.yaml`, `Makefile`, `README.md`, `CLAUDE.md` +- **New shell scripts**: None (existing scripts reused; `test-dnf.sh` and `test-pacman.sh` unchanged) +- **External dependencies**: Container images from Docker Hub and Quay.io; upstream package mirrors (Fedora, Debian, Ubuntu, Arch, CentOS, AlmaLinux, Rocky) diff --git a/openspec/changes/e2e-github-workflow/specs/e2e-github-workflow/spec.md b/openspec/changes/e2e-github-workflow/specs/e2e-github-workflow/spec.md new file mode 100644 index 0000000..5187b4b --- /dev/null +++ b/openspec/changes/e2e-github-workflow/specs/e2e-github-workflow/spec.md @@ -0,0 +1,44 @@ +## ADDED Requirements + +### Requirement: GitHub Actions e2e workflow with workflow_dispatch trigger +The project SHALL provide a GitHub Actions workflow at `.github/workflows/e2e.yaml` that runs e2e tests. The workflow SHALL be triggered only via `workflow_dispatch` (manual trigger). The workflow SHALL NOT run automatically on push or pull request events. + +#### Scenario: Workflow is triggered manually +- **WHEN** a user triggers the e2e workflow via the GitHub Actions UI or API +- **THEN** the workflow starts and runs the e2e test matrix + +#### Scenario: Workflow does not run on push +- **WHEN** code is pushed to any branch +- **THEN** the e2e workflow is NOT triggered + +### Requirement: Matrix strategy with one job per distro/release tuple +The workflow SHALL use a GitHub Actions matrix strategy with one job per distro/release tuple. Each matrix entry SHALL define a display name, the Go test function name to run, and the release version. Each job SHALL appear as a separate entry in the GitHub Actions UI for clear failure isolation. + +#### Scenario: Matrix produces separate jobs +- **WHEN** the e2e workflow is triggered +- **THEN** GitHub Actions creates one job per matrix entry, each visible as a separate row in the workflow run UI + +#### Scenario: Each job runs exactly one distro test +- **WHEN** a matrix job executes +- **THEN** it runs only the Go test function specified by the matrix entry (e.g., `TestFedora`) with the release specified by `E2E_RELEASE` + +### Requirement: 5-minute timeout per matrix job +Each matrix job SHALL have a `timeout-minutes` of 5. + +#### Scenario: Job exceeds timeout +- **WHEN** a matrix job runs longer than 5 minutes +- **THEN** the job is cancelled by GitHub Actions + +### Requirement: Matrix includes all supported distro/release tuples +The workflow matrix SHALL include the following distro/release tuples: Fedora 43, CentOS Stream 10, AlmaLinux 10, Rocky Linux 10, Debian trixie, Ubuntu noble, Arch Linux latest. + +#### Scenario: All distros are represented in the matrix +- **WHEN** the e2e workflow is triggered +- **THEN** jobs are created for Fedora 43, CentOS Stream 10, AlmaLinux 10, Rocky Linux 10, Debian trixie, Ubuntu noble, and Arch Linux latest + +### Requirement: Workflow job steps +Each matrix job SHALL checkout the repository, set up Go, and run the e2e test for the specific distro using `go test -tags e2e -run ./test/e2e/` with the `E2E_RELEASE` environment variable set from the matrix. + +#### Scenario: Job executes test with correct parameters +- **WHEN** a matrix job for Fedora 43 runs +- **THEN** it executes `go test -tags e2e -run TestFedora ./test/e2e/` with `E2E_RELEASE=43` diff --git a/openspec/changes/e2e-github-workflow/specs/e2e-multi-distro/spec.md b/openspec/changes/e2e-github-workflow/specs/e2e-multi-distro/spec.md new file mode 100644 index 0000000..6c4811e --- /dev/null +++ b/openspec/changes/e2e-github-workflow/specs/e2e-multi-distro/spec.md @@ -0,0 +1,85 @@ +## ADDED Requirements + +### Requirement: CentOS Stream e2e test +The test suite SHALL include a CentOS Stream test function `TestCentOSStream` using a `quay.io/centos/centos:stream10` container (or the release specified by `E2E_RELEASE`). The test SHALL configure dnf with a base repo pointing at the pkgproxy `centos-stream` repository, an EPEL repo pointing at the pkgproxy `epel` repository, and a COPR repo pointing at `ganto/jo` using the `epel-$releasever-$basearch` pattern. GPG verification SHALL be enabled for base and EPEL repos, disabled for COPR. + +#### Scenario: CentOS Stream base package install succeeds +- **WHEN** the CentOS Stream container runs `dnf install -y tree` through pkgproxy +- **THEN** the command exits successfully and cached `.rpm` files exist under the `centos-stream/` cache subdirectory + +#### Scenario: CentOS Stream EPEL metadata is accessible +- **WHEN** the CentOS Stream container runs `dnf makecache` with the EPEL repo configured +- **THEN** the command exits successfully (no cache assertion for EPEL) + +#### Scenario: CentOS Stream COPR package install succeeds +- **WHEN** the CentOS Stream container runs `dnf install -y jo` from the COPR repository through pkgproxy +- **THEN** the command exits successfully and cached `.rpm` files exist under the `copr/` cache subdirectory + +### Requirement: AlmaLinux e2e test +The test suite SHALL include an AlmaLinux test function `TestAlmaLinux` using a `docker.io/library/almalinux:10` container (or the release specified by `E2E_RELEASE`). The test SHALL configure dnf with a base repo pointing at the pkgproxy `almalinux` repository, an EPEL repo, and a COPR repo using the `epel-$releasever-$basearch` pattern. + +#### Scenario: AlmaLinux base package install succeeds +- **WHEN** the AlmaLinux container runs `dnf install -y tree` through pkgproxy +- **THEN** the command exits successfully and cached `.rpm` files exist under the `almalinux/` cache subdirectory + +#### Scenario: AlmaLinux EPEL metadata is accessible +- **WHEN** the AlmaLinux container runs `dnf makecache` with the EPEL repo configured +- **THEN** the command exits successfully + +#### Scenario: AlmaLinux COPR package install succeeds +- **WHEN** the AlmaLinux container runs `dnf install -y jo` from the COPR repository through pkgproxy +- **THEN** the command exits successfully and cached `.rpm` files exist under the `copr/` cache subdirectory + +### Requirement: Rocky Linux e2e test +The test suite SHALL include a Rocky Linux test function `TestRockyLinux` using a `docker.io/library/rockylinux:10` container (or the release specified by `E2E_RELEASE`). The test SHALL configure dnf with a base repo pointing at the pkgproxy `rockylinux` repository, an EPEL repo, and a COPR repo using the `epel-$releasever-$basearch` pattern. + +#### Scenario: Rocky Linux base package install succeeds +- **WHEN** the Rocky Linux container runs `dnf install -y tree` through pkgproxy +- **THEN** the command exits successfully and cached `.rpm` files exist under the `rockylinux/` cache subdirectory + +#### Scenario: Rocky Linux EPEL metadata is accessible +- **WHEN** the Rocky Linux container runs `dnf makecache` with the EPEL repo configured +- **THEN** the command exits successfully + +#### Scenario: Rocky Linux COPR package install succeeds +- **WHEN** the Rocky Linux container runs `dnf install -y jo` from the COPR repository through pkgproxy +- **THEN** the command exits successfully and cached `.rpm` files exist under the `copr/` cache subdirectory + +### Requirement: Ubuntu e2e test +The test suite SHALL include an Ubuntu test function `TestUbuntu` using a `docker.io/library/ubuntu:noble` container (or the release specified by `E2E_RELEASE`). The test SHALL configure apt with sources pointing at the pkgproxy `ubuntu` and `ubuntu-security` repositories. The `sources.list` SHALL be generated by the Go test and mounted into the container. + +#### Scenario: Ubuntu metadata refresh succeeds +- **WHEN** the Ubuntu container runs `apt-get update` through pkgproxy +- **THEN** the command exits successfully + +#### Scenario: Ubuntu package install succeeds +- **WHEN** the Ubuntu container runs `apt-get install -y tree` through pkgproxy +- **THEN** the command exits successfully and cached `.deb` files exist under the `ubuntu/` cache subdirectory + +### Requirement: ubuntu-security repository in pkgproxy config +The pkgproxy configuration (`configs/pkgproxy.yaml`) SHALL include a `ubuntu-security` repository with `.deb` suffix and mirrors including `https://security.ubuntu.com/ubuntu/`. + +#### Scenario: ubuntu-security repository is configured +- **WHEN** pkgproxy loads its configuration +- **THEN** the `ubuntu-security` repository is available with at least one upstream mirror + +### Requirement: Fully qualified container image names +All e2e tests SHALL use fully qualified container image names including the registry (e.g., `docker.io/library/fedora:43`, `quay.io/centos/centos:stream10`). Tests SHALL NOT depend on container runtime defaults for registry resolution. + +#### Scenario: Images use fully qualified names +- **WHEN** any e2e test starts a container +- **THEN** the image reference includes the full registry path + +### Requirement: Architecture-independent repo configuration +All e2e test repo configurations SHALL use `$basearch` for architecture and `$releasever` for release version instead of hardcoded values. This SHALL allow the tests to run on both x86_64 and arm64 hosts. + +#### Scenario: Repo files use variables not hardcoded values +- **WHEN** the Go test generates a `.repo` file or `sources.list` +- **THEN** the file uses `$basearch` and `$releasever` variables where supported by the package manager + +### Requirement: COPR for non-Fedora DNF distros uses EPEL pattern +COPR repository configuration for non-Fedora DNF-based distros (CentOS Stream, AlmaLinux, Rocky Linux) SHALL use the URL pattern `/copr/ganto/jo/epel-$releasever-$basearch/`. Fedora SHALL continue using `/copr/ganto/jo/fedora-$releasever-$basearch/`. + +#### Scenario: Non-Fedora COPR uses epel pattern +- **WHEN** the Go test generates a COPR repo file for AlmaLinux +- **THEN** the baseurl uses the pattern `http:///copr/ganto/jo/epel-$releasever-$basearch/` diff --git a/openspec/changes/e2e-github-workflow/specs/e2e-testing/spec.md b/openspec/changes/e2e-github-workflow/specs/e2e-testing/spec.md new file mode 100644 index 0000000..810571e --- /dev/null +++ b/openspec/changes/e2e-github-workflow/specs/e2e-testing/spec.md @@ -0,0 +1,170 @@ +## MODIFIED Requirements + +### Requirement: E2e test framework with container runtime +The project SHALL provide end-to-end tests in `test/e2e/` that start a real pkgproxy process, run Linux distribution containers via a container runtime (podman or docker), and exercise real package managers against real upstream mirrors through the proxy. Tests SHALL be gated behind a `//go:build e2e` build tag and a `make e2e` Makefile target. Each distribution SHALL have its own top-level test function (e.g., `TestFedora`, `TestDebian`) instead of subtests under a single `TestE2E` function. + +#### Scenario: E2e tests do not run during standard test suite +- **WHEN** a developer runs `make test` or `make ci-check` +- **THEN** no e2e tests are executed + +#### Scenario: E2e tests run via make target +- **WHEN** a developer runs `make e2e` +- **THEN** all e2e test functions are executed with the `e2e` build tag and default release versions + +#### Scenario: E2e tests run for a specific distro +- **WHEN** a developer runs `make e2e DISTRO=fedora` +- **THEN** only `TestFedora` is executed with the default release version + +#### Scenario: E2e tests run for a specific distro and release +- **WHEN** a developer runs `make e2e DISTRO=fedora RELEASE=42` +- **THEN** only `TestFedora` is executed with `E2E_RELEASE=42` + +### Requirement: Pkgproxy binary built once via TestMain +The e2e test package SHALL use a `TestMain` function to build the pkgproxy binary once into a shared temporary directory before any test functions run. The binary path SHALL be stored in a package-level variable. Each top-level test function SHALL reuse this pre-built binary when starting its own pkgproxy process. The temporary directory SHALL be cleaned up after all tests complete. + +#### Scenario: Binary is built once for all tests +- **WHEN** `go test -tags e2e ./test/e2e/` runs multiple test functions +- **THEN** the pkgproxy binary is built exactly once via `TestMain` + +#### Scenario: Each test function starts its own pkgproxy process +- **WHEN** `TestFedora` and `TestDebian` both run +- **THEN** each starts a separate pkgproxy process from the shared binary, with its own port and cache directory + +### Requirement: E2E_RELEASE environment variable for release parameterization +Each top-level e2e test function SHALL read the `E2E_RELEASE` environment variable to determine the distribution release version. If `E2E_RELEASE` is not set, the test SHALL use a sensible default release (e.g., `43` for Fedora, `trixie` for Debian, `noble` for Ubuntu, `10` for CentOS Stream/AlmaLinux/Rocky Linux). + +#### Scenario: Default release is used when E2E_RELEASE is unset +- **WHEN** `TestFedora` runs without `E2E_RELEASE` set +- **THEN** the test uses the default release `43` + +#### Scenario: E2E_RELEASE overrides the default +- **WHEN** `TestFedora` runs with `E2E_RELEASE=42` +- **THEN** the test uses release `42` for the container image and repo configuration + +### Requirement: Per-distro-family shell scripts +The e2e tests SHALL use per-distro-family shell scripts (`test-dnf.sh`, `test-pacman.sh`) located in `test/e2e/` that are mounted into containers. The `test-apt.sh` script SHALL have its `sources.list` generation removed (handled by the Go test instead), but SHALL retain cleanup of `sources.list.d/` entries, setting `DEBIAN_FRONTEND=noninteractive`, and running `apt-get update` and `apt-get install`. DNF repo file generation SHALL remain in the Go test. + +#### Scenario: apt script receives pre-generated sources.list +- **WHEN** a Debian or Ubuntu container is started +- **THEN** the Go test generates and mounts the `sources.list` file, and `test-apt.sh` removes interfering `sources.list.d/` entries, sets `DEBIAN_FRONTEND=noninteractive`, and runs `apt-get update` and `apt-get install` + +#### Scenario: DNF script handles both standard and COPR repos +- **WHEN** the Go test generates a `.repo` file with `gpgcheck=0` for COPR +- **THEN** `test-dnf.sh` uses the mounted repo config as-is, without modifying GPG settings + +### Requirement: Makefile e2e target with DISTRO and RELEASE parameters +The `make e2e` target SHALL accept optional `DISTRO` and `RELEASE` parameters. When `DISTRO` is set, it SHALL be converted to the corresponding test function name and passed via `-run`. When `RELEASE` is set, it SHALL be passed as the `E2E_RELEASE` environment variable. The target SHALL use a 15-minute timeout. + +#### Scenario: make e2e without parameters runs all tests +- **WHEN** a developer runs `make e2e` +- **THEN** all e2e test functions run with default releases and a 15-minute timeout + +#### Scenario: make e2e with DISTRO filters to one test +- **WHEN** a developer runs `make e2e DISTRO=fedora` +- **THEN** only `TestFedora` runs + +#### Scenario: make e2e with DISTRO and RELEASE +- **WHEN** a developer runs `make e2e DISTRO=fedora RELEASE=42` +- **THEN** only `TestFedora` runs with `E2E_RELEASE=42` + +### Requirement: Fedora e2e test +The test suite SHALL include a top-level `TestFedora` test function using a `docker.io/library/fedora:` container (where release defaults to `43` or is set via `E2E_RELEASE`). The test SHALL configure dnf to use pkgproxy for the `fedora` repository and include a COPR subtest for `ganto/jo` using the `fedora-$releasever-$basearch` pattern. GPG verification SHALL remain enabled for the base repo, disabled for COPR. + +#### Scenario: Fedora metadata refresh succeeds +- **WHEN** the Fedora container runs `dnf makecache` through pkgproxy +- **THEN** the command exits successfully + +#### Scenario: Fedora package install succeeds +- **WHEN** the Fedora container runs `dnf install -y tree` through pkgproxy +- **THEN** the command exits successfully + +#### Scenario: Fedora packages are cached +- **WHEN** the Fedora package install completes +- **THEN** the cache directory contains at least one `.rpm` file under the `fedora/` subdirectory tree + +#### Scenario: Fedora COPR package install succeeds +- **WHEN** the Fedora container runs `dnf install -y jo` from the COPR repository through pkgproxy +- **THEN** the command exits successfully and cached `.rpm` files exist under the `copr/` cache subdirectory + +### Requirement: Debian e2e test +The test suite SHALL include a top-level `TestDebian` test function using a `docker.io/library/debian:` container (where release defaults to `trixie` or is set via `E2E_RELEASE`). The test SHALL generate a `sources.list` in the Go test pointing at pkgproxy for the `debian` and `debian-security` repositories, mount it into the container, and install a small package. + +#### Scenario: Debian metadata refresh succeeds +- **WHEN** the Debian container runs `apt-get update` through pkgproxy +- **THEN** the command exits successfully + +#### Scenario: Debian package install succeeds +- **WHEN** the Debian container runs `apt-get install -y tree` through pkgproxy +- **THEN** the command exits successfully + +#### Scenario: Debian packages are cached +- **WHEN** the Debian package install completes +- **THEN** the cache directory contains at least one `.deb` file under the `debian/` subdirectory tree + +### Requirement: Arch Linux e2e test +The test suite SHALL include a top-level `TestArch` test function using a `docker.io/library/archlinux:latest` container. The Arch Linux test SHALL NOT use `E2E_RELEASE` as Arch is a rolling release. GPG verification SHALL remain enabled. + +#### Scenario: Arch metadata refresh succeeds +- **WHEN** the Arch container runs `pacman -Sy` through pkgproxy +- **THEN** the command exits successfully + +#### Scenario: Arch package install succeeds +- **WHEN** the Arch container runs `pacman -S --noconfirm tree` through pkgproxy +- **THEN** the command exits successfully + +#### Scenario: Arch packages are cached +- **WHEN** the Arch package install completes +- **THEN** the cache directory contains at least one `.tar.zst` file under the `archlinux/` subdirectory tree + +### Requirement: COPR e2e test +The COPR test SHALL be a subtest within each DNF-based distro's top-level test function rather than a standalone test. For Fedora, the COPR URL pattern SHALL be `/copr/ganto/jo/fedora-$releasever-$basearch/`. For non-Fedora DNF distros, the pattern SHALL be `/copr/ganto/jo/epel-$releasever-$basearch/`. GPG verification SHALL be disabled for COPR (`gpgcheck=0`). + +#### Scenario: COPR package install succeeds within Fedora test +- **WHEN** `TestFedora` runs the COPR subtest +- **THEN** `jo` is installed from the COPR repository and cached `.rpm` files exist under the `copr/` subdirectory + +#### Scenario: COPR package install succeeds within non-Fedora DNF test +- **WHEN** `TestAlmaLinux` runs the COPR subtest +- **THEN** `jo` is installed from the COPR repository using the `epel-$releasever-$basearch` URL pattern + +## ADDED Requirements + +### Requirement: E2e test documentation in README.md +The `README.md` SHALL document how to run e2e tests via `make e2e` including the optional `DISTRO` and `RELEASE` parameters. It SHALL note that e2e tests should be extended when adding support for new Linux distributions. + +#### Scenario: Developer finds e2e test instructions in README +- **WHEN** a developer reads the README.md +- **THEN** they find instructions for running `make e2e`, `make e2e DISTRO=fedora`, and `make e2e DISTRO=fedora RELEASE=42` + +#### Scenario: README reminds to add e2e tests for new distros +- **WHEN** a developer reads the e2e testing section in README.md +- **THEN** they find guidance that adding support for a new Linux distribution requires adding corresponding e2e tests + +### Requirement: E2e test rules in CLAUDE.md +The `CLAUDE.md` SHALL list `make e2e` in the Commands section. The Rules section SHALL state that e2e tests must pass before a feature is considered complete. The Rules section SHALL state that adding support for a new Linux distribution requires adding corresponding e2e tests. The Rules section SHALL state that changes to client configuration snippets (e.g. `sources.list`, `.repo` files) must be replicated in the landing page snippets and in `README.md`. + +#### Scenario: CLAUDE.md commands include e2e +- **WHEN** Claude Code reads CLAUDE.md +- **THEN** `make e2e` is listed in the Commands section with usage examples + +#### Scenario: CLAUDE.md rules require e2e completion +- **WHEN** Claude Code checks the Rules section +- **THEN** it finds that e2e tests must pass before a feature is considered complete + +#### Scenario: CLAUDE.md rules require e2e for new distros +- **WHEN** Claude Code checks the Rules section +- **THEN** it finds that adding a new Linux distribution requires adding corresponding e2e tests + +#### Scenario: CLAUDE.md rules require client config consistency +- **WHEN** Claude Code checks the Rules section +- **THEN** it finds that changes to client configuration snippets (sources.list, .repo files) must be replicated in the landing page snippets and in README.md + +## REMOVED Requirements + +### Requirement: Sequential distro test execution +**Reason**: With separate top-level test functions per distro, sequential execution is no longer enforced at the test level. Each test function manages its own pkgproxy instance. In GitHub Actions, tests run in parallel via the matrix strategy. Locally, `go test` runs top-level test functions sequentially by default. +**Migration**: No migration needed. Each top-level test function is self-contained with its own pkgproxy instance and cache directory. + +### Requirement: Shared cache directory across all distro tests +**Reason**: With separate top-level test functions, each test manages its own pkgproxy process and cache directory. The pkgproxy binary is shared (built once in `TestMain`), but each test function has its own process, port, and cache. +**Migration**: Each test function creates its own temporary cache directory via `t.TempDir()`. diff --git a/openspec/changes/e2e-github-workflow/tasks.md b/openspec/changes/e2e-github-workflow/tasks.md new file mode 100644 index 0000000..1c35d4d --- /dev/null +++ b/openspec/changes/e2e-github-workflow/tasks.md @@ -0,0 +1,49 @@ +## 1. Configuration + +- [ ] 1.1 Add `ubuntu-security` repository to `configs/pkgproxy.yaml` with `.deb` suffix and `https://security.ubuntu.com/ubuntu/` mirror + +## 2. Client config updates + +- [ ] 2.1 Update Ubuntu client config section in `README.md` to point `noble-security` at `/ubuntu-security` instead of `/ubuntu` +- [ ] 2.2 Update Ubuntu landing page snippet to point `noble-security` at `/ubuntu-security` instead of `/ubuntu` + +## 3. Test restructuring + +- [ ] 3.1 Refactor `test/e2e/e2e_test.go`: add `TestMain` that builds pkgproxy binary once into a shared temp directory and stores path in a package-level variable. Extract shared helpers (container runtime detection, port allocation, pkgproxy start from pre-built binary, cache assertion, container run) and add `E2E_RELEASE` env var reading with default fallback helper +- [ ] 3.2 Convert existing `TestE2E/Fedora` subtest into top-level `TestFedora` function with its own pkgproxy instance, cache dir, and default release `43`. Include COPR subtest using `fedora-$releasever-$basearch` pattern +- [ ] 3.3 Convert existing `TestE2E/Debian` subtest into top-level `TestDebian` function. Generate `sources.list` in Go test (pointing at `/debian` and `/debian-security`), mount it into the container. Default release `trixie` +- [ ] 3.4 Convert existing `TestE2E/Arch` subtest into top-level `TestArch` function. No `E2E_RELEASE` support (rolling release). Use fully qualified image `docker.io/library/archlinux:latest` +- [ ] 3.5 Remove the old `TestE2E` function and `TestE2E/COPR` subtest (COPR is now part of each DNF distro test) + +## 4. New distro tests + +- [ ] 4.1 Add `TestCentOSStream` function using `quay.io/centos/centos:stream` image, default release `10`. Include base repo (`centos-stream`), EPEL repo, and COPR subtest (`epel-$releasever-$basearch` pattern) +- [ ] 4.2 Add `TestAlmaLinux` function using `docker.io/library/almalinux:` image, default release `10`. Include base repo (`almalinux`), EPEL repo, and COPR subtest +- [ ] 4.3 Add `TestRockyLinux` function using `docker.io/library/rockylinux:` image, default release `10`. Include base repo (`rockylinux`), EPEL repo, and COPR subtest +- [ ] 4.4 Add `TestUbuntu` function using `docker.io/library/ubuntu:` image, default release `noble`. Generate `sources.list` with `/ubuntu` and `/ubuntu-security` repos + +## 5. Shell script changes + +- [ ] 5.1 Remove `sources.list` generation from `test/e2e/test-apt.sh` (now handled by Go test). Retain `sources.list.d/` cleanup, `DEBIAN_FRONTEND=noninteractive`, and `apt-get update`/`apt-get install`. Accept packages as arguments + +## 6. Makefile + +- [ ] 6.1 Update `make e2e` target to support optional `DISTRO` and `RELEASE` parameters. Convert `DISTRO` value to test function name via `-run`. Pass `RELEASE` as `E2E_RELEASE` env var. Set 15-minute timeout + +## 7. GitHub Actions workflow + +- [ ] 7.1 Create `.github/workflows/e2e.yaml` with `workflow_dispatch` trigger, matrix strategy with 7 entries (fedora/43, centos-stream/10, almalinux/10, rockylinux/10, debian/trixie, ubuntu/noble, archlinux/latest), 5-minute timeout per job, checkout + setup-go + go test steps + +## 8. Fully qualified image names + +- [ ] 8.1 Update all existing container image references in `TestFedora` and `TestDebian` to use fully qualified names (`docker.io/library/...`) + +## 9. Documentation + +- [ ] 9.1 Update `README.md`: add a "Testing" or "Development" section documenting `make e2e` usage (with `DISTRO`/`RELEASE` parameters) and note that e2e tests should be extended when adding support for new Linux distributions +- [ ] 9.2 Update `CLAUDE.md`: add `make e2e` to the Commands section, add a rule that e2e tests must pass before a feature is considered complete, add a rule that adding support for a new Linux distribution requires adding corresponding e2e tests, and add a rule that changes to client config snippets (sources.list, .repo files) must be replicated in the landing page snippets and in README.md + +## 10. Validation + +- [ ] 10.1 Update `CHANGELOG.md` with the changes in the `[Unreleased]` section +- [ ] 10.2 Run `make ci-check` to verify no regressions in unit tests or linting From 4f96ce6a8e43a76e6794b75358fe307b02f44da6 Mon Sep 17 00:00:00 2001 From: Reto Gantenbein Date: Sun, 22 Mar 2026 00:55:15 +0100 Subject: [PATCH 2/2] Add e2e GitHub Actions workflow, new distro tests, and ubuntu-security repo - Add GitHub Actions workflow (.github/workflows/e2e.yaml) with workflow_dispatch trigger and matrix strategy for 7 distro/release tuples - Restructure e2e tests from single TestE2E into per-distro top-level functions (TestFedora, TestDebian, TestArch) with TestMain building the binary once - Add e2e tests for CentOS Stream, AlmaLinux, Rocky Linux, and Ubuntu with EPEL and COPR coverage for DNF-based distros - Add ubuntu-security repository to pkgproxy config and update landing page snippet and README to use /ubuntu-security for security updates - Move sources.list generation from test-apt.sh into Go test, add repo config printing to all shell scripts - Update Makefile e2e target with DISTRO/RELEASE params and 15m timeout - Update CLAUDE.md and README.md with e2e testing documentation Co-Authored-By: Claude Opus 4.6 --- .github/workflows/e2e.yaml | 57 ++++ CHANGELOG.md | 1 + CLAUDE.md | 6 + Makefile | 17 +- README.md | 31 +- configs/pkgproxy.yaml | 6 + openspec/changes/e2e-github-workflow/tasks.md | 40 +-- pkg/pkgproxy/landing.go | 8 +- pkg/pkgproxy/landing_test.go | 3 +- test/e2e/e2e_test.go | 310 +++++++++++++++--- test/e2e/test-apt.sh | 19 +- test/e2e/test-dnf.sh | 6 + test/e2e/test-pacman.sh | 4 + 13 files changed, 413 insertions(+), 95 deletions(-) create mode 100644 .github/workflows/e2e.yaml diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml new file mode 100644 index 0000000..331b296 --- /dev/null +++ b/.github/workflows/e2e.yaml @@ -0,0 +1,57 @@ +--- +name: E2E Tests + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + + e2e: + runs-on: ubuntu-latest + timeout-minutes: 5 + + strategy: + fail-fast: false + matrix: + include: + - name: Fedora 43 + test: TestFedora + release: "43" + - name: CentOS Stream 10 + test: TestCentOSStream + release: "10" + - name: AlmaLinux 10 + test: TestAlmaLinux + release: "10" + - name: Rocky Linux 10 + test: TestRockyLinux + release: "10" + - name: Debian trixie + test: TestDebian + release: trixie + - name: Ubuntu noble + test: TestUbuntu + release: noble + - name: Arch Linux latest + test: TestArch + release: latest + + name: ${{ matrix.name }} + + steps: + + - uses: actions/checkout@v6 + + - uses: actions/setup-go@v6 + with: + go-version: 'stable' + check-latest: true + + - name: Run e2e test + env: + E2E_RELEASE: ${{ matrix.release }} + CONTAINER_RUNTIME: docker + run: go test -tags e2e -v -race -timeout 5m -run ${{ matrix.test }} ./test/e2e/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a1b8d8..2e63228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - End-to-end tests using real package managers (dnf, apt, pacman) in containers via `make e2e` +- `ubuntu-security` repository in default configuration ### Changed diff --git a/CLAUDE.md b/CLAUDE.md index 9795cf8..9a312a9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,6 +11,9 @@ make build # build binary → bin/ make ci-check # lint + govulncheck + tests make run # run locally with debug logging go test -v -race ./pkg/pkgproxy/ -run TestName # run a single test +make e2e # run all e2e tests (requires podman or docker) +make e2e DISTRO=fedora # run e2e tests for a specific distro +make e2e DISTRO=fedora RELEASE=42 # run e2e tests for a specific distro and release ``` ## Pre-commit @@ -28,6 +31,9 @@ pre-commit run codespell --all-files - Do not delete failing tests. - Update the `[Unreleased]` section of `CHANGELOG.md` for every user-facing change made to the codebase. - Before pushing a release tag: rename `[Unreleased]` to `[v] - `, add a new empty `[Unreleased]` section above it, and commit. +- E2e tests must pass before a feature is considered complete. +- Adding support for a new Linux distribution requires adding corresponding e2e tests. +- Changes to client config snippets (sources.list, .repo files) must be replicated in the landing page snippets and in README.md. ## OpenSpec diff --git a/Makefile b/Makefile index a9d83ca..e8abf09 100644 --- a/Makefile +++ b/Makefile @@ -97,12 +97,25 @@ test: ## Run the tests against the codebase $(info **************************************************) go test $(GO_TEST_ARGS) $(GO_TEST_ARGS_EXTRA) ./... +# distroToTest converts a DISTRO value to the corresponding Go test function name. +# Usage: $(call distroToTest,fedora) → TestFedora +define distroToTest +$(strip $(if $(filter fedora,$(1)),TestFedora,\ +$(if $(filter centos-stream,$(1)),TestCentOSStream,\ +$(if $(filter almalinux,$(1)),TestAlmaLinux,\ +$(if $(filter rockylinux,$(1)),TestRockyLinux,\ +$(if $(filter debian,$(1)),TestDebian,\ +$(if $(filter ubuntu,$(1)),TestUbuntu,\ +$(if $(filter archlinux,$(1)),TestArch,\ +$(error Unknown DISTRO: $(1). Use one of: fedora centos-stream almalinux rockylinux debian ubuntu archlinux))))))))) +endef + .PHONY: e2e -e2e: ## Run end-to-end tests (requires podman or docker) +e2e: ## Run end-to-end tests (requires podman or docker). Use DISTRO= and RELEASE= to filter. $(info *************************************************) $(info ********** EXECUTING 'e2e' MAKE TARGET **********) $(info *************************************************) - go test -tags e2e $(GO_TEST_ARGS) $(GO_TEST_ARGS_EXTRA) ./test/e2e/ + E2E_RELEASE=$(RELEASE) go test -tags e2e -timeout 15m $(GO_TEST_ARGS) $(GO_TEST_ARGS_EXTRA) $(if $(DISTRO),-run $(call distroToTest,$(DISTRO))) ./test/e2e/ .PHONY: coverage coverage: ## Generates test coverage report diff --git a/README.md b/README.md index bbd541d..58a7ff3 100644 --- a/README.md +++ b/README.md @@ -167,11 +167,36 @@ baseurl=http://:8080/rockylinux/$releasever/BaseOS/$basearch/os/ E.g. Ubuntu 24.04 Noble Numbat: `/etc/apt/sources.list` (substitute your release codename): ``` -deb http://:8080/ubuntu noble main restricted universe multiverse -deb http://:8080/ubuntu noble-updates main restricted universe multiverse -deb http://:8080/ubuntu noble-security main restricted universe multiverse +deb http://:8080/ubuntu noble main restricted universe multiverse +deb http://:8080/ubuntu noble-updates main restricted universe multiverse +deb http://:8080/ubuntu-security noble-security main restricted universe multiverse ``` +## Testing + +### End-to-End Tests + +End-to-end tests validate pkgproxy against real package managers running in containers. They require either [Podman](https://podman.io/) or Docker. + +Run all e2e tests: +```shell +make e2e +``` + +Run tests for a specific distribution: +```shell +make e2e DISTRO=fedora +``` + +Run tests for a specific distribution and release: +```shell +make e2e DISTRO=fedora RELEASE=42 +``` + +Supported `DISTRO` values: `fedora`, `centos-stream`, `almalinux`, `rockylinux`, `debian`, `ubuntu`, `archlinux`. + +When adding support for a new Linux distribution, corresponding e2e tests should be added as well. + ## Building the Container Image Build a container image locally using [ko](https://ko.build/): diff --git a/configs/pkgproxy.yaml b/configs/pkgproxy.yaml index b4d0501..cfb8ed3 100644 --- a/configs/pkgproxy.yaml +++ b/configs/pkgproxy.yaml @@ -82,3 +82,9 @@ repositories: mirrors: - https://mirror.init7.net/ubuntu/ - http://archive.ubuntu.com/ubuntu/ + ubuntu-security: + suffixes: + - .deb + mirrors: + - https://mirror.init7.net/ubuntu/ + - https://security.ubuntu.com/ubuntu/ diff --git a/openspec/changes/e2e-github-workflow/tasks.md b/openspec/changes/e2e-github-workflow/tasks.md index 1c35d4d..9fbff1a 100644 --- a/openspec/changes/e2e-github-workflow/tasks.md +++ b/openspec/changes/e2e-github-workflow/tasks.md @@ -1,49 +1,49 @@ ## 1. Configuration -- [ ] 1.1 Add `ubuntu-security` repository to `configs/pkgproxy.yaml` with `.deb` suffix and `https://security.ubuntu.com/ubuntu/` mirror +- [x] 1.1 Add `ubuntu-security` repository to `configs/pkgproxy.yaml` with `.deb` suffix and `https://security.ubuntu.com/ubuntu/` mirror ## 2. Client config updates -- [ ] 2.1 Update Ubuntu client config section in `README.md` to point `noble-security` at `/ubuntu-security` instead of `/ubuntu` -- [ ] 2.2 Update Ubuntu landing page snippet to point `noble-security` at `/ubuntu-security` instead of `/ubuntu` +- [x] 2.1 Update Ubuntu client config section in `README.md` to point `noble-security` at `/ubuntu-security` instead of `/ubuntu` +- [x] 2.2 Update Ubuntu landing page snippet to point `noble-security` at `/ubuntu-security` instead of `/ubuntu` ## 3. Test restructuring -- [ ] 3.1 Refactor `test/e2e/e2e_test.go`: add `TestMain` that builds pkgproxy binary once into a shared temp directory and stores path in a package-level variable. Extract shared helpers (container runtime detection, port allocation, pkgproxy start from pre-built binary, cache assertion, container run) and add `E2E_RELEASE` env var reading with default fallback helper -- [ ] 3.2 Convert existing `TestE2E/Fedora` subtest into top-level `TestFedora` function with its own pkgproxy instance, cache dir, and default release `43`. Include COPR subtest using `fedora-$releasever-$basearch` pattern -- [ ] 3.3 Convert existing `TestE2E/Debian` subtest into top-level `TestDebian` function. Generate `sources.list` in Go test (pointing at `/debian` and `/debian-security`), mount it into the container. Default release `trixie` -- [ ] 3.4 Convert existing `TestE2E/Arch` subtest into top-level `TestArch` function. No `E2E_RELEASE` support (rolling release). Use fully qualified image `docker.io/library/archlinux:latest` -- [ ] 3.5 Remove the old `TestE2E` function and `TestE2E/COPR` subtest (COPR is now part of each DNF distro test) +- [x] 3.1 Refactor `test/e2e/e2e_test.go`: add `TestMain` that builds pkgproxy binary once into a shared temp directory and stores path in a package-level variable. Extract shared helpers (container runtime detection, port allocation, pkgproxy start from pre-built binary, cache assertion, container run) and add `E2E_RELEASE` env var reading with default fallback helper +- [x] 3.2 Convert existing `TestE2E/Fedora` subtest into top-level `TestFedora` function with its own pkgproxy instance, cache dir, and default release `43`. Include COPR subtest using `fedora-$releasever-$basearch` pattern +- [x] 3.3 Convert existing `TestE2E/Debian` subtest into top-level `TestDebian` function. Generate `sources.list` in Go test (pointing at `/debian` and `/debian-security`), mount it into the container. Default release `trixie` +- [x] 3.4 Convert existing `TestE2E/Arch` subtest into top-level `TestArch` function. No `E2E_RELEASE` support (rolling release). Use fully qualified image `docker.io/library/archlinux:latest` +- [x] 3.5 Remove the old `TestE2E` function and `TestE2E/COPR` subtest (COPR is now part of each DNF distro test) ## 4. New distro tests -- [ ] 4.1 Add `TestCentOSStream` function using `quay.io/centos/centos:stream` image, default release `10`. Include base repo (`centos-stream`), EPEL repo, and COPR subtest (`epel-$releasever-$basearch` pattern) -- [ ] 4.2 Add `TestAlmaLinux` function using `docker.io/library/almalinux:` image, default release `10`. Include base repo (`almalinux`), EPEL repo, and COPR subtest -- [ ] 4.3 Add `TestRockyLinux` function using `docker.io/library/rockylinux:` image, default release `10`. Include base repo (`rockylinux`), EPEL repo, and COPR subtest -- [ ] 4.4 Add `TestUbuntu` function using `docker.io/library/ubuntu:` image, default release `noble`. Generate `sources.list` with `/ubuntu` and `/ubuntu-security` repos +- [x] 4.1 Add `TestCentOSStream` function using `quay.io/centos/centos:stream` image, default release `10`. Include base repo (`centos-stream`), EPEL repo, and COPR subtest (`epel-$releasever-$basearch` pattern) +- [x] 4.2 Add `TestAlmaLinux` function using `docker.io/library/almalinux:` image, default release `10`. Include base repo (`almalinux`), EPEL repo, and COPR subtest +- [x] 4.3 Add `TestRockyLinux` function using `docker.io/library/rockylinux:` image, default release `10`. Include base repo (`rockylinux`), EPEL repo, and COPR subtest +- [x] 4.4 Add `TestUbuntu` function using `docker.io/library/ubuntu:` image, default release `noble`. Generate `sources.list` with `/ubuntu` and `/ubuntu-security` repos ## 5. Shell script changes -- [ ] 5.1 Remove `sources.list` generation from `test/e2e/test-apt.sh` (now handled by Go test). Retain `sources.list.d/` cleanup, `DEBIAN_FRONTEND=noninteractive`, and `apt-get update`/`apt-get install`. Accept packages as arguments +- [x] 5.1 Remove `sources.list` generation from `test/e2e/test-apt.sh` (now handled by Go test). Retain `sources.list.d/` cleanup, `DEBIAN_FRONTEND=noninteractive`, and `apt-get update`/`apt-get install`. Accept packages as arguments ## 6. Makefile -- [ ] 6.1 Update `make e2e` target to support optional `DISTRO` and `RELEASE` parameters. Convert `DISTRO` value to test function name via `-run`. Pass `RELEASE` as `E2E_RELEASE` env var. Set 15-minute timeout +- [x] 6.1 Update `make e2e` target to support optional `DISTRO` and `RELEASE` parameters. Convert `DISTRO` value to test function name via `-run`. Pass `RELEASE` as `E2E_RELEASE` env var. Set 15-minute timeout ## 7. GitHub Actions workflow -- [ ] 7.1 Create `.github/workflows/e2e.yaml` with `workflow_dispatch` trigger, matrix strategy with 7 entries (fedora/43, centos-stream/10, almalinux/10, rockylinux/10, debian/trixie, ubuntu/noble, archlinux/latest), 5-minute timeout per job, checkout + setup-go + go test steps +- [x] 7.1 Create `.github/workflows/e2e.yaml` with `workflow_dispatch` trigger, matrix strategy with 7 entries (fedora/43, centos-stream/10, almalinux/10, rockylinux/10, debian/trixie, ubuntu/noble, archlinux/latest), 5-minute timeout per job, checkout + setup-go + go test steps ## 8. Fully qualified image names -- [ ] 8.1 Update all existing container image references in `TestFedora` and `TestDebian` to use fully qualified names (`docker.io/library/...`) +- [x] 8.1 Update all existing container image references in `TestFedora` and `TestDebian` to use fully qualified names (`docker.io/library/...`) ## 9. Documentation -- [ ] 9.1 Update `README.md`: add a "Testing" or "Development" section documenting `make e2e` usage (with `DISTRO`/`RELEASE` parameters) and note that e2e tests should be extended when adding support for new Linux distributions -- [ ] 9.2 Update `CLAUDE.md`: add `make e2e` to the Commands section, add a rule that e2e tests must pass before a feature is considered complete, add a rule that adding support for a new Linux distribution requires adding corresponding e2e tests, and add a rule that changes to client config snippets (sources.list, .repo files) must be replicated in the landing page snippets and in README.md +- [x] 9.1 Update `README.md`: add a "Testing" or "Development" section documenting `make e2e` usage (with `DISTRO`/`RELEASE` parameters) and note that e2e tests should be extended when adding support for new Linux distributions +- [x] 9.2 Update `CLAUDE.md`: add `make e2e` to the Commands section, add a rule that e2e tests must pass before a feature is considered complete, add a rule that adding support for a new Linux distribution requires adding corresponding e2e tests, and add a rule that changes to client config snippets (sources.list, .repo files) must be replicated in the landing page snippets and in README.md ## 10. Validation -- [ ] 10.1 Update `CHANGELOG.md` with the changes in the `[Unreleased]` section -- [ ] 10.2 Run `make ci-check` to verify no regressions in unit tests or linting +- [x] 10.1 Update `CHANGELOG.md` with the changes in the `[Unreleased]` section +- [x] 10.2 Run `make ci-check` to verify no regressions in unit tests or linting diff --git a/pkg/pkgproxy/landing.go b/pkg/pkgproxy/landing.go index 7e53221..8fac227 100644 --- a/pkg/pkgproxy/landing.go +++ b/pkg/pkgproxy/landing.go @@ -93,9 +93,11 @@ var snippetFuncs = map[string]func(string) string{ "baseurl=http://" + addr + "/rockylinux/$releasever/BaseOS/$basearch/os/" }, "ubuntu": func(addr string) string { - return "deb http://" + addr + "/ubuntu main restricted universe multiverse\n" + - "deb http://" + addr + "/ubuntu -updates main restricted universe multiverse\n" + - "deb http://" + addr + "/ubuntu -security main restricted universe multiverse" + return "deb http://" + addr + "/ubuntu main restricted universe multiverse\n" + + "deb http://" + addr + "/ubuntu -updates main restricted universe multiverse" + }, + "ubuntu-security": func(addr string) string { + return "deb http://" + addr + "/ubuntu-security -security main restricted universe multiverse" }, } diff --git a/pkg/pkgproxy/landing_test.go b/pkg/pkgproxy/landing_test.go index 81e0782..1ef9bc4 100644 --- a/pkg/pkgproxy/landing_test.go +++ b/pkg/pkgproxy/landing_test.go @@ -82,7 +82,8 @@ func TestLandingHandlerKnownSnippets(t *testing.T) { {"epel", ".rpm", "baseurl=http://localhost:8080/epel/$releasever/Everything/$basearch/"}, {"fedora", ".rpm", "baseurl=http://localhost:8080/fedora/releases/$releasever/Everything/$basearch/os/"}, {"rockylinux", ".rpm", "baseurl=http://localhost:8080/rockylinux/$releasever/BaseOS/$basearch/os/"}, - {"ubuntu", ".deb", "deb http://localhost:8080/ubuntu <release> main restricted universe multiverse"}, + {"ubuntu", ".deb", "deb http://localhost:8080/ubuntu <release> main restricted universe multiverse"}, + {"ubuntu-security", ".deb", "deb http://localhost:8080/ubuntu-security <release>-security main restricted universe multiverse"}, } for _, tt := range tests { t.Run(tt.repo, func(t *testing.T) { diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index d8a60b0..89e4037 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -16,15 +16,46 @@ import ( "github.com/stretchr/testify/require" ) +// pkgproxyBin holds the path to the pre-built pkgproxy binary (set in TestMain). +var pkgproxyBin string + // containerRuntime holds the detected container runtime binary name. var containerRuntime string // hostGateway holds the hostname that containers use to reach the host. var hostGateway string +func TestMain(m *testing.M) { + // Build pkgproxy binary once for all test functions. + tmpDir, err := os.MkdirTemp("", "pkgproxy-e2e-*") + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create temp dir: %v\n", err) + os.Exit(1) + } + bin := filepath.Join(tmpDir, "pkgproxy") + cmd := exec.Command("go", "build", "-o", bin, ".") + cmd.Dir = projectRoot() + cmd.Env = append(os.Environ(), "CGO_ENABLED=0") + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "build failed: %s\n%v\n", out, err) + os.RemoveAll(tmpDir) + os.Exit(1) + } + pkgproxyBin = bin + + code := m.Run() + os.RemoveAll(tmpDir) + os.Exit(code) +} + func detectContainerRuntime(t *testing.T) { t.Helper() + if containerRuntime != "" { + return + } + if v := os.Getenv("CONTAINER_RUNTIME"); v != "" { if _, err := exec.LookPath(v); err != nil { t.Skipf("CONTAINER_RUNTIME=%s not found on PATH", v) @@ -46,6 +77,13 @@ func detectContainerRuntime(t *testing.T) { t.Logf("container runtime: %s, host gateway: %s", containerRuntime, hostGateway) } +func releaseOrDefault(defaultRelease string) string { + if v := os.Getenv("E2E_RELEASE"); v != "" { + return v + } + return defaultRelease +} + func freePort(t *testing.T) int { t.Helper() l, err := net.Listen("tcp", "0.0.0.0:0") @@ -55,27 +93,16 @@ func freePort(t *testing.T) int { return port } -func buildPkgproxy(t *testing.T) string { - t.Helper() - bin := filepath.Join(t.TempDir(), "pkgproxy") - cmd := exec.Command("go", "build", "-o", bin, ".") - cmd.Dir = filepath.Join(projectRoot()) - cmd.Env = append(os.Environ(), "CGO_ENABLED=0") - out, err := cmd.CombinedOutput() - require.NoError(t, err, "build failed: %s", out) - return bin -} - func projectRoot() string { // test/e2e/ -> project root wd, _ := os.Getwd() return filepath.Join(wd, "..", "..") } -func startPkgproxy(t *testing.T, bin string, port int, cacheDir string) *exec.Cmd { +func startPkgproxy(t *testing.T, port int, cacheDir string) { t.Helper() configPath := filepath.Join(projectRoot(), "configs", "pkgproxy.yaml") - cmd := exec.Command(bin, "serve", + cmd := exec.Command(pkgproxyBin, "serve", "--host", "0.0.0.0", "--port", fmt.Sprintf("%d", port), "--config", configPath, @@ -97,12 +124,11 @@ func startPkgproxy(t *testing.T, bin string, port int, cacheDir string) *exec.Cm conn, err := net.DialTimeout("tcp", addr, 200*time.Millisecond) if err == nil { conn.Close() - return cmd + return } time.Sleep(100 * time.Millisecond) } t.Fatalf("pkgproxy did not become ready on %s", addr) - return cmd } func runContainer(t *testing.T, image string, mounts []string, cmdArgs []string) { @@ -140,77 +166,253 @@ func assertCachedFiles(t *testing.T, cacheDir string, repoPrefix string, suffix } } -func TestE2E(t *testing.T) { +// setupPkgproxy is a convenience that detects the container runtime, allocates +// a free port, creates a temp cache dir, and starts a pkgproxy instance. +// It returns the proxy address and cache directory. +func setupPkgproxy(t *testing.T) (proxyAddr string, cacheDir string) { + t.Helper() detectContainerRuntime(t) - - bin := buildPkgproxy(t) port := freePort(t) - cacheDir := t.TempDir() + cacheDir = t.TempDir() + startPkgproxy(t, port, cacheDir) + proxyAddr = fmt.Sprintf("%s:%d", hostGateway, port) + return proxyAddr, cacheDir +} + +func scriptDir() string { + return filepath.Join(projectRoot(), "test", "e2e") +} - startPkgproxy(t, bin, port, cacheDir) +// dnfRepoFile creates a .repo file in a temp directory and returns its path. +func dnfRepoFile(t *testing.T, name string, content string) string { + t.Helper() + repoFile := filepath.Join(t.TempDir(), "pkgproxy-"+name+".repo") + require.NoError(t, os.WriteFile(repoFile, []byte(content), 0644)) + return repoFile +} - proxyAddr := fmt.Sprintf("%s:%d", hostGateway, port) - scriptDir := filepath.Join(projectRoot(), "test", "e2e") +func TestFedora(t *testing.T) { + release := releaseOrDefault("43") + proxyAddr, cacheDir := setupPkgproxy(t) - t.Run("Fedora", func(t *testing.T) { - repoFile := filepath.Join(t.TempDir(), "pkgproxy-fedora.repo") - repoContent := fmt.Sprintf(`[fedora] + repoFile := dnfRepoFile(t, "fedora", fmt.Sprintf(`[fedora] # metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch baseurl=http://%s/fedora/releases/$releasever/Everything/$basearch/os/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch -`, proxyAddr) - require.NoError(t, os.WriteFile(repoFile, []byte(repoContent), 0644)) +`, proxyAddr)) + + image := fmt.Sprintf("docker.io/library/fedora:%s", release) + runContainer(t, image, + []string{ + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + repoFile + ":/etc/yum.repos.d/pkgproxy-fedora.repo:ro,z", + }, + []string{"bash", "/test-dnf.sh", proxyAddr, "tree"}, + ) + assertCachedFiles(t, cacheDir, "fedora", ".rpm") + + t.Run("COPR", func(t *testing.T) { + coprFile := dnfRepoFile(t, "copr", fmt.Sprintf(`[copr:copr.fedorainfracloud.org:ganto:jo] +baseurl=http://%s/copr/ganto/jo/fedora-$releasever-$basearch/ +gpgcheck=0 +`, proxyAddr)) - runContainer(t, "fedora:43", + runContainer(t, image, []string{ - filepath.Join(scriptDir, "test-dnf.sh") + ":/test-dnf.sh:ro,z", - repoFile + ":/etc/yum.repos.d/pkgproxy-fedora.repo:ro,z", + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + coprFile + ":/etc/yum.repos.d/pkgproxy-copr.repo:ro,z", }, - []string{"bash", "/test-dnf.sh", proxyAddr, "tree"}, + []string{"bash", "/test-dnf.sh", proxyAddr, "jo"}, ) - - assertCachedFiles(t, cacheDir, "fedora", ".rpm") + assertCachedFiles(t, cacheDir, "copr", ".rpm") }) +} + +func TestDebian(t *testing.T) { + release := releaseOrDefault("trixie") + proxyAddr, cacheDir := setupPkgproxy(t) + + sourcesList := filepath.Join(t.TempDir(), "sources.list") + sourcesContent := fmt.Sprintf(`deb http://%s/debian %s main contrib non-free non-free-firmware +deb http://%s/debian %s-updates main contrib non-free non-free-firmware +deb http://%s/debian-security %s-security main contrib non-free non-free-firmware +`, proxyAddr, release, proxyAddr, release, proxyAddr, release) + require.NoError(t, os.WriteFile(sourcesList, []byte(sourcesContent), 0644)) + + image := fmt.Sprintf("docker.io/library/debian:%s", release) + runContainer(t, image, + []string{ + filepath.Join(scriptDir(), "test-apt.sh") + ":/test-apt.sh:ro,z", + sourcesList + ":/etc/apt/sources.list:ro,z", + }, + []string{"bash", "/test-apt.sh", "tree"}, + ) + assertCachedFiles(t, cacheDir, "debian", ".deb") +} + +func TestArch(t *testing.T) { + proxyAddr, cacheDir := setupPkgproxy(t) + + runContainer(t, "docker.io/library/archlinux:latest", + []string{ + filepath.Join(scriptDir(), "test-pacman.sh") + ":/test-pacman.sh:ro,z", + }, + []string{"bash", "/test-pacman.sh", proxyAddr, "tree"}, + ) + assertCachedFiles(t, cacheDir, "archlinux", ".tar.zst") +} + +func TestCentOSStream(t *testing.T) { + release := releaseOrDefault("10") + proxyAddr, cacheDir := setupPkgproxy(t) + + repoFile := dnfRepoFile(t, "centos-stream", fmt.Sprintf(`[baseos] +baseurl=http://%s/centos-stream/$releasever-stream/BaseOS/$basearch/os/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial-SHA256 +`, proxyAddr)) + + epelFile := dnfRepoFile(t, "epel", fmt.Sprintf(`[epel] +baseurl=http://%s/epel/$releasever/Everything/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +`, proxyAddr)) + + image := fmt.Sprintf("quay.io/centos/centos:stream%s", release) + runContainer(t, image, + []string{ + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + repoFile + ":/etc/yum.repos.d/pkgproxy-centos-stream.repo:ro,z", + epelFile + ":/etc/yum.repos.d/pkgproxy-epel.repo:ro,z", + }, + []string{"bash", "/test-dnf.sh", proxyAddr, "tree"}, + ) + assertCachedFiles(t, cacheDir, "centos-stream", ".rpm") t.Run("COPR", func(t *testing.T) { - repoFile := filepath.Join(t.TempDir(), "pkgproxy-copr.repo") - repoContent := fmt.Sprintf(`[copr:copr.fedorainfracloud.org:ganto:jo] -baseurl=http://%s/copr/ganto/jo/fedora-$releasever-$basearch/ + coprFile := dnfRepoFile(t, "copr", fmt.Sprintf(`[copr:copr.fedorainfracloud.org:ganto:jo] +baseurl=http://%s/copr/ganto/jo/epel-$releasever-$basearch/ gpgcheck=0 -`, proxyAddr) - require.NoError(t, os.WriteFile(repoFile, []byte(repoContent), 0644)) +`, proxyAddr)) - runContainer(t, "fedora:43", + runContainer(t, image, []string{ - filepath.Join(scriptDir, "test-dnf.sh") + ":/test-dnf.sh:ro,z", - repoFile + ":/etc/yum.repos.d/pkgproxy-copr.repo:ro,z", + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + coprFile + ":/etc/yum.repos.d/pkgproxy-copr.repo:ro,z", }, []string{"bash", "/test-dnf.sh", proxyAddr, "jo"}, ) - assertCachedFiles(t, cacheDir, "copr", ".rpm") }) +} + +func TestAlmaLinux(t *testing.T) { + release := releaseOrDefault("10") + proxyAddr, cacheDir := setupPkgproxy(t) + + repoFile := dnfRepoFile(t, "almalinux", fmt.Sprintf(`[baseos] +baseurl=http://%s/almalinux/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-$releasever +`, proxyAddr)) + + epelFile := dnfRepoFile(t, "epel", fmt.Sprintf(`[epel] +baseurl=http://%s/epel/$releasever/Everything/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +`, proxyAddr)) + + image := fmt.Sprintf("docker.io/library/almalinux:%s", release) + runContainer(t, image, + []string{ + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + repoFile + ":/etc/yum.repos.d/pkgproxy-almalinux.repo:ro,z", + epelFile + ":/etc/yum.repos.d/pkgproxy-epel.repo:ro,z", + }, + []string{"bash", "/test-dnf.sh", proxyAddr, "tree"}, + ) + assertCachedFiles(t, cacheDir, "almalinux", ".rpm") + + t.Run("COPR", func(t *testing.T) { + coprFile := dnfRepoFile(t, "copr", fmt.Sprintf(`[copr:copr.fedorainfracloud.org:ganto:jo] +baseurl=http://%s/copr/ganto/jo/epel-$releasever-$basearch/ +gpgcheck=0 +`, proxyAddr)) - t.Run("Debian", func(t *testing.T) { - runContainer(t, "debian:trixie", + runContainer(t, image, []string{ - filepath.Join(scriptDir, "test-apt.sh") + ":/test-apt.sh:ro,z", + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + coprFile + ":/etc/yum.repos.d/pkgproxy-copr.repo:ro,z", }, - []string{"bash", "/test-apt.sh", proxyAddr, "trixie", "tree"}, + []string{"bash", "/test-dnf.sh", proxyAddr, "jo"}, ) - - assertCachedFiles(t, cacheDir, "debian", ".deb") + assertCachedFiles(t, cacheDir, "copr", ".rpm") }) +} + +func TestRockyLinux(t *testing.T) { + release := releaseOrDefault("10") + proxyAddr, cacheDir := setupPkgproxy(t) + + repoFile := dnfRepoFile(t, "rockylinux", fmt.Sprintf(`[baseos] +baseurl=http://%s/rockylinux/$releasever/BaseOS/$basearch/os/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-$releasever +`, proxyAddr)) + + epelFile := dnfRepoFile(t, "epel", fmt.Sprintf(`[epel] +baseurl=http://%s/epel/$releasever/Everything/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$releasever +`, proxyAddr)) + + image := fmt.Sprintf("docker.io/rockylinux/rockylinux:%s", release) + runContainer(t, image, + []string{ + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + repoFile + ":/etc/yum.repos.d/pkgproxy-rockylinux.repo:ro,z", + epelFile + ":/etc/yum.repos.d/pkgproxy-epel.repo:ro,z", + }, + []string{"bash", "/test-dnf.sh", proxyAddr, "tree"}, + ) + assertCachedFiles(t, cacheDir, "rockylinux", ".rpm") - t.Run("Arch", func(t *testing.T) { - runContainer(t, "archlinux:latest", + t.Run("COPR", func(t *testing.T) { + coprFile := dnfRepoFile(t, "copr", fmt.Sprintf(`[copr:copr.fedorainfracloud.org:ganto:jo] +baseurl=http://%s/copr/ganto/jo/epel-$releasever-$basearch/ +gpgcheck=0 +`, proxyAddr)) + + runContainer(t, image, []string{ - filepath.Join(scriptDir, "test-pacman.sh") + ":/test-pacman.sh:ro,z", + filepath.Join(scriptDir(), "test-dnf.sh") + ":/test-dnf.sh:ro,z", + coprFile + ":/etc/yum.repos.d/pkgproxy-copr.repo:ro,z", }, - []string{"bash", "/test-pacman.sh", proxyAddr, "tree"}, + []string{"bash", "/test-dnf.sh", proxyAddr, "jo"}, ) - - assertCachedFiles(t, cacheDir, "archlinux", ".tar.zst") + assertCachedFiles(t, cacheDir, "copr", ".rpm") }) } + +func TestUbuntu(t *testing.T) { + release := releaseOrDefault("noble") + proxyAddr, cacheDir := setupPkgproxy(t) + + sourcesList := filepath.Join(t.TempDir(), "sources.list") + sourcesContent := fmt.Sprintf(`deb http://%s/ubuntu %s main restricted universe multiverse +deb http://%s/ubuntu %s-updates main restricted universe multiverse +deb http://%s/ubuntu-security %s-security main restricted universe multiverse +`, proxyAddr, release, proxyAddr, release, proxyAddr, release) + require.NoError(t, os.WriteFile(sourcesList, []byte(sourcesContent), 0644)) + + image := fmt.Sprintf("docker.io/library/ubuntu:%s", release) + runContainer(t, image, + []string{ + filepath.Join(scriptDir(), "test-apt.sh") + ":/test-apt.sh:ro,z", + sourcesList + ":/etc/apt/sources.list:ro,z", + }, + []string{"bash", "/test-apt.sh", "tree"}, + ) + assertCachedFiles(t, cacheDir, "ubuntu", ".deb") +} diff --git a/test/e2e/test-apt.sh b/test/e2e/test-apt.sh index 55935a7..a7da342 100755 --- a/test/e2e/test-apt.sh +++ b/test/e2e/test-apt.sh @@ -1,26 +1,21 @@ #!/bin/bash # test-apt.sh — Install packages via apt through pkgproxy. -# Usage: test-apt.sh [package...] +# Usage: test-apt.sh [package...] +# +# Expects a sources.list to be mounted into /etc/apt/sources.list by the caller. set -euo pipefail -PROXY_ADDR="$1"; shift -RELEASE="$1"; shift PACKAGES=("$@") -echo "==> Proxy: ${PROXY_ADDR}" -echo "==> Release: ${RELEASE}" echo "==> Packages: ${PACKAGES[*]}" -# Write sources.list pointing at pkgproxy for both debian and debian-security. -cat > /etc/apt/sources.list < sources.list:" +echo "--- /etc/apt/sources.list ---" +cat /etc/apt/sources.list + export DEBIAN_FRONTEND=noninteractive apt-get update diff --git a/test/e2e/test-dnf.sh b/test/e2e/test-dnf.sh index 5178834..d16ec04 100755 --- a/test/e2e/test-dnf.sh +++ b/test/e2e/test-dnf.sh @@ -16,6 +16,12 @@ echo "==> Packages: ${PACKAGES[*]}" # Remove all default repo files so only the mounted pkgproxy repo is used. find /etc/yum.repos.d/ -name '*.repo' ! -name 'pkgproxy-*' -delete +echo "==> Repo files:" +for f in /etc/yum.repos.d/pkgproxy-*.repo; do + echo "--- ${f} ---" + cat "${f}" +done + dnf makecache dnf install -y "${PACKAGES[@]}" diff --git a/test/e2e/test-pacman.sh b/test/e2e/test-pacman.sh index f81cd14..c630714 100755 --- a/test/e2e/test-pacman.sh +++ b/test/e2e/test-pacman.sh @@ -12,6 +12,10 @@ echo "==> Packages: ${PACKAGES[*]}" # Configure pacman mirror to use pkgproxy. echo "Server = http://${PROXY_ADDR}/archlinux/\$repo/os/\$arch" > /etc/pacman.d/mirrorlist +echo "==> mirrorlist:" +echo "--- /etc/pacman.d/mirrorlist ---" +cat /etc/pacman.d/mirrorlist + pacman -Sy pacman -S --noconfirm "${PACKAGES[@]}"