ci: bump actions/download-artifact from 4 to 8 #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============================================================================= | |
| # Emulator integration test for ipp-usb | |
| # | |
| # This workflow exercises ipp-usb against a *virtual* IPP-over-USB printer, | |
| # with no physical hardware, using the go-mfp MFP simulator written by | |
| # Alexander Pevzner (https://github.com/OpenPrinting/go-mfp). | |
| # | |
| # The chain under test is the real thing end to end: | |
| # | |
| # mfp-virtual --usbip (emulated printer, speaks the USB/IP protocol) | |
| # | TCP :3240 | |
| # usbip attach + vhci_hcd (kernel exposes it as a local USB device) | |
| # | | |
| # libusb -> ipp-usb (discovers the device, tunnels HTTP over USB) | |
| # | |
| # What we assert: | |
| # 1. ipp-usb discovers the emulated device (VID:PID dead:beaf). | |
| # 2. ipp-usb completes an HTTP-over-USB round-trip - the eSCL | |
| # ScannerCapabilities probe returns 200 OK from the simulator. | |
| # 3. A client request routed *through* ipp-usb's TCP listener reaches the | |
| # emulated device and comes back 200 OK (client -> ipp-usb -> USB). | |
| # 4. A real IPP Get-Printer-Attributes, sent through ipp-usb to the printer | |
| # path, returns successful-ok with the model's make-and-model. | |
| # | |
| # Notes: | |
| # * The emulator is driven by an example MFP model (Kyocera ECOSYS M2040dn) | |
| # shipped in go-mfp, which provides both the eSCL (scanner) and IPP | |
| # (printer) endpoints, so both the scan and print paths are exercised. | |
| # * The go-mfp commit is pinned for reproducibility - bump GO_MFP_REF to | |
| # pick up newer emulator behaviour. | |
| # ============================================================================= | |
| name: Emulator Test | |
| on: | |
| push: | |
| branches: | |
| - '**' | |
| pull_request: | |
| branches: | |
| - '**' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| # go-mfp (the IPP-over-USB emulator) - pinned for reproducibility. | |
| GO_MFP_REPO: https://github.com/OpenPrinting/go-mfp.git | |
| GO_MFP_REF: 7e0ec8c4b411a111a1cee631ba3cc3c48a3a5403 | |
| # Example MFP model shipped in go-mfp (provides the IPP + eSCL endpoints). | |
| GO_MFP_MODEL: modeling/examples/Kyocera-ECOSYS-M2040dn.py | |
| # Build deps for ipp-usb (libusb + avahi) and for the go-mfp emulator | |
| # (adds Python/JPEG/PNG for its cgo bits). usbutils/linux-tools provide | |
| # lsusb and the usbip client; avahi-daemon lets ipp-usb publish over DNS-SD; | |
| # cups-ipp-utils provides ipptool for the IPP round-trip assertion. | |
| APT_DEPS: >- | |
| gcc pkg-config make | |
| libusb-1.0-0-dev libavahi-client-dev | |
| libjpeg-dev libpng-dev python3-dev | |
| linux-tools-generic linux-tools-common linux-tools-virtual | |
| usbutils avahi-daemon cups-ipp-utils | |
| jobs: | |
| emulator-test: | |
| name: ipp-usb vs. virtual IPP-over-USB printer | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out ipp-usb | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: stable | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update -o Acquire::Retries=3 | |
| sudo apt-get install -y -o Acquire::Retries=3 ${{ env.APT_DEPS }} | |
| - name: Load the USB/IP kernel module (vhci_hcd) | |
| run: | | |
| # The virtual device is attached through the vhci_hcd driver. On | |
| # GitHub-hosted runners the module lives in linux-modules-extra for | |
| # the running kernel; install it on demand if the first load fails. | |
| if ! sudo modprobe vhci-hcd 2>/dev/null; then | |
| sudo apt-get install -y -o Acquire::Retries=3 \ | |
| "linux-modules-extra-$(uname -r)" | |
| sudo modprobe vhci-hcd | |
| fi | |
| lsmod | grep -q vhci_hcd | |
| echo "vhci_hcd loaded." | |
| - name: Put the usbip client on PATH | |
| run: | | |
| # Ubuntu ships the usbip client inside linux-tools, not as a | |
| # standalone package. It is a userspace tool and works regardless | |
| # of the running kernel version. | |
| usbip_bin="$(ls /usr/lib/linux-tools-*/usbip 2>/dev/null | head -1)" | |
| test -n "$usbip_bin" | |
| sudo ln -sf "$usbip_bin" /usr/local/bin/usbip | |
| usbip version | |
| - name: Build ipp-usb | |
| run: | | |
| go build -tags nethttpomithttp2 -mod=vendor -o ipp-usb . | |
| ./ipp-usb -h >/dev/null 2>&1 || true | |
| - name: Build the go-mfp emulator (mfp-virtual) | |
| run: | | |
| git clone "${GO_MFP_REPO}" go-mfp | |
| git -C go-mfp checkout --quiet "${GO_MFP_REF}" | |
| ( cd go-mfp && go build -o mfp-virtual ./cmd/mfp-virtual ) | |
| test -x go-mfp/mfp-virtual | |
| - name: Start the emulator and attach it as a USB device | |
| run: | | |
| # Start the emulated IPP-over-USB printer (USB/IP server on :3240), | |
| # driven by the example MFP model (IPP printer + eSCL scanner). | |
| ./go-mfp/mfp-virtual -m "go-mfp/${GO_MFP_MODEL}" --usbip -d \ | |
| > emulator.log 2>&1 & | |
| echo $! | sudo tee /tmp/emulator.pid >/dev/null | |
| # Wait for the USB/IP server to advertise the device. | |
| for i in $(seq 1 30); do | |
| if usbip list -r localhost 2>/dev/null | grep -q '1-1'; then | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| usbip list -r localhost | |
| # Attach it - now it is a real local USB device. | |
| sudo usbip attach -r localhost -b 1-1 | |
| sleep 2 | |
| lsusb | |
| if ! lsusb | grep -qi 'dead:beaf'; then | |
| echo "::error::emulated printer did not attach as a USB device" | |
| cat emulator.log | |
| exit 1 | |
| fi | |
| echo "Virtual IPP-over-USB printer attached." | |
| - name: Start DNS-SD stack (avahi) for ipp-usb | |
| run: | | |
| sudo systemctl start dbus || sudo service dbus start || true | |
| sudo systemctl start avahi-daemon || sudo service avahi-daemon start || true | |
| - name: Run ipp-usb against the emulated printer | |
| run: | | |
| sudo mkdir -p /var/ipp-usb/dev | |
| # Run ipp-usb in debug mode (console logging) in the background, | |
| # pointed at the repo's own conf + quirks so no /etc install is | |
| # needed. It hot-plug-discovers the attached virtual printer. | |
| sudo ./ipp-usb debug \ | |
| -path-conf-files-srch "$PWD" \ | |
| -path-quirks-files-srch "$PWD/ipp-usb-quirks" \ | |
| > ippusb.log 2>&1 & | |
| echo $! | sudo tee /tmp/ippusb.pid >/dev/null | |
| # Wait (up to 40s) for discovery + the HTTP-over-USB probe. | |
| ok=0 | |
| for i in $(seq 1 40); do | |
| if grep -q 'ScannerCapabilities - 200 OK' ippusb.log; then | |
| ok=1 | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| echo "===================== ipp-usb log =====================" | |
| cat ippusb.log | |
| echo "=======================================================" | |
| # Assertion 1: ipp-usb found the emulated device. | |
| if ! grep -q 'Found new device. VID:PID = dead:beaf' ippusb.log; then | |
| echo "::error::ipp-usb did not discover the emulated printer" | |
| exit 1 | |
| fi | |
| # Assertion 2: an HTTP request was tunnelled over USB and answered. | |
| if [ "$ok" -ne 1 ]; then | |
| echo "::error::HTTP-over-USB round-trip did not complete (no 200 OK)" | |
| exit 1 | |
| fi | |
| echo "OK: ipp-usb discovered the printer and completed an HTTP-over-USB round-trip." | |
| # Assertion 3 - done in THIS step so the background ipp-usb is still | |
| # running (a backgrounded process does not survive into the next step). | |
| # Route a client request *through* ipp-usb's TCP listener: | |
| # client -> ipp-usb (TCP) -> USB -> emulator | |
| # The device port comes from http-min-port (default 60000); prefer the | |
| # persisted state file, fall back to the debug log, then to 60000. | |
| port="$(sudo grep -hoE 'http-port[[:space:]]*=[[:space:]]*[0-9]+' \ | |
| /var/ipp-usb/dev/* 2>/dev/null | grep -oE '[0-9]+' | head -1)" | |
| port="${port:-$(grep -oE 'localhost:[0-9]+' ippusb.log | head -1 | cut -d: -f2)}" | |
| port="${port:-60000}" | |
| # Use the "localhost" hostname, not 127.0.0.1: ipp-usb 302-redirects | |
| # IP-address requests to the hostname (it keys per-client auth off the | |
| # Host header). -L follows the redirect as a safety net. | |
| echo "Querying ipp-usb on localhost:${port}" | |
| code=000 | |
| for i in $(seq 1 10); do | |
| code="$(curl -sL -o caps.xml -w '%{http_code}' \ | |
| "http://localhost:${port}/eSCL/ScannerCapabilities" || echo 000)" | |
| [ "$code" = "200" ] && break | |
| sleep 1 | |
| done | |
| echo "HTTP status: ${code}" | |
| head -c 400 caps.xml || true | |
| echo | |
| if [ "$code" != "200" ] || ! grep -qi 'ScannerCapabilities' caps.xml; then | |
| echo "::error::client request through ipp-usb did not succeed" | |
| exit 1 | |
| fi | |
| echo "OK: client -> ipp-usb -> USB round-trip returned 200 OK." | |
| # Assertion 4 - drive the IPP *print* path end to end. Send a real | |
| # Get-Printer-Attributes through ipp-usb to /ipp/print; require the | |
| # standard ipptool test to PASS (status successful-ok) and the | |
| # response to carry the model's make-and-model. | |
| echo "Running ipptool Get-Printer-Attributes on ipp://localhost:${port}/ipp/print" | |
| if ! ipptool -tv "ipp://localhost:${port}/ipp/print" \ | |
| get-printer-attributes.test > ipptool.log 2>&1; then | |
| echo "::error::IPP Get-Printer-Attributes through ipp-usb failed" | |
| cat ipptool.log | |
| exit 1 | |
| fi | |
| cat ipptool.log | |
| if ! grep -q 'ECOSYS M2040dn' ipptool.log; then | |
| echo "::error::IPP response did not carry the expected printer model" | |
| exit 1 | |
| fi | |
| echo "OK: IPP Get-Printer-Attributes round-trip returned the Kyocera model." | |
| - name: Collect logs on failure | |
| if: failure() | |
| run: | | |
| echo "----- emulator.log -----"; cat emulator.log 2>/dev/null || true | |
| echo "----- ippusb.log -----"; cat ippusb.log 2>/dev/null || true | |
| echo "----- ipptool.log -----"; cat ipptool.log 2>/dev/null || true | |
| echo "----- usbip port -----"; usbip port 2>/dev/null || true | |
| echo "----- lsusb -----"; lsusb 2>/dev/null || true | |
| - name: Tear down | |
| if: always() | |
| run: | | |
| sudo kill "$(cat /tmp/ippusb.pid 2>/dev/null)" 2>/dev/null || true | |
| sudo usbip detach -p 00 2>/dev/null || true | |
| kill "$(cat /tmp/emulator.pid 2>/dev/null)" 2>/dev/null || true |