source: ntrip/trunk/BNC/tests/README.md

Last change on this file was 11127, checked in by stuerze, 3 days ago

test suite extended regardiing security aspects

File size: 8.6 KB
Line 
1# BNC regression tests
2
3Run BNC headless on fixed inputs and compare its outputs with stored reference
4outputs. No network access is needed.
5
6```
7tests/run_tests.py # all cases (parallel), exit code 1 on failure
8tests/run_tests.py ssr_ rinex_qc # only cases whose name contains a pattern
9tests/run_tests.py --list
10tests/run_tests.py --update NAME # accept current output as new reference
11 # (removes references of outputs no longer produced)
12```
13
14Build `./bnc` first. Each case runs in `tests/work/<case>/`,
15which has an `Input` symlink to `Example_Configs/Input` and an empty `Output`
16directory, so the example configurations run unchanged. On a failure, the
17full diff is at `tests/work/<case>/<output>.diff` and the exact command line
18is in `tests/work/<case>/command.txt`.
19
20## Layout
21
22| Path | Content |
23|---|---|
24| `run_tests.py` | runner; the `case.json` format is documented in its header |
25| `cases/<name>/case.json` | config, extra `-key` arguments, raw capture, outputs to compare |
26| `cases/<name>/expected/*.gz` | normalised reference outputs |
27| `data/*.raw` | short raw captures (BNC `rawOutFile` format) replayed via `--file` |
28| `tools/fakecaster.py` | local Ntrip caster recording an upload as a BNC raw file (case key `fakecaster`); optionally TLS and serving a stream |
29| `tools/bncraw.py` | `info` (streams, time span, RTCM3 message types), `slice` and `crs` (decode 1300/1301/1302) for raw captures |
30| `tools/mkcrafted.py` | writes `data/crafted_limits.raw`: crafted frames at the upper field limits |
31| `tools/ssr_harness.sh` | builds `tools/ssr_harness.cpp` with the SSR decoders under ASan/UBSan and runs it |
32| `tools/ssl_check.py` | TLS checks of the Ntrip 2s client and upload (not part of `run_tests.py`) |
33| `work/` | scratch output, not versioned |
34
35Before comparing, the runner removes content that changes with each run or
36BNC version: wall-clock log prefixes, `Start BNC` lines, the BNC version
37string, the RINEX `PGM / RUN BY / DATE` line, and the `Run by`/`Date` lines
38in reqc logs.
39
40## Cases
41
42* File-based examples: `rinex_concat`, `rinex_qc`, `sp3_compare`, `ppp_postproc`,
43 `ppp_osm` (04, 05, 21, 11, 12), plus the command-line variants `*_cli` and
44 `sp3_compare_exclude` (scripts 24, 23, 28). The QC cases use the 1 h BRUX
45 files instead of the full-day file.
46* `rinex_edit_minele`: Edit/Concatenate with a 10 deg elevation mask (1 h BRUX
47 files), covering the ephemeris selection for the elevation mask.
48* Stream replays of the real-time examples (`replay_*`), all from the 5 min
49 slice `data/wtzr_cnes_5min.raw` (BCEP00BKG0, WTZR00DEU0, SSRA00CNE1):
50 `replay_rinex_obs` (01, skeleton not mandatory as there is no caster offline),
51 `replay_rinex_eph` (02), `replay_feed_engine` (07, IP port disabled) and
52 `replay_save_sp3` (14, with SSRA00CNE1 instead of SSRA00BKG1).
53* `replay_save_sp3_has`: 14 with Galileo HAS (SSRA00EUH0) only; its epochs are
54 off the SP3/CLK sampling grid and are written at the preceding grid epoch.
55* Real-time PPP replays (`ppp_rt_*`) from 11 min slices of the CNES and WHU
56 captures (`data/wtzr_cnes_11min.raw`, `data/wtzr_whu_11min.raw`):
57 `ppp_rt_float` (08), `ppp_rt_quickstart` (10, NMEA port disabled), `ppp_rt_ar_cnes` (29) and `ppp_rt_ar_whu`
58 (30), compared exactly.
59* `ppp_rt_net` (09, two stations) and `ppp_rt_has` (13, Galileo HAS via
60 SSRA00EUH0) from `data/merged_260930_11min.raw`, a slice of two simultaneous
61 recordings merged by time (BCEP00BKG0, WTZR00DEU0, FFMJ00DEU0, SSRA00CNE1,
62 SSRA00EUH0).
63* Combination (`combi`, `combi_ppp`; 17 and 18 unchanged) from
64 `data/combi_261005_11min.raw` (SSRA00BKG1, SSRA00CNE1, SSRA00CHC1, BCEP00BKG0,
65 FFMJ00DEU0), upload to the caster disabled, SP3/CLK/BIA written to files.
66* `combi_multi`: 17 with the 7 ACs of an operational combination (BKG1, CHC1,
67 CNE1, GFZ1, GMV0, NRC0, SHA1; IGS-SSR and RTCM-SSR) from
68 `data/combi_multi_261002_5min.raw`. Covers legacy and erroneous epoch
69 encodings, missing reference-signal biases, inconsistent biases and
70 persistent outliers. The longest case (about 4 min).
71* `combi_refsig`: `combi` with non-default reference signals (`ssrRefSignals
72 C:1P&5P`): BDS clock referral and code biases from the Bias SINEX file on
73 C1P/C5P (generic DCB derivation), CLK/BIA and the combination log compared.
74* Upload (`upload_*`; 16, 19, 20) from `data/upload_rtnet_5min.raw` (RTNET engine
75 output + BCEP00BKG0): BNC uploads to a local fake caster
76 (`tools/fakecaster.py`, Ntrip 1/2, chunked), and a `post` step decodes the
77 received stream again: `upload_rtnet` (IGS-SSR encoding, SP3/CLK/BIA files,
78 decoded `.ssr`, CRS messages 1300/1302 decoded by `bncraw.py crs` in a
79 `tool` post step), `upload_eph` (RTCM3 ephemerides to RINEX nav) and
80 `upload_raw` (raw forwarding to RINEX nav). `upload_rtnet_rtcm` encodes the same input to RTCM-SSR
81 (message numbers 1057-1068, 1240-1270) and decodes it again.
82* SSR decoding (`ssr_*`): 3 min slices of real streams replayed through
83 `03_BrdcCorr.bnc`. They compare the `.ssr` files and the `BNC_DEBUG_SSR`
84 stderr trace. On a build without that trace, the trace comparison is
85 reported as SKIP.
86 * `ssr_igs_SSRA00CNE1`: IGS-SSR 4076, `SsrCorrIgs`
87 * `ssr_rtcm_SSRA00CNE0`, `ssr_rtcm_WHU1_OSBC`: RTCM 1059-1270; these test
88 whichever class `RTCM3Decoder.cpp` selects for non-4076 SSR.
89* `ssr_weekchange`: 2 min across the GPS week change (SSRA00CNE1, SSRA00CHC1);
90 corrections of Saturday received after midnight must keep their epochs.
91* `ssr_qc`, `ssr_qc_select`: SSR QC (31_SsrQC, one file per stream, 5 min interval;
92 all streams resp. `ssrQcStreams SSRA00CNE1,SSRA00GMV0`) of the 7 AC streams of
93 `data/combi_multi_261002_5min.raw`. `ssr_qc_bias` adds the CAS DCB file as
94 'QC Bias File' (code bias check against the other ACs and the file).
95
96* `decoder_limits`: crafted, CRC-valid frames from `tools/mkcrafted.py`
97 using the largest values the formats allow: VTEC with degree/order 16
98 (IGS-SSR 4076/201 and RTCM-SSR 1264, 2 and 4 layers) and RTCM 1300/1301/1302
99 with 31-character names, listed by the RTCM scan in the log. The
100 coefficients are C(d,o) = (100*d+o)/200 TECU and S = -C, both `.ssr` files
101 are identical apart from the station ID. These frames overflowed the
102 coefficient and name arrays; the 4-layer VTEC crashed BNC.
103
104## Sanitizer check of the SSR decoders
105
106```
107tests/tools/ssr_harness.sh # crafted_limits.raw
108tests/tools/ssr_harness.sh tests/data/*.raw # real captures
109```
110
111In BNC all SSR target structs are members of one `RTCM3coDecoder` object,
112so a write beyond one struct corrupts the next member without any
113AddressSanitizer report. The harness decodes every frame with all three
114format classes into separately allocated structs, so ASan reports it. It
115also covers the new RTCM-SSR metadata (message 60 in
116`crafted_limits.raw`: 7 entries with additional parameters of 40 and 0 bits,
117and 31 entries, which must be rejected), which `RTCM3Decoder.cpp` does not
118dispatch at present. Every decoded VTEC and metadata message is encoded
119again with the `Make*` function of the same class and decoded once more; the
120result must be identical. Exit code 0 only without sanitizer errors and
121differences.
122
123## TLS check
124
125```
126tests/tools/ssl_check.py [--bnc PATH]
127```
128
129Runs BNC against `tools/fakecaster.py` with TLS on port 443 (BNC uploads with
130Ntrip 2s always to 443) inside an unprivileged user and network namespace
131(`unshare -rn`), with a test CA, server and client certificates created by
132openssl in `work/ssl_check/`. Checks for upload and download: certificate of
133an unknown CA rejected, accepted with the CA in `sslCaCertPath`, accepted with
134`sslIgnoreErrors` and the ignored errors logged; for upload also a
135certificate for another host name (rejected) and a client certificate
136required by the caster, with and without `sslIgnoreErrors`. Takes about 3 min.
137
138## Adding a replay case
139
140```
141tests/tools/bncraw.py info capture.raw
142tests/tools/bncraw.py slice capture.raw tests/data/new.raw --stations SSRA00XYZ0 \
143 --start 2026-09-28T12:00:00 --end 2026-09-28T12:03:00
144mkdir tests/cases/new && $EDITOR tests/cases/new/case.json # copy an ssr_* case
145tests/run_tests.py --update new
146```
147
148Before accepting a reference with `--update`, check it by hand; for decoder
149cases, hand-decode the raw bits. The reference records what BNC does, not what
150is correct.
151
152## Reproducibility of replays
153
154In batch post-processing (`--file`), BNC delivers decoded ephemerides and
155corrections synchronously to the PPP (`t_bncCore::decoderConnectionType`) and
156starts reading only after all PPP instances are connected
157(`t_pppThread::waitUntilReady`). Replays are therefore reproducible run to run,
158including PPP with ambiguity resolution. Live operation is not affected.
Note: See TracBrowser for help on using the repository browser.