From c5c2390ec9e24c0f9f47e1866d39fb37654900fd Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Tue, 16 Jun 2026 09:19:21 +0530 Subject: [PATCH 1/2] ci: add multi-arch autopkgtests with DESTDIR staging and env-var path overrides --- .github/workflows/build.yaml | 22 ++++- Makefile.am | 90 ++++++++++++++++++ ci/autopkgtest/debian-tests/control | 11 +++ .../debian-tests/libcupsfilters-2-dev | 52 ++++++++++ ci/autopkgtest/run.sh | 94 +++++++++++++++++++ 5 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 ci/autopkgtest/debian-tests/control create mode 100755 ci/autopkgtest/debian-tests/libcupsfilters-2-dev create mode 100755 ci/autopkgtest/run.sh diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ac9d5871d..05383e3c4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -59,7 +59,8 @@ jobs: libfontconfig1-dev libfreetype6-dev build-essential qtbase5-dev qtchooser libcairo2-dev \ libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev \ libopenjp2-7-dev libjpeg-dev libjxl-dev libpoppler-cpp-dev libpython3-dev libdbus-1-dev \ - mupdf-tools poppler-utils ghostscript wget tar make gettext + mupdf-tools poppler-utils ghostscript wget tar make gettext \ + dbus file - name: Build PDFio and libcupsfilters (Native) if: matrix.use-qemu == false @@ -85,6 +86,16 @@ jobs: # V=1 shows compiler commands; VERBOSE=1 restores full internal test details make check V=1 VERBOSE=1 || (test -f test-suite.log && cat test-suite.log; exit 1) + - name: Autopkgtest (DESTDIR staging, native) + if: matrix.use-qemu == false + run: | + set -ex + cd "$GITHUB_WORKSPACE" + # Full downstream suite: libcupsfilters-2-dev (compile/link/run) + + # libcupsfilters-2-functionality. Both point at the staged tree via + # environment overrides, so no privilege or path redirection is needed. + make test-autopkgtest V=1 + - name: Upload test artifacts (Native) if: matrix.use-qemu == false && always() uses: actions/upload-artifact@v4 @@ -115,7 +126,8 @@ jobs: libfontconfig1-dev libfreetype6-dev build-essential qtbase5-dev qtchooser libcairo2-dev \ libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev \ libopenjp2-7-dev libjpeg-dev libjxl-dev libpoppler-cpp-dev libpython3-dev libdbus-1-dev \ - mupdf-tools poppler-utils ghostscript wget tar make gettext gcc g++ + mupdf-tools poppler-utils ghostscript wget tar make gettext gcc g++ \ + dbus file run: | set -ex REPO_DIR=$(pwd) @@ -139,6 +151,12 @@ jobs: # Mark test-pclm-overflow.sh as XFAIL; VERBOSE=1 for full internal logs make check V=1 VERBOSE=1 XFAIL_TESTS="cupsfilters/test-pclm-overflow.sh" || (test -f test-suite.log && cat test-suite.log; exit 1) + # Full downstream autopkgtest suite. Both tests resolve the staged + # build tree through environment overrides (no absolute paths, no + # privilege, no bind mounts), so the same suite that runs on the + # native legs runs unchanged under QEMU emulation. + make test-autopkgtest V=1 + - name: Upload test artifacts (Emulated) if: matrix.use-qemu == true && always() uses: actions/upload-artifact@v4 diff --git a/Makefile.am b/Makefile.am index e7624124d..d51ac0220 100644 --- a/Makefile.am +++ b/Makefile.am @@ -380,3 +380,93 @@ uninstall-hook: $(RM) $(DESTDIR)$(pkgcharsetdir)/pdf.utf-8 SUBDIRS = + +# ============================================================================= +# Downstream Debian autopkgtest harness (DESTDIR staging) +# +# Builds, DESTDIR-installs into an ephemeral $(CIROOT) tree, tops up the +# test-only programs/data that `make install` does not ship, rewrites the +# staged libcupsfilters.pc so a consumer resolves THIS build, then runs the +# vendored downstream scripts against it. No privilege, no bind mounts, no +# proot -> identical on native and QEMU-emulated architectures. +# ============================================================================= +CIROOT = $(abs_top_builddir)/_ciroot + +EXTRA_DIST += \ + ci/autopkgtest/run.sh \ + ci/autopkgtest/debian-tests/control \ + ci/autopkgtest/debian-tests/libcupsfilters-2-dev \ + ci/autopkgtest/debian-tests/libcupsfilters-2-functionality + +# Fix A: these are check_PROGRAMS (build-only; never copied by `make install`). +# The functionality test executes them as installed binaries (/usr/bin/...), +# so build them and stage them into $(CIROOT)$(bindir). libtool --mode=install +# relinks each cleanly against $(libdir) (LD_LIBRARY_PATH then forces the +# staged library at run time). +STAGED_TEST_BINARIES = \ + testdither \ + testpdf1 \ + testpdf2 \ + test-analyze \ + test-pdf \ + test-ps \ + testcmyk \ + testrgb + +install-test-programs: $(STAGED_TEST_BINARIES) + $(MKDIR_P) "$(CIROOT)$(bindir)" + @for p in $(STAGED_TEST_BINARIES); do \ + echo " STAGE $$p -> $(CIROOT)$(bindir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) "$$p" "$(CIROOT)$(bindir)/$$p" || exit 1; \ + done + +# Fix C (data seeding): the functionality test copies its input images from +# $(datadir)/libcupsfilters-tests, which upstream `make install` does not ship. +# Seed image.pgm and image.ppm (both are cupsfilters/image.pgm, matching the +# downstream packaging) so the unmodified script finds them. +install-test-data: + $(MKDIR_P) "$(CIROOT)$(datadir)/libcupsfilters-tests" + @echo " STAGE cupsfilters/image.pgm -> $(CIROOT)$(datadir)/libcupsfilters-tests/image.pgm" + $(INSTALL_DATA) "$(srcdir)/cupsfilters/image.pgm" "$(CIROOT)$(datadir)/libcupsfilters-tests/image.pgm" + @echo " STAGE cupsfilters/image.pgm -> $(CIROOT)$(datadir)/libcupsfilters-tests/image.ppm" + $(INSTALL_DATA) "$(srcdir)/cupsfilters/image.pgm" "$(CIROOT)$(datadir)/libcupsfilters-tests/image.ppm" + +stage-ciroot: all + rm -rf "$(CIROOT)" + $(MAKE) $(AM_MAKEFLAGS) install DESTDIR="$(CIROOT)" + $(MAKE) $(AM_MAKEFLAGS) install-test-programs install-test-data + @pc="$(CIROOT)$(libdir)/pkgconfig/libcupsfilters.pc"; \ + if [ -f "$$pc" ]; then \ + sed -i.bak -E "s#^(prefix|exec_prefix|libdir|includedir)=(/.*)#\1=$(CIROOT)\2#" "$$pc"; \ + rm -f "$$pc.bak"; \ + echo "stage-ciroot: rewrote staged-tree paths in $$pc"; \ + fi + +# Common environment for the wrapper. LIBCUPSFILTERS_BINDIR / LIBCUPSFILTERS_TESTDIR +# point the functionality test at the staged binaries and data instead of the +# system /usr paths, so it needs no absolute-path redirection (no root, no proot) +# and runs identically on native and QEMU-emulated architectures. +CIROOT_ENV = \ + CIROOT="$(CIROOT)" \ + CIPREFIX="$(exec_prefix)" \ + TOP_BUILDDIR="$(abs_top_builddir)" \ + LIBCUPSFILTERS_BINDIR="$(CIROOT)$(bindir)" \ + LIBCUPSFILTERS_TESTDIR="$(CIROOT)$(datadir)/libcupsfilters-tests" + +# Full downstream suite in a single wrapper invocation -> one aggregate +# PASS/FAIL summary across both tests. Identical on every architecture. +test-autopkgtest: stage-ciroot + $(CIROOT_ENV) \ + $(SHELL) $(srcdir)/ci/autopkgtest/run.sh libcupsfilters-2-dev libcupsfilters-2-functionality + +# Single-test convenience targets (handy for debugging one case in isolation). +test-autopkgtest-dev: stage-ciroot + $(CIROOT_ENV) \ + $(SHELL) $(srcdir)/ci/autopkgtest/run.sh libcupsfilters-2-dev + +test-autopkgtest-func: stage-ciroot + $(CIROOT_ENV) \ + $(SHELL) $(srcdir)/ci/autopkgtest/run.sh libcupsfilters-2-functionality + +.PHONY: stage-ciroot install-test-programs install-test-data \ + test-autopkgtest test-autopkgtest-dev test-autopkgtest-func diff --git a/ci/autopkgtest/debian-tests/control b/ci/autopkgtest/debian-tests/control new file mode 100644 index 000000000..6f50a5297 --- /dev/null +++ b/ci/autopkgtest/debian-tests/control @@ -0,0 +1,11 @@ +Tests: libcupsfilters-2-dev +Depends: build-essential, + dbus, + libcups2-dev, + libcupsfilters-dev, + pkg-config, +Restrictions: allow-stderr + +Tests: libcupsfilters-2-functionality +Depends: libcupsfilters-tests +Restrictions: allow-stderr diff --git a/ci/autopkgtest/debian-tests/libcupsfilters-2-dev b/ci/autopkgtest/debian-tests/libcupsfilters-2-dev new file mode 100755 index 000000000..d5177362b --- /dev/null +++ b/ci/autopkgtest/debian-tests/libcupsfilters-2-dev @@ -0,0 +1,52 @@ +#!/bin/sh +# autopkgtest check: Build and run a program against libcupsfilters, to verify +# that the headers and pkg-config file are installed correctly +# (C) 2012 Canonical Ltd. +# (C) 2018-2019 Simon McVittie +# Authors: Martin Pitt, Simon McVittie + +set -eux + +package=libcupsfilters +WORKDIR="$(mktemp -d)" +export HOME="$WORKDIR" +export XDG_RUNTIME_DIR="$WORKDIR" +trap 'cd /; rm -rf "$WORKDIR"' 0 INT QUIT ABRT PIPE TERM + +if [ -n "${DEB_HOST_GNU_TYPE:-}" ]; then + CROSS_COMPILE="$DEB_HOST_GNU_TYPE-" +else + CROSS_COMPILE= +fi + +cd "$WORKDIR" +cat < test.c +// All header files of libcupsfilters API +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + // Actually use something from the library, so that it gets actually linked + cfCUPSLogFunc(NULL, CF_LOGLEVEL_DEBUG, "TEST OUTPUT %d %d %d", 1, 2, 3); + return (0); +} +EOF + +# Deliberately word-splitting pkg-config's output: +# shellcheck disable=SC2046 +${CROSS_COMPILE}gcc -o "${package}-test" test.c $(${CROSS_COMPILE}pkg-config --cflags --libs "$package") +echo "build ($package): OK" +[ -x "${package}-test" ] +dbus-run-session -- "./${package}-test" 2>&1 | grep -q 'DEBUG: TEST OUTPUT 1 2 3' +echo "run ($package): OK" diff --git a/ci/autopkgtest/run.sh b/ci/autopkgtest/run.sh new file mode 100755 index 000000000..0ad0871a7 --- /dev/null +++ b/ci/autopkgtest/run.sh @@ -0,0 +1,94 @@ +#!/bin/sh +# ci/autopkgtest/run.sh +# +# Universal DESTDIR-staging wrapper for the downstream Debian autopkgtests. +# Points PATH / LD_LIBRARY_PATH / PKG_CONFIG_PATH at the staged install tree +# ($CIROOT) produced by `make stage-ciroot`, then runs the unmodified +# downstream scripts vendored under ci/autopkgtest/debian-tests/. +# +# The downstream scripts take environment overrides (e.g. LIBCUPSFILTERS_BINDIR, +# LIBCUPSFILTERS_TESTDIR) that default to the system /usr paths but can be +# redirected into the staging tree. That keeps every test free of absolute-path +# assumptions, so the wrapper needs no privilege and no bind mounts and runs +# identically on native and QEMU-emulated architectures. +# +# Env in: +# CIROOT staging root (default: $PWD/_ciroot) +# CIPREFIX configured prefix (default: /usr) +# TOP_BUILDDIR build tree (default: $PWD) +# Any extra exported variables (e.g. LIBCUPSFILTERS_BINDIR, +# LIBCUPSFILTERS_TESTDIR) are passed straight through to the scripts. +set -eu + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +TESTS_DIR="$SCRIPT_DIR/debian-tests" + +: "${CIROOT:=$PWD/_ciroot}" +: "${CIPREFIX:=/usr}" +: "${TOP_BUILDDIR:=$PWD}" + +if [ ! -d "$CIROOT" ]; then + echo "run.sh: staging root not found: $CIROOT (run 'make stage-ciroot' first)" >&2 + exit 1 +fi + +ROOT="$CIROOT$CIPREFIX" +MULTIARCH=$(dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null \ + || gcc -dumpmachine 2>/dev/null || echo "") + +PATH="$ROOT/bin:$ROOT/sbin:$TOP_BUILDDIR:$TOP_BUILDDIR/.libs:$PATH" +LD_LIBRARY_PATH="$ROOT/lib${MULTIARCH:+:$ROOT/lib/$MULTIARCH}:$TOP_BUILDDIR/.libs${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +PKG_CONFIG_PATH="$ROOT/lib/pkgconfig${MULTIARCH:+:$ROOT/lib/$MULTIARCH/pkgconfig}:$ROOT/share/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" +export PATH LD_LIBRARY_PATH PKG_CONFIG_PATH + +if [ "$#" -eq 0 ]; then + echo "run.sh: usage: run.sh [test-name...]" >&2 + exit 2 +fi + +rc=0 +total=0 +n_pass=0 +n_fail=0 +results="" +for name in "$@"; do + total=$((total + 1)) + script="$TESTS_DIR/$name" + if [ ! -f "$script" ]; then + echo "run.sh: no such test: $script" >&2 + n_fail=$((n_fail + 1)) + results="$results +FAIL: $name (not found)" + rc=1 + continue + fi + chmod +x "$script" 2>/dev/null || true + workdir=$(mktemp -d) + echo "=== autopkgtest: $name (CIROOT=$CIROOT, prefix=$CIPREFIX) ===" + if ( cd "$workdir" && "$script" ); then + echo "=== PASS: $name ===" + n_pass=$((n_pass + 1)) + results="$results +PASS: $name" + else + ec=$? + echo "=== FAIL: $name (exit $ec) ===" >&2 + n_fail=$((n_fail + 1)) + results="$results +FAIL: $name (exit $ec)" + rc=1 + fi + rm -rf "$workdir" +done + +echo "============================================================================" +echo "Downstream autopkgtest summary" +echo "============================================================================" +printf '# TOTAL: %d\n' "$total" +printf '# PASS: %d\n' "$n_pass" +printf '# FAIL: %d\n' "$n_fail" +echo "----------------------------------------------------------------------------" +printf '%s\n' "$results" | sed '/^$/d' +echo "============================================================================" + +exit $rc From 37773c1e003869925b012a5f8b5b83401e1a080a Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Tue, 16 Jun 2026 09:25:51 +0530 Subject: [PATCH 2/2] ci: add missing functionality autopkgtest script --- .../libcupsfilters-2-functionality | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100755 ci/autopkgtest/debian-tests/libcupsfilters-2-functionality diff --git a/ci/autopkgtest/debian-tests/libcupsfilters-2-functionality b/ci/autopkgtest/debian-tests/libcupsfilters-2-functionality new file mode 100755 index 000000000..56d57d2b2 --- /dev/null +++ b/ci/autopkgtest/debian-tests/libcupsfilters-2-functionality @@ -0,0 +1,74 @@ +#!/bin/sh +# autopkgtest check: Run "make check" test programs using libcupsfilters +# installed on the system. +# (C) 2012 Canonical Ltd. +# (C) 2023 Till Kamppeter +# Authors: Martin Pitt, Till Kamppeter + +set -eux + +package=libcupsfilters +WORKDIR="$(mktemp -d)" +export HOME="$WORKDIR" +export XDG_RUNTIME_DIR="$WORKDIR" +trap 'cd /; rm -rf "$WORKDIR"' 0 INT QUIT ABRT PIPE TERM + +# Location of the installed test programs and their image data. Default to the +# system paths used when the package is installed (the normal Debian autopkgtest +# case); allow a staged build tree to override them so the test assumes no +# absolute paths and runs unprivileged on every architecture. +: "${LIBCUPSFILTERS_BINDIR:=/usr/bin}" +: "${LIBCUPSFILTERS_TESTDIR:=/usr/share/libcupsfilters-tests}" + +# Copy test image files into right place +cp -r "$LIBCUPSFILTERS_TESTDIR" cupsfilters + +# Run the test programs and check the output files +"$LIBCUPSFILTERS_BINDIR/testdither" > out +echo "run test program 'testdither' on system's $package: OK" +file out | grep -qi 'netpbm image data' +echo "check output file ($package): OK" + +"$LIBCUPSFILTERS_BINDIR/testpdf1" > out +echo "run test program 'testpdf1' on system's $package: OK" +file out | grep -q 'PDF document' +echo "check output file ($package): OK" + +"$LIBCUPSFILTERS_BINDIR/testpdf2" > out +echo "run test program 'testpdf2' on system's $package: OK" +file out | grep -q 'PDF document' +echo "check output file ($package): OK" + +"$LIBCUPSFILTERS_BINDIR/test-analyze" > out +echo "run test program 'test-analyze' on system's $package: OK" +file out | grep -q 'ASCII text' +echo "check output file ($package): OK" + +"$LIBCUPSFILTERS_BINDIR/test-pdf" +echo "run test program 'test-pdf' on system's $package: OK" +file test.pdf | grep -q 'PDF document' +echo "check output file ($package): OK" + +"$LIBCUPSFILTERS_BINDIR/test-ps" +echo "run test program 'test-ps' on system's $package: OK" +file test.ps | grep -q 'PostScript document' +echo "check output file ($package): OK" + +cd cupsfilters +rm -rf test +"$LIBCUPSFILTERS_BINDIR/testcmyk" +echo "run test program 'testcmyk' on system's $package: OK" +ls -1 test +ls -1 test | wc -l +ls -1 test | wc -l | grep -q '^58$' +echo "check output directory ($package): OK" + +rm -rf test +"$LIBCUPSFILTERS_BINDIR/testrgb" +echo "run test program 'testrgb' on system's $package: OK" +ls -1 test +ls -1 test | wc -l +ls -1 test | wc -l | grep -q '^10$' +echo "check output directory ($package): OK" +rm -rf test +cd ..