Skip to content

TEST RESULTS

Stack test results

Live verification of relay-edge + relay-pubsub + Relay (+ Zynera) on a co-deployed lab stack.

← Docs hub · Integration guide · Event matrix · Browser docs

Last re-run: 2026-08-29 · Outcome: all gates PASS on labs 212 (:8443) and 175 (:18080)

Path Script Result
Unit tests go test ./... PASS
Smoke smoke.sh · smoke-firewater.sh · smoke-remote-edge.sh · smoke-fleet.sh PASS (also in GitHub Actions CI)
Gateway stack (212) e2e-stack.sh + config/lab-stack.env PASS — farm 10/10 Accept + 5/5 Act · FW 5 · remote-edge 6 · fleet 6
Gateway stack (175) e2e-stack.sh + config/lab-stack-175.env PASS — same matrix; Relay on :18080
Direct Relay e2e-direct-stack.sh PASS — farm 10 · firewater 13 · remote-edge 6 · fleet 6
CI / release Actions CI + tag Release PASS — v0.1.1 binaries + ghcr.io/zyvorai/relay-edge

Act wiring (required for Farm Act): Relay must call a reachable pubsub /v1/actions (remote host URL if pubsub is not on the Relay box) with outbound RELAY_TLS_INSECURE when using self-signed TLS (relay#8bef494). Helper: scripts/lab-wire-relay-act.sh (defaults to co-located 127.0.0.1 — edit targets for remote pubsub).

CI note: GitHub Actions runs unit tests + the four smoke scripts against a mock Relay. Full gateway/direct matrices above remain lab-only (need live Relay + pubsub).


What we tested

End-to-end proof that all four event families from relay-edge reach Relay — via relay-pubsub (gateway) or direct POST /v1/events — plus Act via the pubsub Action Gateway (rpg_*) and optional Zynera Decision Records.

Layer Verified behaviour
relay-edge Farm seasons/sites + firewater plant + remote-edge NOC + fleet IoT simulators; stamp + publish
relay-pubsub 40-topic catalog; Pub/Sub REST → Relay; inbound /v1/actions for all controller targets
Relay Accept, notify, ack, act, verify for every family; Zynera awaiting_decision only when policy + Zynera configured
Zynera Decision Record create (Relay), human freeze Approved → act; Rejected → failed (optional)

Lab topology

Any service can be remote. From your workstation, always use host IPs in BASE / GATEWAY / EDGE — never 127.0.0.1 (that is the machine running the script).

Service URL pattern Repo
relay-edge https://<edge-host>:18086 relay-edge
relay-pubsub https://<pubsub-host>:8081 relay-pubsub
relay-pubsub console https://<pubsub-host>:8082/ relay-pubsub
Relay https://<relay-host>:8443 or :18080 relay
Zynera gateway http://<zynera-host>:30631 forge
Zynera UI (Zeus) http://<zynera-host>:30862 forge
Example lab Relay port Env template
<ephemeral-ip> (all-on-one) 8443 config/lab-stack.env
<ephemeral-ip> (all-on-one) 18080 config/lab-stack-175.env

Relay process env — Act targets must reach pubsub’s host (127.0.0.1 only when Relay and pubsub share a machine):

RELAY_TENANT=fasal-edge
RELAY_ACTION_TARGETS=farm-controller=https://<pubsub-host>:8081/v1/actions,\
firewater-controller=https://<pubsub-host>:8081/v1/actions,\
remote-edge-controller=https://<pubsub-host>:8081/v1/actions,\
fleet-controller=https://<pubsub-host>:8081/v1/actions
RELAY_TLS_INSECURE=1          # outbound action HTTPS to self-signed pubsub
RELAY_FORGE_BASE_URL=http://<zynera-host>:30631   # optional
RELAY_FORGE_API_KEY=<k8s zynera-api-gateway-secret>

pubsub and relay-edge share the same RELAY_AUTH_TOKEN (JWT from demo/demo login).

Set external URLs in config/lab-stack.env or config/lab-stack-175.env (from the matching .example).


How we tested

1. Prepare environment

git clone https://github.com/zyvorai/relay-edge.git && cd relay-edge
cp config/lab-stack.env.example config/lab-stack.env
# Edit BASE, GATEWAY, EDGE, ZYNERA_BASE for your lab host

Fill in config/lab-stack.env:

Variable Source
RELAY_AUTH_TOKEN curl -fsSk -X POST $BASE/v1/auth/login -d '{"username":"demo","password":"demo"}' → .token
ZYNERA_API_KEY kubectl -n zynera get secret zynera-api-gateway-secret -o jsonpath='{.data.api-key}' \| base64 -d

Ensure Relay has RELAY_FORGE_* and RELAY_TLS_INSECURE=1 (see above). After any Relay restart, re-sync pubsub:

# on lab host
sudo sed -i "s|^RELAY_AUTH_TOKEN=.*|RELAY_AUTH_TOKEN=$TOKEN|" /etc/relay-pubsub/relay-pubsub.env
sudo systemctl restart relay-pubsub

Redeploy relay-edge if needed:

RELAY_AUTH_TOKEN=$TOKEN ./scripts/deploy-remote.sh <HOST> [USER]

2. Health probe

set -a && source config/lab-stack.env && set +a
./scripts/stack-probe.sh

Checks: relay-edge /healthz, pubsub /healthz, Relay /healthz, Zynera POST /api/zeus/decisions probe.

3. Event matrix (integration gate)

./scripts/e2e-events-matrix.sh
Phase Cases Pass criteria
A. Farm 10 catalog types via gateway REST 5 critical → pol_critical_farm + ack + Act executed with rpg_* provider; 5 advisory → pol_advisory, notify-only
B. Firewater 5 scenarios New Relay event per type (firewater.*, edge.*)
C. Remote edge 6 scenarios (incl. drone_patrol) New Relay event per type (remote-edge.*)
D. Fleet 6 scenarios New Relay event per type (fleet.*)

4. Full stack + Zynera path

./scripts/e2e-zynera-stack.sh

Runs the event matrix (Phase A), then:

Phase Action
B Patch pol_critical_farm → decision_backend: forge (restored on exit)
C relay-edge farm publish irrigation.required
D Operator ack approve in Relay → awaiting_decision
E–F Zynera freeze Approved → Relay resumes → act/verify
G Second event → Zynera freeze Rejected → Relay failed

Skip flags:

  • ./scripts/stack-probe.sh --zynera-optional — when Zynera is not deployed
  • ./scripts/e2e-zynera-stack.sh --skip-matrix — Zynera path only

Without Zynera (tested 2026-08-28)

Most edge sites run relay-edge + relay-pubsub + Relay only — all four event families (farm, firewater/edge IoT, remote edge, fleet/multi-IoT), not farm alone. Zynera is optional for human Decision Records.

Plan

Step What Families Requires Zynera?
1 Health: edge, pubsub, Relay all No
2 Farm catalog via gateway REST farm (10 types, 5 Act) No
3 Firewater / edge IoT scenarios industrial plant + edge AI/comms No
4 Remote edge scenarios Starlink, Galleon, UAV, vision, IoT No
5 Fleet scenarios AMR, OT, energy, BMS, security, … No
6 Native ack → act (all stamped targets) farm · firewater · remote-edge · fleet No
7 Zynera freeze approve/reject farm (policy patch in e2e) Yes

Most edge sites run relay-edge + relay-pubsub + Relay only. Zynera is optional.

→ Stack without Zynera — architecture, sequence, state diagrams · Test results

Leave ZYNERA_BASE and ZYNERA_API_KEY empty in config/lab-stack.env. Do not set RELAY_FORGE_* on Relay unless you need step 5.

How to run

cp config/lab-stack.env.example config/lab-stack.env
# BASE, GATEWAY, EDGE, RELAY_AUTH_TOKEN only — leave ZYNERA_* blank

set -a && source config/lab-stack.env && set +a
./scripts/e2e-stack.sh

Alternative (same coverage):

./scripts/stack-probe.sh --zynera-optional
./scripts/e2e-events-matrix.sh
# or: ./scripts/e2e-zynera-stack.sh   # skips Zynera phases B–G automatically

Results (2026-08-28 morning — Accept + Act OK)

Script Result
stack-probe.sh --zynera-optional PASS — Zynera skipped
e2e-events-matrix.sh PASS — A farm 10/10 Accept + 5/5 Act · B firewater 5 · C remote-edge 5 · D fleet 6
e2e-stack.sh PASS — probe + matrix
e2e-zynera-stack.sh PASS — matrix only; Zynera path skipped

Re-run (2026-08-28 → 2026-08-29 — Act wiring fix + lab 175)

After Farm Act failed with tls: certificate signed by unknown authority, we redeployed Relay (RELAY_TLS_INSECURE=1 honored on the action HTTP client) and set action targets. Final verification 2026-08-29:

Lab Script Result
212 (:8443) e2e-stack.sh PASS — farm 10/10 Accept + 5/5 Act · FW 5 · remote-edge 6 · fleet 6
175 (:18080) e2e-stack.sh PASS — same matrix after Act TLS patch + JWT sync
both stack-probe.sh --zynera-optional PASS
212 e2e-direct-stack.sh PASS

Wire Act on a fresh lab:

# From a checkout of zyvorai/relay (commit 8bef494+), or copy action TLS patch from a working host:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o /tmp/relay-linux ./cmd/relay
RELAY_BIN=/tmp/relay-linux ./scripts/lab-wire-relay-act.sh <HOST>
# then sync pubsub JWT + gateway deploy + e2e-stack.sh

If ZYNERA_BASE is set but Zynera is down, e2e-zynera-stack.sh still PASS after the event matrix (Zynera phases skipped with warning).


Direct Relay (tested 2026-08-28)

relay-edge → Relay without relay-pubsub (GATEWAY_BASE_URL empty on edge). Accept-only gate — Act requires pubsub Action Gateway.

How to run

cp config/lab-direct.env.example config/lab-direct.env
# BASE, EDGE, RELAY_AUTH_TOKEN

RELAY_EDGE_DIRECT=1 RELAY_AUTH_TOKEN=<jwt> ./scripts/deploy-remote.sh <HOST> [USER]

set -a && source config/lab-direct.env && set +a
./scripts/stack-probe.sh --direct
./scripts/e2e-direct-relay.sh
# or: ./scripts/e2e-direct-stack.sh

Restore gateway mode after test:

RELAY_AUTH_TOKEN=<jwt> ./scripts/deploy-remote.sh <HOST> [USER]

Scenario coverage

Section Cases Pass criteria
0. Guard open season publish.path == "relay"
A. Farm 10 types via season API Accept in Relay; path relay
B. Firewater 13 scenarios New Relay event per type
C. Remote edge 6 scenarios (+ 2 readings-only skip) New Relay event per type
D. Fleet 6 scenarios (+ 2 readings-only skip) New Relay event per type

Results (2026-08-29, lab)

Script Result
stack-probe.sh --direct PASS
e2e-direct-relay.sh PASS — farm 10 · firewater 13 · remote-edge 6 · fleet 6
e2e-direct-stack.sh PASS when Relay stays up for the full run

Transient: Relay briefly unreachable mid-matrix once (curl: Couldn't connect on :8443); re-run after recovery was full PASS. Always restore gateway mode after direct tests (deploy-remote.sh without RELAY_EDGE_DIRECT).


With Zynera (tested 2026-08-28)

stack-probe.sh

  ok  relay-edge $EDGE/healthz
  ok  relay-pubsub $GATEWAY/healthz
  ok  Relay $BASE/healthz
  ok  Zynera $ZYNERA_BASE/api/zeus/decisions
PASS: stack probe

e2e-events-matrix.sh

Section Result
A. Farm catalog 10/10 Accept; 5/5 Act via rpg_*
B. Firewater / edge 5/5 events in Relay
C. Remote edge 6/6 events in Relay (incl. drone_patrol)
D. Fleet 6/6 events in Relay

e2e-zynera-stack.sh

Phase Result
A. Event matrix PASS
B. Policy → forge backend PASS (restored on exit)
C. relay-edge publish PASS
D. ack → awaiting_decision PASS
E–F. Zynera Approved → act PASS (verifying / action_pending)
G. Zynera Rejected → failed PASS

Exit code: 0


Issues hit during verification

Symptom Fix
Gateway publish 500 / 401 Re-sync RELAY_AUTH_TOKEN on pubsub after Relay restart; restart relay-pubsub
Farm Act failed — TLS unknown authority Relay action client must skip verify when RELAY_TLS_INSECURE=1 (relay#8bef494); older trees may lack the patch — sync from a working lab or rebuild. Helper: lab-wire-relay-act.sh
Farm Act failed — mock / wrong host Point all controllers at the reachable pubsub /v1/actions (not mock://; not laptop 127.0.0.1 if pubsub is remote)
e2e hits wrong machine BASE/GATEWAY/EDGE must be remote host URLs when testing from a laptop — 127.0.0.1 is your laptop
Action circuit breaker open Reset by fixing TLS + restarting Relay; publish fresh catalog events
publish.path=gateway when expecting direct Set GATEWAY_BASE_URL= explicitly (unset ≠ direct); use RELAY_EDGE_DIRECT=1 deploy
Edge left in direct mode after direct tests Redeploy without RELAY_EDGE_DIRECT before gateway e2e
Relay blip mid long matrix (:8443 / :18080 down) Wait for healthz; re-run matrix
Wrong Relay port on 175 Use :18080 (config/lab-stack-175.env), not :8443
relay-edge unreachable on :18086 ./scripts/deploy-remote.sh <HOST>
Zynera ack curl SSL error Scripts use RELAY_TLS_INSECURE=1 / curl -k for Relay HTTPS
Policy patch JSON error Fetch policy via GET /v1/policies list (no get-by-id route)

Reproduce on any lab

# 0) If Farm Act fails with TLS unknown authority / mock targets:
#    RELAY_BIN=/path/to/linux-amd64-relay ./scripts/lab-wire-relay-act.sh <HOST>
#    then re-sync pubsub RELAY_AUTH_TOKEN and restart relay-pubsub

export BASE=https://<relay-host>:8443          # or :18080 on lab 175
export GATEWAY=https://<gateway-host>:8081
export EDGE=https://<edge-host>:18086
export ZYNERA_BASE=http://<zynera-host>:30631   # optional
export ZYNERA_API_KEY=<secret>                 # optional
export RELAY_AUTH_TOKEN=<jwt>
export RELAY_TLS_INSECURE=1

./scripts/stack-probe.sh --zynera-optional
./scripts/e2e-stack.sh

# Lab 175 shortcut:
#   set -a && source config/lab-stack-175.env && set +a && ./scripts/e2e-stack.sh

# Direct (no pubsub) — then restore gateway deploy without RELAY_EDGE_DIRECT
RELAY_EDGE_DIRECT=1 RELAY_AUTH_TOKEN=<jwt> ./scripts/deploy-remote.sh <HOST>
./scripts/e2e-direct-stack.sh
RELAY_AUTH_TOKEN=<jwt> ./scripts/deploy-remote.sh <HOST>

Unit / smoke tests (no Relay required for smoke; unit always). Also run in GitHub Actions CI:

go test ./...
# or: make vet test
EDGE=http://127.0.0.1:18086 make smoke-all
# equivalent:
EDGE=http://127.0.0.1:18086 ./scripts/smoke.sh
EDGE=http://127.0.0.1:18086 ./scripts/smoke-firewater.sh
EDGE=http://127.0.0.1:18086 ./scripts/smoke-remote-edge.sh
EDGE=http://127.0.0.1:18086 ./scripts/smoke-fleet.sh

Repo Commit Change
relay-edge 0dfc219 CI gaps closed: fleet smoke, tag-gated release, GHCR, /readyz//version, systemd
relay-edge 7588d7f Initial GitHub Actions CI + first release v0.1.0
relay-edge b206e8f lab-wire-relay-act.sh; document full PASS after Act TLS fix
relay-edge 1247041 e2e-direct-stack.sh, drone_patrol in gateway matrix, gateway env tests
relay-edge 70e4742 Direct Relay e2e script, expanded scenarios, GATEWAY_BASE_URL= fix
relay 8bef494 RELAY_TLS_INSECURE for outbound action gateway

Topic Document
Simulate all one-liner INTEGRATION.md — Simulate all
Direct Relay path RELAY.md — Try direct mode
Event type tables EVENT_MATRIX.md
Configuration / empty gateway CONFIGURATION.md
Lab ports & deploy DEPLOYMENT.md
CI / releases / GHCR DEPLOYMENT.md — CI and releases
Browser summary /ui/docs.html