Files
gps-denied-onboard/_docs/02_document/tests/resilience-tests.md
T

13 KiB
Raw Blame History

Resilience Tests

Each test defines fault injection + observable recovery + quantifiable pass/fail. All run through the public interfaces from environment.md.


NFT-RES-01: Companion-computer process kill mid-flight (AC-5.3, AC-NEW-1)

Summary: SUT process killed mid-flight; SUT restarts and recovers from FC's IMU-extrapolated position within 30 s. Traces to: AC-5.3, AC-NEW-1, F-T11, results_report row 25. Tier: T1.

Preconditions: SUT in steady-state tracking; FC continues to fly.

Fault injection:

  • docker kill -s SIGKILL <sut> followed by docker start <sut>.

Steps:

Step Action Expected Behavior
1 SIGKILL SUT SUT process exits non-gracefully; FC continues IMU-only DR per AC-5.2
2 Restart SUT container starts
3 Time from container start to first valid GPS_INPUT (fix_type==3) t_recovery ≤ 30 s
4 Read GLOBAL_POSITION_INT from FC at SUT-start; assert pipeline seeds from it source recovery via FC pose
5 After first satellite match, error ≤ 50 m accuracy restored

Pass criteria: t_recovery ≤ 30 s p95 over 50 trials; AC-5.2 fallback observable on FC during the gap; accuracy restored ≤ 50 m after first match. Duration: 60 s per trial; 50-trial campaign on T4.


NFT-RES-02: GPS spoofing — promotion within 3 s (AC-NEW-2)

Summary: FC GPS-loss / lane-switch event signalled → SUT promotes its estimate to primary within 3 s. Traces to: AC-NEW-2, F-T12. Tier: T3 (deferred-sitl).

Preconditions: SITL + gps-spoof-injector.

Fault injection:

  • Inject malicious GPS_RAW_INT with 1 km lat/lon offset starting at scripted t=0.

Steps:

Step Action Expected Behavior
1 t=0: inject spoof FC observes anomaly; emits EKF lane-switch / fix-loss in EKF_STATUS_REPORT
2 SUT subscribes to GPS_RAW_INT, EKF_STATUS_REPORT, SYS_STATUS and maintains a "real-GPS health" rolling average health drops below threshold
3 Within 3 s, SUT raises GPS_INPUT to primary mode + emits STATUSTEXT PROMOTE to GCS promotion event observable

Pass criteria: 95th percentile of t_promote ≤ 3 s over 50 trials. Duration: 30 min campaign.


NFT-RES-03: 3-s no-fix → FC fallback to IMU-only DR (AC-5.2)

Summary: Pipeline blackout for >3 s — FC falls back to IMU-only DR; SUT logs the failure. Traces to: AC-5.2, restrictions §Failsafe. Tier: T3.

Fault injection: scripted scenario where SUT cannot produce any estimate for 3.5 s (e.g., cuVSLAM tracking loss + cache poisoned + matcher offline).

Steps:

Step Action Expected Behavior
1 Inject blackout SUT publishes STATUSTEXT WARN within 1 s of blackout
2 At t=3 s of blackout, SUT emits a single STATUSTEXT FAILSAFE recorded
3 Observe FC EKF_STATUS_REPORT FC switches to IMU-only DR within 4 s of blackout start
4 After 5 s, restore pipeline SUT re-emits valid GPS_INPUT; FC re-fuses

Pass criteria: FC fallback observable within 4 s; SUT recovers within 30 s of pipeline restore (matches AC-NEW-1 budget). Duration: 60 s per trial.


NFT-RES-04: 3-consecutive-failures → RELOC_REQ + waiting state (AC-3.4)

Summary: When SUT cannot determine position for ≥3 consecutive frames AND ≥2 s, it sends a re-localization request. Traces to: AC-3.4, results_report rows 20, 21, 46. Tier: T1.

Fault injection: scripted 3 frames of failed satellite matching + cuVSLAM degraded.

Steps:

Step Action Expected Behavior
1 Trigger 3 consecutive frame failures spanning ≥2 s counter increments
2 Within 2 s of the third failure, STATUSTEXT RELOC_REQ: last_lat=… last_lon=… uncertainty=…m emitted regex match
3 While waiting, SUT continues VO/IMU dead reckoning (fix_type==0, source dead_reckoned) and continues satellite-match attempts (counter increments) observable
4 FC continues with last known position + IMU extrapolation EKF_STATUS_REPORT consistent

Pass criteria: regex matches; SUT continues emitting GPS_INPUT in waiting state; satellite-match counter increments. Duration: 60 s.


NFT-RES-05: Operator hint workflow (AC-3.4, AC-6.2)

Summary: Operator hint is consumed as a 500 m seed for VPR/cross-view re-loc. Traces to: AC-3.4, AC-6.2, F-T10, results_report row 22. Tier: T1.

Preconditions: SUT in re-loc waiting (after NFT-RES-04).

Fault injection (cooperative): qgc-mock sends STATUSTEXT RELOC_HINT: lat=… lon=… sigma=500m.

Steps:

Step Action Expected Behavior
1 Send hint SUT consumes hint; STATUSTEXT HINT_RECEIVED echoed
2 First fix after hint error ≤ 500 m
3 After next satellite match error ≤ 50 m; tracking_state == NORMAL

Pass criteria: as above. Duration: 60 s.


NFT-RES-06: Sharp turn — VO-loss → satellite re-loc (AC-3.2)

Summary: <5 % overlap, <70°, <200 m drift triggers VO loss; satellite re-loc recovers within 3 frames. Traces to: AC-3.2, F-T7. Tier: T1.

Fault injection: synthetic sharp-turn pair injected into nav_cam_60_slice.

Steps: see FT-P-14; resilience perspective: cuVSLAM tracking-loss event → matcher invocation via re-loc trigger → recovery.

Pass criteria: error ≤ 50 m within 3 frames of turn; cuVSLAM tracking-state returns to NORMAL. Duration: 60 s.


NFT-RES-07: Disconnected-segment recovery (AC-3.3)

Summary: ≥3 disconnected segments per flight; each segment connects to prior trajectory via global retrieval. Traces to: AC-3.3, F-T8. Tier: T1.

Fault injection: disconnected_segments_replay with ≥3 large gaps.

Steps:

Step Action Expected Behavior
1 Replay segment N (after gap) VPR retrieves top-K candidate chunks; matcher relocalizes within 10 frames
2 After re-loc, trajectory continuity restored (no jump in EKF position beyond gap-expected) tracking_state == NORMAL
3 Repeat for ≥3 segments all 3 succeed

Pass criteria: 3/3 segments recover within 10 frames; trajectory continuity maintained. Duration: 5 min.


NFT-RES-08: cuVSLAM-degraded fall-back path

Summary: If cuVSLAM underperforms (tracking lost repeatedly), SUT degrades gracefully and emits dead_reckoned source label rather than producing wild estimates. Traces to: AC-1.4, AC-3.x, R8 reframed. Tier: T1.

Fault injection: scripted cuVSLAM tracking loss for 30 s.

Steps:

Step Action Expected Behavior
1 Force cuVSLAM tracking-loss for 30 s source label switches to dead_reckoned; horiz_accuracy grows
2 After 30 s, restore cuVSLAM source label returns to vo_extrapolated or satellite_anchored
3 Verify GPS_INPUT during the 30 s window does not contain wild jumps per-frame Δposition ≤ IMU integration bound

Pass criteria: source label correctly transitions; no wild jumps; behaviour reversible. Duration: 60 s.


NFT-RES-09: Tile-cache corruption — graceful degradation

Summary: Corrupted MBTiles entry triggers reject + WARN, not a crash. Traces to: AC-8.3, AC-3.x. Tier: T1.

Fault injection: overwrite a tile sidecar JSON with garbage between SUT runs.

Steps:

Step Action Expected Behavior
1 Inject corruption SUT logs WARN at cache-load
2 Replay frames over the affected sector matcher does not consume the corrupt tile; falls through to next candidate
3 SUT process does NOT crash; tracking_state may go DEGRADED for affected frames, then NORMAL

Pass criteria: process alive; corrupt tile never produces satellite_anchored; recovery on next valid sector. Duration: 60 s.


NFT-RES-10: SITL F-T9 source-switching (AC-4.3 Option A)

Summary: ArduPilot SITL fuses GPS_INPUT correctly; failover to EK3_SRC2_* when primary unavailable. Traces to: AC-4.3, F-T9 Option A. Tier: T3.

Fault injection: temporarily stop SUT GPS_INPUT emission for 5 s; observe FC failover.

Steps:

Step Action Expected Behavior
1 SUT stops emitting FC EKF3 detects loss; switches to EK3_SRC2_*=GPS
2 Resume SUT emission EKF3 switches back; no double-fusion (no #30076 / #32506 symptoms)

Pass criteria: clean switch in both directions; EKF3 logs show no double-fusion symptoms. Duration: 15 min.


NFT-RES-11: MAVLink2 signing failure — FC rejects, SUT logs

Summary: When the runner sends a deliberately mis-signed GPS_INPUT, FC rejects and SUT/FC log the rejection. Traces to: M-7, S-T1, F-T9 signing assertion. Tier: T3.

Fault injection: send a GPS_INPUT with valid schema but invalid signing tag.

Steps: see FT-N-14.

Pass criteria: FC ARM-rejects the message; STATUSTEXT WARN observable; FC continues on prior valid source. Duration: 30 s.


NFT-RES-12: Stale-tile rejection (AC-NEW-6)

Summary: Tile beyond freshness budget (or grace zone) is rejected — satellite_anchored source label NEVER produced from it. Traces to: AC-8.2, AC-NEW-6, NF-T6. Tier: T1.

Fault injection: stale_tile_scenarios with ages 7 / 11 / 13 / 18 months for active-conflict + stable-rear sectors.

Steps:

Step Action Expected Behavior
1 For each combination, replay frames over the affected sector matcher invocation either skipped or scored 0
2 Assert source label of resulting GPS_INPUT NEVER satellite_anchored from stale tile
3 Confidence weight on tiles in 30-day grace zone linearly decayed per spec

Pass criteria: as above. Duration: 5 min.


NFT-RES-13: F-T16 cloud-occlusion injection

Summary: Synthetic cloud occlusion on a fraction of frames does not cause cascading failure. Traces to: F-T16, AC-3.x. Tier: T2 (deferred-corpus).

Fault injection: 30 % of frames in AerialVL S03 replay overlaid with synthetic cloud cover.

Steps:

Step Action Expected Behavior
1 Run replay matcher fails on cloud-occluded frames; pipeline degrades to vo_extrapolated
2 After cloud passes, satellite re-loc resumes source returns to satellite_anchored

Pass criteria: AC-1.1 / AC-1.2 still met on the non-cloud-frame subset; pipeline does not enter unrecoverable state. Duration: 90 min.


NFT-RES-14: 8-hour soak — no FDR rollover loss (AC-NEW-3)

Summary: Sustained 8 h replay; FDR caps at 64 GB and rolls over without silently dropping a payload class. Traces to: AC-NEW-3, NF-T5. Tier: T4 (deferred-hil).

Fault injection: replay synthetic_8h_load continuously for 8 h.

Steps:

Step Action Expected Behavior
1 Run replay FDR populates
2 Inspect at every hour boundary size monotonic up to cap; rollover events logged
3 After 8 h FDR ≤ 64 GB; all payload classes present (positions, IMU, GPS_INPUT, tlog, system health, mid-flight tiles, failure-thumbnail log)

Pass criteria: ≤ 64 GB; all classes present in the latest segment; rollover events logged for any class that hit cap. Duration: 8 h.


NFT-RES-15: AC-NEW-7 cache-poisoning Service-side voting

Summary: Single-flight onboard tile is NOT promoted to trusted basemap until ≥2 voting flights confirm. Traces to: AC-NEW-7, F-T3. Tier: T1 (with service-stub).

Fault injection (cooperative): submit a single-flight tile with deliberately deflated EKF covariance.

Steps: see FT-N-17.

Pass criteria: candidate stays trust_level=candidate; promotion only after N≥2 voting; for active sectors, single-flight promotion only when σ_xy ≤ 3 m AND OSM-road-overlap ≥ 70 %. Duration: 5 min.


NFT-RES-16: ROS 2 topic-rate sanity (F-T19)

Summary: Under simulated load, all expected ROS 2 contract topics meet expected publish rates. Traces to: F-T19, Q6 → A. Tier: T1 (uses ROS 2 sniffer that subscribes only to documented contract topics, treating internal topics as opaque).

Fault injection: synthetic load (load generator publishes pseudo-image frames at 3 fps + IMU at 200 Hz).

Steps: subscribe to nav_msgs/Odometry (cuVSLAM output), sensor_msgs/Image (camera input), mavros/global_position/global (FC bridge), mavros/imu/data (FC bridge).

Pass criteria: each contract topic publishes at expected rate ± 10 % over a 5 min window. Duration: 5 min.