diff --git a/docs/README.md b/docs/README.md index 3079c9d..230f1a7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,11 +7,13 @@ A Flutter-based Android GUI wrapper for iperf3, the popular network performance ``` lib/ # Flutter/Dart application layer ├── main.dart # Composition root: picks the Iperf3Runner impl +├── main_headless.dart # Runs a test with no widgets (see Layering) ├── domain/ # Pure Dart — no Flutter import │ ├── models/ │ │ ├── test_configuration.dart # Server, port, duration, interval, parallel streams │ │ ├── iperf3_result.dart # Raw output, exit code, stopped flag -│ │ └── iperf3_event.dart # Parsed --json-stream reports +│ │ ├── iperf3_event.dart # Parsed --json-stream reports +│ │ └── iperf3_session.dart # One run accumulated: samples, totals, stats │ └── services/ │ └── iperf3_runner.dart # The contract the UI depends on ├── data/ # Transport — flutter/services only @@ -69,6 +71,27 @@ tree against an in-memory runner with no MethodChannel, native library or device — and what keeps a test double at five stable members instead of mirroring the transport's whole surface. +**The core does not need the UI.** What happened during a run is accumulated by +`Iperf3Session` in the domain layer — samples, totals, errors, and the mean, +peak and retransmit figures over them. The view model holds no run data of its +own and the screen derives no numbers; both read the session. Replacing the +presentation layer therefore means rewriting rendering, not re-deriving results. + +`lib/main_headless.dart` is the standing proof: it runs a full test through +`Iperf3Service` and `Iperf3Session` with `WidgetsFlutterBinding` but no +`runApp` — no widget tree, no render surface. If the run path ever starts +needing the UI, it stops working. + +```bash +flutter run -t lib/main_headless.dart \ + --dart-define=IPERF_SERVER=192.168.2.182 --dart-define=IPERF_STREAMS=4 +``` + +Use it when a figure has to be trustworthy. A 4-stream local run reports +**30.2% local CPU headless against 79.9% through the UI** — the phone is near +CPU-bound at gigabit rates, so a repainting transcript measurably depresses +throughput. Numbers taken through the UI are pessimistic. + `test/architecture_test.dart` enforces all of this by reading the actual imports under `lib/`, including a check that no fourth layer directory has appeared unnoticed. Change the layering there when the layering should change;