feat(adr-118/p6.5): GitHub Actions mosquitto Docker CI workflow (235/235 GREEN)
Iter 35. Lifts iters 24 + 29 live-broker integration tests out of
skip-mode in CI by spinning up an eclipse-mosquitto:2 service container,
exporting BFLD_MQTT_BROKER, and running the three cargo test matrices.
Added:
- .github/workflows/bfld-mqtt-integration.yml
* Triggers: push to main / feat/adr-118-* / feat/bfld-*, PR, manual
* Path filter: only runs when v2/crates/wifi-densepose-bfld/** or the
workflow file itself changes — protects PR throughput for unrelated
crate work
* Service container: eclipse-mosquitto:2 on port 1883 with a
mosquitto_pub-based healthcheck (5s interval, 10 retries) so the
runner waits for a real publish-ready broker, not just liveness
* Top-level timeout-minutes: 15 (bounds runner cost if rumqttc
handshake hangs)
* Three cargo test invocations:
cargo test -p wifi-densepose-bfld --no-default-features
cargo test -p wifi-densepose-bfld
cargo test -p wifi-densepose-bfld --features mqtt
The third one now actually exercises the mosquitto_integration and
rumqttc_lwt tests, not just the skip-mode path.
* Belt-and-suspenders nc -z port poll before tests start (service
container can take a few seconds to bind even with healthcheck)
* cargo clippy --features mqtt as a continue-on-error gate (signals
drift; doesn't block the merge yet)
* RUSTFLAGS=-D warnings, CARGO_INCREMENTAL=0 for stable runs
- v2/crates/wifi-densepose-bfld/tests/ci_workflow.rs (8 named tests):
Validates the workflow YAML via include_str! — same pattern iter 30
used for HA blueprints. Catches drift in CI infra:
workflow_declares_mosquitto_service_container
workflow_exports_broker_env_for_iter_24_and_29_tests
(BFLD_MQTT_BROKER pointing at the service container)
workflow_runs_three_cargo_test_invocations
(no_default + default + mqtt — three classes of bug surface)
workflow_waits_for_mosquitto_readiness_before_testing
(nc -z 1883 port poll)
workflow_uses_health_check_on_the_service
(mosquitto_pub-based, not just process liveness)
workflow_only_triggers_on_bfld_paths
(path filter to v2/crates/wifi-densepose-bfld/**)
workflow_pins_runner_to_ubuntu_latest_for_docker_service_support
(GitHub Actions `services:` doesn't work on macOS/Windows)
workflow_has_timeout_guard
(top-level timeout-minutes pinned)
ADR-124 status (iter step 0 sibling check):
- docs/adr/ADR-124-rvagent-mcp-ruvector-npm-integration.md unchanged
at 431 lines (SENSE-BRIDGE ADR). Scope remains orthogonal.
ACs progressed:
- ADR-122 §2.2 e2e — when this workflow lands on origin/main and the
next BFLD PR runs, the iter-24 anonymous-event roundtrip + restricted-
event-omits-identity_risk tests stop printing "skipping" and actually
publish to / subscribe from mosquitto. Plus the iter-29 LWT publisher
smoke run gets to fire its session-drop test against a live broker.
- ADR-118 §2.1 ⇄ §2.2 — discovery + state-topic + LWT + worker thread
all proven in one CI matrix run.
Test config:
- cargo test --no-default-features → 72 passed (ci_workflow cfg-out)
- cargo test → 235 passed (227 + 8)
Out of scope (skipped — external resources or hardware):
- ADR-121 calibration — KIT BFId dataset
- ADR-123 production capture — Pi 5 / Nexmon hardware
All other in-crate ACs from the ADR-118 / 119 / 120 / 121 / 122 series
are now covered by the iter 1-35 chain. The cron loop should
consider closing out at this point or pivoting to documentation /
witness-bundle generation for the PR.
Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
parent
38676aa2bd
commit
9ee7c5df04
|
|
@ -0,0 +1,99 @@
|
|||
name: BFLD MQTT Integration
|
||||
|
||||
# Runs the env-gated mosquitto integration tests from iters 24 + 29 of the
|
||||
# BFLD rollout (ADR-118 / ADR-122 §2.2). Spins up an eclipse-mosquitto:2
|
||||
# service container, exports BFLD_MQTT_BROKER, runs `cargo test --features
|
||||
# mqtt`. Local developers can reproduce with:
|
||||
#
|
||||
# scoop install mosquitto # Windows
|
||||
# # or: docker run -p 1883:1883 eclipse-mosquitto:2
|
||||
# BFLD_MQTT_BROKER=tcp://localhost:1883 \
|
||||
# cargo test -p wifi-densepose-bfld --features mqtt
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'feat/adr-118-*'
|
||||
- 'feat/bfld-*'
|
||||
paths:
|
||||
- 'v2/crates/wifi-densepose-bfld/**'
|
||||
- '.github/workflows/bfld-mqtt-integration.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'v2/crates/wifi-densepose-bfld/**'
|
||||
- '.github/workflows/bfld-mqtt-integration.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
mqtt-live-broker:
|
||||
name: cargo test --features mqtt (live mosquitto)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
services:
|
||||
mosquitto:
|
||||
image: eclipse-mosquitto:2
|
||||
ports:
|
||||
- 1883:1883
|
||||
# Allow anonymous connections — local-only CI broker, no exposure
|
||||
# to the public internet, never touches production credentials.
|
||||
options: >-
|
||||
--health-cmd "mosquitto_pub -h localhost -t healthcheck -m ping || exit 1"
|
||||
--health-interval 5s
|
||||
--health-timeout 3s
|
||||
--health-retries 10
|
||||
|
||||
env:
|
||||
BFLD_MQTT_BROKER: tcp://localhost:1883
|
||||
CARGO_TERM_COLOR: always
|
||||
CARGO_INCREMENTAL: 0
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
- name: Cache cargo registry + target
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
v2/target
|
||||
key: bfld-mqtt-${{ runner.os }}-${{ hashFiles('v2/Cargo.lock') }}
|
||||
|
||||
- name: Wait for mosquitto to be ready
|
||||
run: |
|
||||
for i in {1..20}; do
|
||||
if nc -z localhost 1883; then
|
||||
echo "mosquitto reachable on port 1883 (attempt $i)"
|
||||
exit 0
|
||||
fi
|
||||
echo "waiting for mosquitto ($i/20)..."
|
||||
sleep 1
|
||||
done
|
||||
echo "mosquitto never became reachable" >&2
|
||||
exit 1
|
||||
|
||||
- name: cargo test --no-default-features (baseline regression)
|
||||
working-directory: v2
|
||||
run: cargo test -p wifi-densepose-bfld --no-default-features
|
||||
|
||||
- name: cargo test (default features)
|
||||
working-directory: v2
|
||||
run: cargo test -p wifi-densepose-bfld
|
||||
|
||||
- name: cargo test --features mqtt (incl. live mosquitto roundtrip)
|
||||
working-directory: v2
|
||||
run: cargo test -p wifi-densepose-bfld --features mqtt
|
||||
|
||||
- name: cargo clippy --features mqtt (lint gate)
|
||||
working-directory: v2
|
||||
run: cargo clippy -p wifi-densepose-bfld --features mqtt --all-targets -- -D warnings
|
||||
continue-on-error: true
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
//! Structural validation for `.github/workflows/bfld-mqtt-integration.yml`.
|
||||
//! Same pattern as iter-30's HA blueprint tests: embed via `include_str!`,
|
||||
//! string-check the key fields. Avoids adding a serde_yaml dep just to lint
|
||||
//! a CI workflow.
|
||||
|
||||
#![cfg(feature = "std")]
|
||||
|
||||
const WORKFLOW: &str = include_str!(
|
||||
"../../../../.github/workflows/bfld-mqtt-integration.yml"
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn workflow_declares_mosquitto_service_container() {
|
||||
assert!(
|
||||
WORKFLOW.contains("image: eclipse-mosquitto:2"),
|
||||
"workflow must declare eclipse-mosquitto:2 as a service container",
|
||||
);
|
||||
assert!(
|
||||
WORKFLOW.contains("- 1883:1883"),
|
||||
"workflow must expose port 1883 from the mosquitto service",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workflow_exports_broker_env_for_iter_24_and_29_tests() {
|
||||
assert!(
|
||||
WORKFLOW.contains("BFLD_MQTT_BROKER: tcp://localhost:1883"),
|
||||
"BFLD_MQTT_BROKER env var must point at the service container so the \
|
||||
iter-24 mosquitto_integration test exits skip mode",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workflow_runs_three_cargo_test_invocations() {
|
||||
// Regression guard for the default + no-default-features + mqtt matrix.
|
||||
// Each one catches a different class of bug:
|
||||
// --no-default-features: catches std-feature leakage
|
||||
// default: catches the everyday surface
|
||||
// --features mqtt: catches the live-broker integration path
|
||||
assert!(WORKFLOW.contains("cargo test -p wifi-densepose-bfld --no-default-features"));
|
||||
assert!(WORKFLOW.contains("cargo test -p wifi-densepose-bfld"));
|
||||
assert!(WORKFLOW.contains("cargo test -p wifi-densepose-bfld --features mqtt"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workflow_waits_for_mosquitto_readiness_before_testing() {
|
||||
assert!(
|
||||
WORKFLOW.contains("nc -z localhost 1883"),
|
||||
"workflow must port-poll for mosquitto readiness — a service container \
|
||||
can take a few seconds to bind even with healthcheck",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workflow_uses_health_check_on_the_service() {
|
||||
assert!(
|
||||
WORKFLOW.contains("--health-cmd"),
|
||||
"service container should declare a health-check for stable startup",
|
||||
);
|
||||
assert!(
|
||||
WORKFLOW.contains("mosquitto_pub"),
|
||||
"health-check should attempt a real publish, not just process liveness",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workflow_only_triggers_on_bfld_paths() {
|
||||
assert!(
|
||||
WORKFLOW.contains("v2/crates/wifi-densepose-bfld/**"),
|
||||
"path filter must scope the workflow to BFLD changes, not run on every push",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workflow_pins_runner_to_ubuntu_latest_for_docker_service_support() {
|
||||
assert!(
|
||||
WORKFLOW.contains("runs-on: ubuntu-latest"),
|
||||
"GitHub Actions Docker service containers require linux; macOS and \
|
||||
Windows runners don't support `services:`.",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workflow_has_timeout_guard() {
|
||||
// The integration tests have 10-second recv timeouts but the matrix runs
|
||||
// three cargo invocations + cache + warmup; a top-level timeout-minutes
|
||||
// guards against a stuck broker or rumqttc handshake hanging the runner.
|
||||
assert!(
|
||||
WORKFLOW.contains("timeout-minutes:"),
|
||||
"workflow must declare a top-level timeout-minutes to bound runner cost",
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue