From 8e49538e231223cada3bd5eaed87d8cb164b1954 Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Sun, 26 Jul 2026 12:08:55 +0530 Subject: [PATCH 1/2] ci: resolve ipp-usb TCP port via DNS-SD instead of the state file Both the snap and emulator tests scraped http-port from ipp-usb's private per-device state file to reach its TCP listener. Resolve it over DNS-SD (avahi-browse -r on _ipp._tcp) instead: the port comes from the advertised SRV record, so the test now asserts the port ipp-usb publishes is the port it serves. Keep the state-file/log scrape as a fallback so it cannot regress where browsing is unavailable; add avahi-utils to the deps. --- .github/workflows/emulator-test.yml | 27 ++++++++++++++++++++------- .github/workflows/snap-test.yml | 27 ++++++++++++++++++++------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/.github/workflows/emulator-test.yml b/.github/workflows/emulator-test.yml index 3409f61..52f5b2a 100644 --- a/.github/workflows/emulator-test.yml +++ b/.github/workflows/emulator-test.yml @@ -55,14 +55,15 @@ env: 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. + # lsusb and the usbip client; avahi-daemon lets ipp-usb publish over DNS-SD, + # avahi-utils (avahi-browse) lets the test resolve the advertised port 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 + usbutils avahi-daemon avahi-utils cups-ipp-utils jobs: emulator-test: @@ -194,10 +195,22 @@ jobs: # 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)" + # Resolve the port from DNS-SD (ipp-usb's public interface) rather + # than its private state file: avahi-browse -r gives the SRV record + # and field 9 of the parseable output is the port. This also asserts + # the port ipp-usb *advertises* is the port it serves. Retry a few + # seconds since publication can lag daemon start. + port="" + for i in $(seq 1 15); do + port="$(avahi-browse -rptk _ipp._tcp 2>/dev/null \ + | awk -F';' '/^=/{print $9; exit}')" + [ -n "$port" ] && break + sleep 1 + done + # Fall back to the private state file / debug log if DNS-SD did not + # resolve, so the assertion cannot regress where browsing is absent. + port="${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 diff --git a/.github/workflows/snap-test.yml b/.github/workflows/snap-test.yml index 7f3c543..18620b3 100644 --- a/.github/workflows/snap-test.yml +++ b/.github/workflows/snap-test.yml @@ -70,13 +70,14 @@ env: GO_MFP_MODEL: modeling/examples/Kyocera-ECOSYS-M2040dn.py # Host deps: the go-mfp emulator needs Python/JPEG/PNG for its cgo bits; # usbutils/linux-tools provide lsusb and the usbip client; avahi-daemon lets - # the confined snap publish over DNS-SD. The snap itself is built in an - # isolated LXD container, so its build deps are not installed here. + # the confined snap publish over DNS-SD, and avahi-utils (avahi-browse) lets + # the test resolve the advertised port over DNS-SD. The snap itself is built + # in an isolated LXD container, so its build deps are not installed here. APT_DEPS: >- gcc pkg-config make libjpeg-dev libpng-dev python3-dev linux-tools-generic linux-tools-common linux-tools-virtual - usbutils avahi-daemon + usbutils avahi-daemon avahi-utils jobs: snap-test: @@ -289,10 +290,22 @@ jobs: # Assertion C - route a client request *through* the confined daemon's # TCP listener: client -> ipp-usb (TCP) -> USB -> emulator. Resolve - # the per-device port from the state dir, fall back to the log, then - # to 60000. - port="$(sudo grep -rhoE 'http-port[[:space:]]*=[[:space:]]*[0-9]+' \ - "$dev_dir" 2>/dev/null | grep -oE '[0-9]+' | head -1)" + # the port from DNS-SD (ipp-usb's public interface) rather than the + # private state file: avahi-browse -r gives the SRV record and field 9 + # of the parseable output is the port. This also asserts that the + # port ipp-usb *advertises* is the port it actually serves. Retry a + # few seconds since publication can lag the daemon (re)start. + port="" + for i in $(seq 1 15); do + port="$(avahi-browse -rptk _ipp._tcp 2>/dev/null \ + | awk -F';' '/^=/{print $9; exit}')" + [ -n "$port" ] && break + sleep 1 + done + # Fall back to the private state file / log if DNS-SD did not resolve, + # so the assertion cannot regress where browsing is unavailable. + port="${port:-$(sudo grep -rhoE 'http-port[[:space:]]*=[[:space:]]*[0-9]+' \ + "$dev_dir" 2>/dev/null | grep -oE '[0-9]+' | head -1)}" port="${port:-$(sudo grep -rhoE 'localhost:[0-9]+' "$log_dir" 2>/dev/null | head -1 | cut -d: -f2)}" port="${port:-60000}" # Use the "localhost" hostname, not 127.0.0.1: ipp-usb 302-redirects From ccc50158364e09ddcfd0ab4130514c449725ddaa Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Sun, 26 Jul 2026 12:19:18 +0530 Subject: [PATCH 2/2] ci: log whether ipp-usb port came from DNS-SD or the fallback Make the DNS-SD resolution observable in the run so the assertion is visibly exercised (the resolved port can coincide with the fallback default, hiding which path won). --- .github/workflows/emulator-test.yml | 5 +++++ .github/workflows/snap-test.yml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/emulator-test.yml b/.github/workflows/emulator-test.yml index 52f5b2a..3aa86b2 100644 --- a/.github/workflows/emulator-test.yml +++ b/.github/workflows/emulator-test.yml @@ -207,6 +207,11 @@ jobs: [ -n "$port" ] && break sleep 1 done + if [ -n "$port" ]; then + echo "Resolved port ${port} from DNS-SD (_ipp._tcp SRV record)" + else + echo "::warning::DNS-SD did not resolve; falling back to state file/log" + fi # Fall back to the private state file / debug log if DNS-SD did not # resolve, so the assertion cannot regress where browsing is absent. port="${port:-$(sudo grep -hoE 'http-port[[:space:]]*=[[:space:]]*[0-9]+' \ diff --git a/.github/workflows/snap-test.yml b/.github/workflows/snap-test.yml index 18620b3..128efa7 100644 --- a/.github/workflows/snap-test.yml +++ b/.github/workflows/snap-test.yml @@ -302,6 +302,11 @@ jobs: [ -n "$port" ] && break sleep 1 done + if [ -n "$port" ]; then + echo "Resolved port ${port} from DNS-SD (_ipp._tcp SRV record)" + else + echo "::warning::DNS-SD did not resolve; falling back to state file/log" + fi # Fall back to the private state file / log if DNS-SD did not resolve, # so the assertion cannot regress where browsing is unavailable. port="${port:-$(sudo grep -rhoE 'http-port[[:space:]]*=[[:space:]]*[0-9]+' \