3 Commits

Author SHA1 Message Date
YueGuobin
e0329ceee6
test(e2e): give the dynamips routers a detected idle-PC
Without one every c7200 busy-waits a full CPU core for the whole scenario
-- the tests create raw nodes and no template supplies a value (measured:
constant ~100 % per router, up to ~6 minutes per dynamips scenario).

harness.dynamips_idlepc() detects a value through the controller's
auto_idlepc endpoint (the GUI idle-PC finder path: a throwaway project
boots the image, candidate values are validated by measuring actual CPU
usage) and caches it in ~/.cache/gns3-e2e/idlepc.json keyed by the image
checksum, so the cost (~100 s here) is paid once per image, not per run.
GNS3_E2E_IDLEPC overrides detection; any failure returns None and the
scenarios run without one rather than fail on a CPU optimisation.

All four scenarios that boot c7200 routers (dynamips kernel/relay,
ethernet switch kernel/relay) pass the value at creation. Live: detected
0x60189234 for the M11 image (238 s first run including detection); the
routers drop from ~100 % during boot to 3-8 % steady (sampled per
process), and a re-run reports the cached value with no detection.
2026-10-06 00:21:10 +08:00
YueGuobin
30cb7119e5
test(e2e): assert the L2-anchor spec's server-side guarantees
The spec's gns3-server alignment section promised three assertions the
suites never carried; they land in harness.py and run in every kernel
scenario (plus the relay controls' anchor checks):

- E.1 assert_pure_l2: anchors and bridges carry no L3 identity (addrgenmode
  none, no address in /proc/net/if_inet6, no ip -o -4 addr) -- the kernel
  scenarios' anchors and per-link/switch bridges, relay-mode anchors and
  the switch's relay TAPs alike (hardening is a creation-time property,
  not a datapath one);
- E.2 assert_idle_silence (Dynamips suite): guest interfaces shut to
  silence IOS's own CDP/keepalives, settle 2.5 s, then a 5 s window of
  zero traffic over both anchors and the per-link bridge;
- assert_forwarding: every attached port reports brport/state == 3 -- a
  bridge left DOWN keeps its ports disabled and forwards nothing, with no
  error anywhere; the assertion is the only signal.

harness.l2only_supported() probes a throwaway uBridge once (link l2only
against a nonexistent device: 208 = command present, 202-Unknown command
= old build); without the command the assertions skip -- the spec's
degradation contract, mirroring the tc-capability skip.

The first live run caught a fifth-creator gap: the switch's relay port
TAPs (minted implicitly by bridge add_nio_tap) carried a live fe80::.
Delivered uBridge-side per the spec (fb72758: the transient TAP is
hardened at creation, attaches untouched); the server needed no change,
and the relay-control E.1 check is that creator's end-to-end coverage.
2026-10-06 00:21:10 +08:00
YueGuobin
5c2c8cdb0c
test(e2e): a live end-to-end suite, Dynamips as the first scenario
Live e2e verification moves into the repository instead of being rewritten
as a throwaway script every time: tests/e2e/ carries a shared harness (REST
client, isolated-instance lifecycle, a deliberately dumb IOS console
driver, host-side kernel inspection: bridge membership, tap admin state,
tc qdiscs) and each node type adds only its scenario module. The e2e marker
plus 'addopts = -m "not e2e"' keeps these privileged, image-dependent
tests out of normal runs; they are opt-in: pytest -m e2e tests/e2e -s.

The harness targets an existing server via GNS3_E2E_URL or starts an
isolated instance (own config dir — DB and paths follow it — on a free
port) and deletes its project afterwards (GNS3_E2E_KEEP=1 keeps it on
failure).

The first scenario drives two real c7200 routers on a real IOS image
through the REST API and the consoles: the kernel link is created while the
routers are stopped (deferred wiring), the per-link kernel bridge enslaves
exactly the two anchors, real ICMP crosses it, delay 100 shows netem on
both anchors and grows the RTT (~200 ms), suspend kills the traffic on an
admin-down anchor, capture writes a pcap of ICMP records, a serial link
between the same routers stays on the relay and still pings, delete/
re-create and stop/start leave the wiring consistent, and deleting the
project removes every anchor and bridge. A negative control runs the same
topology on an isolated relay-configured instance (no per-link bridge,
nothing enslaved, still pings).
2026-10-06 00:21:09 +08:00