Test Strategy
What this page covers: Test categories, environments, coverage targets, test patterns, and known gaps.
Prerequisites: Getting Started for build and run instructions.
Executive Summary
Suite |
File |
Tests |
Focus |
Environment |
|---|---|---|---|---|
|
|
2 |
Device init, deinit, get_info |
native_sim |
|
|
6 |
Volume create, remove, resize, get_info |
native_sim |
|
|
3 |
LEB map, unmap, is_mapped |
native_sim |
|
|
5 |
LEB write, read, get_size |
native_sim |
|
|
2 |
PEB erase, dirty-to-free recycling |
native_sim |
|
|
1 |
Multi-volume cross-functional workflows |
native_sim |
|
|
97 |
NULL params, out-of-range, no-space, contract tests, corrupt headers, reserved PEB corruption, degraded recovery, LEB edge cases |
native_sim |
|
|
6 |
Max LEB capacity, alignment, sqnum persistence |
native_sim |
|
|
30 |
Corruption, dual-bank, sqnum conflicts, degraded mode, multi-volume recovery, free vs. uncommitted PEB classification |
native_sim |
|
|
4 |
Transactional safety under allocation failures, COW overwrite, invariant checks |
native_sim |
|
|
26 |
Malloc/flash-write/flash-erase fault sweeps across init, volume, and I/O paths; commit-order fault injection (VID write failure preserves old mapping) |
native_sim |
|
|
33 |
Geometry validation, partition guard, format failures, header corruption at init |
native_sim |
|
|
4 |
Full utilization, init cycling, wear leveling |
native_sim (simulator only) |
|
|
4 |
Randomized churn with reboots, multi-volume operations, persistence across reinit, EC counter equality after 500 cycles |
native_sim (simulator only) |
|
|
5 |
Bad-block torture, erase retry, degraded transitions |
native_sim (simulator only) |
|
|
3 |
Basic lifecycle, persistence, stress cycles (board-portable smoke) |
native_sim |
|
|
5 |
Multi-threaded readers/writers, deinit quiescence, partition guard |
native_sim |
|
|
6 |
Erased-value helper unit tests ( |
native_sim |
|
|
5 |
Central mutation gate: write-shutdown blocks all mutators, degraded mode blocks reserved-metadata only, runtime PEB corruption recovered transparently, runtime degradation sets flag and blocks mutations, erase_peb recovers reserved bank and clears flag |
native_sim |
|
|
4 |
Persistent vol_id high-watermark: same-boot reuse prevention, cross-reboot persistence, slot re-indexing stability, overflow fail-closed |
native_sim |
Total (plain) |
251 |
Secure Backend Parity Tests
All secure tests require CONFIG_UBI_CRYPTO=y and run with a PSA-imported test root key.
Suite |
File |
Tests |
Focus |
Environment |
|---|---|---|---|---|
|
|
3 |
Crypto type sizes, secure format on blank, plain unaffected by secure types |
native_sim |
|
|
8 |
Format/attach, mode mismatch, freshness rejection, NULL callbacks, allowlist validation |
native_sim |
|
|
2 |
Secure init/deinit, info sane, reboot persistence |
native_sim |
|
|
7 |
Create, remove, resize, shrink, multi-volume persistence, vid_counter_floor reconstruction (parity with |
native_sim |
|
|
3 |
Single/multi LEB write/read, overwrite (parity with |
native_sim |
|
|
4 |
Map/unmap lifecycle, dirty PEB accounting, unmap→reboot persistence, unmap→erase→reboot (parity with |
native_sim |
|
|
4 |
Fill-unmap-erase cycle, anchor wear-leveling migration, stale-anchor rejection after reboot, reclaim continuity witness preservation (parity with |
native_sim |
|
|
1 |
Multi-volume create/write/remove/resize/map/reboot (parity with |
native_sim |
|
|
2 |
LEB data tampering smoke, reserved PEB tampering smoke |
native_sim |
|
|
15 |
Sticky crypto read-only, event escalation, freshness sync cadence, sync failure events, reads in read-only, budget SOON/NOW thresholds, KEY_RETIRABLE, allowlist reject, missing key, rollback mismatch, sticky read-only reinit, mixed-key rotation |
native_sim |
|
|
9 |
Interrupted data write COW preservation, interrupted VID commit, first-write-leaves-unmapped, reboot after partial write, interrupted anchor rewrite continuity, reserved generation replay rejection, interrupted reserved PEB commit, interrupted anchor creation during volume create, init-time anchor re-creation for orphaned volumes |
native_sim |
|
|
11 |
Chunked LEB geometry, geometry reject, single/multi-chunk write/read, partial reads within and across chunk boundaries, last-chunk padding, reboot persistence, overwrite, chunk tamper isolation, zero-length map fallback (requires |
native_sim |
|
|
5 |
Portable forensic scan: plaintext data absence, volume name absence, key material absence, post-overwrite+erase absence, negative test validates scanner on plain backend |
native_sim |
Total (secure) |
74 |
What native_sim Proves vs. What Hardware Proves
Aspect |
native_sim (simulator) |
Hardware (b_u585i_iot02a, nrf5340dk) |
|---|---|---|
Functional correctness |
Full — all 325 tests run (324 pass, 1 skip, 33 suites) |
Build verification only (CI cross-compiles) |
Flash timing / latency |
Not representative |
Realistic |
Power-loss behavior |
Not tested (simulator has no power-loss model) |
Not currently tested (no HIL power-loss setup) |
Bad block behavior |
Simulated via |
Real flash errors (rare on NOR) |
Wear-leveling distribution |
Verified via erase counter checks |
Observable but not systematically tested |
Memory footprint |
Approximate (host allocator) |
Precise (Cortex-M33 heap) |
Test Categories
1. Unit / Functional Tests
Core API verification organized by functional area:
Suite |
File |
Focus |
|---|---|---|
|
|
Device init, deinit, get_info |
|
|
Volume create, remove, resize, get_info |
|
|
LEB map, unmap, is_mapped |
|
|
LEB write, read, get_size |
|
|
PEB erase, dirty-to-free recycling |
|
|
Multi-volume and cross-functional workflows |
2. Error Handling Tests
Suite |
File |
Focus |
|---|---|---|
|
|
NULL parameters, out-of-range LEB numbers, no-space conditions, resize edge cases, overwrite semantics, no-volumes paths, contract tests (idempotent unmap, no-op map, static volume write, invalid type, zero LEBs, capacity accounting), corrupt EC/VID headers, reserved PEB corruption, degraded recovery, LEB edge cases, wrong vol_id removal |
3. Boundary Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Max LEB capacity writes, exceeds-capacity errors, exact read offsets, alignment boundaries, sub-alignment writes |
4. Recovery / Corruption Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Corrupt EC header -> bad PEB, corrupt VID CRC -> bad PEB, valid EC + erased VID + erased data -> free PEB, valid EC + erased VID + non-erased data -> dirty PEB (uncommitted write), orphan vol_id -> dirty PEB, duplicate LEB sqnum conflict resolution, erase_peb no-op when clean, dual-bank recovery during resize, degraded-mode blocking, multi-volume recovery, reinit after interrupted commit preserves old data |
5. Fault Injection Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Transactional safety: malloc failure during create (P0.2), COW overwrite preserves old data on failure (P0.7), invariant checker after create/write/remove and resize/shrink cycles. Requires |
5b. I/O Fault Injection Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Systematic malloc-failure sweeps (init with no volumes, with volume, with orphans, with duplicates, with bad VID CRC, with bad EC), scratch alloc faults, diag alloc fault, volume create/remove alloc sweeps, flash erase failure -> bad PEB transition, commit-order tests (VID write failure after data write preserves old mapping; unmapped LEB stays unmapped on VID failure). Requires |
5c. Init Error Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Geometry validation (erase block size, write block size, partition size), partition guard ( |
6. Stress Tests (simulator only)
Suite |
File |
Focus |
|---|---|---|
|
|
Full volume utilization, init-deinit cycling, PEB wear leveling, multi-volume concurrent usage |
|
|
Randomized churn with reboots, multi-volume mixed operations, persistence across reinit, EC counter equality after 500 cycles |
7. Torture Tests (simulator only)
Suite |
File |
Focus |
|---|---|---|
|
|
Bad-block torture, erase retry logic, degraded-mode transitions |
8. HIL Smoke Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Board-portable smoke: basic lifecycle, persistence across reinit, stress cycles. Runs on both native_sim and hardware targets. |
9. Concurrency Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Multi-threaded concurrent readers, reader-writer interleave, deinit-after-quiescence, double-init partition guard ( |
10. Mutation Gate Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Central mutation gate: write-shutdown flag blocks all 7 public mutators ( |
11. Volume ID Watermark Tests
Suite |
File |
Focus |
|---|---|---|
|
|
Persistent vol_id high-watermark: same-boot reuse prevention (create, remove, create → new id), cross-reboot persistence (create, remove, reinit, create → watermark survives), slot re-indexing stability (remove middle volume, remaining vol_ids unchanged), overflow fail-closed (vol_id_watermark = UINT32_MAX → |
Test Environment
Primary: native_sim
Platform: Zephyr
native_simboard with flash simulatorConfig:
CONFIG_FLASH_SIMULATOR=y,CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y,CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE=yUsage: All test suites run here; stress and torture tests are simulator-only
Flash Geometry Variants
All functional and stress tests run against three flash geometries to exercise
different erase-block sizes, write-block alignment requirements, and partition
capacities. The geometry is selected via DTC overlay files in tests/boards/.
Variant |
Overlay file |
Erase block |
Write block |
Partition |
PEB count |
|---|---|---|---|---|---|
Default |
|
8192 B |
1 B |
128 KB |
16 |
nRF5340 |
|
4096 B |
4 B |
64 KB |
16 |
STM32U5 |
|
8192 B |
16 B |
128 KB |
16 |
Running locally with a geometry overlay:
# nRF5340 geometry
west build -p always -b native_sim ubi/tests -- \
-DDTC_OVERLAY_FILE="boards/native_sim_nrf5340.overlay"
./build/zephyr/zephyr.exe
# STM32U5 geometry
west build -p always -b native_sim ubi/tests -- \
-DDTC_OVERLAY_FILE="boards/native_sim_stm32u5.overlay"
./build/zephyr/zephyr.exe
CI: The native-tests job matrix includes geometry: [default, nrf5340, stm32u5],
producing 6 jobs (2 mem backends × 3 geometries).
Twister: testcase.yaml contains 16 geometry-specific scenarios using
extra_dtc_overlay_files (8 per geometry variant).
Secondary: b_u585i_iot02a
Platform: STM32U585AI hardware target (8 KB erase blocks, 128 KB UBI partition)
Usage: Cross-compilation verification (build only in CI)
Secondary: nrf5340dk/nrf5340/cpuapp
Platform: Nordic nRF5340 DK, application core (4 KB erase blocks, 64 KB UBI partition)
Usage: Cross-compilation verification (build only in CI)
Coverage
Targets
Metric |
Target |
Achieved (v0.22.0) |
|---|---|---|
Line coverage |
>= 80% |
85.0% plain (1670/1964), 77.3% secure (3572/4623) |
Branch coverage |
>= 70% |
51.8% plain (844/1628), 40.7% secure (1554/3817) |
Tooling
Instrumentation: Zephyr
CONFIG_COVERAGE=y+CONFIG_COVERAGE_GCOV=yCollection:
lcov --capturefiltered tolib/src/*Report:
genhtmlwith--branch-coverage
Running Locally
bash scripts/coverage.sh
HTML report is generated at build/coverage/html/index.html.
CI
The coverage job in .github/workflows/ci.yml builds with coverage, runs tests,
collects lcov data, and uploads the HTML report as a build artifact.
Test Patterns
Fixture Pattern
Each test suite uses the standard ZTest fixture. Shared helpers in tests/src/ eliminate boilerplate:
ubi_test_fixture.h—ubi_test_setup_mtd(),ubi_test_erase_partition(),ubi_test_init_device(),ubi_test_reinit_device()ubi_test_memory.h—ubi_test_memory_snapshot(),ubi_test_memory_check_no_leak()(requiresCONFIG_SYS_HEAP_RUNTIME_STATS)ubi_test_raw_flash.h—ubi_test_raw_write_ec_hdr(),ubi_test_raw_write_vid_hdr()for corruption injection
#include "ubi_test_fixture.h"
static struct ubi_mtd mtd = { 0 };
static void *ztest_suite_setup(void) {
ubi_test_setup_mtd(&mtd);
return NULL;
}
static void ztest_testcase_before(void *ctx) {
(void)ctx;
ubi_test_erase_partition();
}
ZTEST_SUITE(suite_name, NULL, ztest_suite_setup, ztest_testcase_before,
ztest_testcase_teardown, NULL);
Every test starts with a fully erased flash partition, ensuring isolation.
Corruption Testing Pattern
Recovery tests use raw flash_area_write() to inject corrupt headers:
Initialize UBI normally (creates device/volume headers on reserved PEBs)
Deinit
Directly write corrupt EC or VID headers on data PEBs
Re-init and verify PEB classification (
bad_peb_count,dirty_peb_count, etc.)
Compile Flags
Tests build with strict warnings to catch issues at compile time:
-Werror -Wextra -Wshadow -Wdouble-promotion -Wformat=2
-Wnull-dereference -Wunused -Wno-unused-parameter
Known Gaps
Gap |
Impact |
Mitigation |
|---|---|---|
No power-loss simulation |
Interrupted writes and metadata commits not tested |
Recovery logic is tested via corruption injection (corrupt headers, duplicate LEBs) |
Partial flash write failure coverage |
Flash write fault injection covers |
|
HIL smoke only (no CI hardware) |
|
Manual hardware testing during development; HIL CI planned |
Non-0xFF erased value end-to-end |
Erased-value helpers are unit-tested for 0x00, but the flash simulator only supports 0xFF |
Helpers are trivial; integration tests on 0xFF backend cover the full scan path |
Secure tamper detection precision |
Tamper tests verify no-crash and graceful handling but do not assert specific AUTH_FAILURE events (depends on PEB layout) |
Forensic scan suite ( |
Secure data size limit |
Secure LEB read requires scratch memory for decryption ( |
Use data within scratch budget in tests; increase |
How to Add a New Test
Choose the appropriate test file based on test category (see executive summary table)
Add a
ZTEST(suite_name, test_name)functionFollow the fixture pattern: init -> operate -> assert -> deinit
If testing a new file, add it to
tests/CMakeLists.txtBuild and run:
bash scripts/run_tests.sh