Expand description
Globally-ordered mock for MMIO driver testing in Rust.
Built on top of the MMIO region abstractions in
//sdk/lib/driver/mmio/rust, this crate provides a high-density, readable,
trace-like API for testing drivers that interact with memory-mapped I/O
(MMIO).
§Usage guide
§Initialize the test double
Create a MockMmioRegionBuilder instance covering the expected MMIO
region size in bytes.
use globally_ordered_mock_mmio::MockMmioRegionBuilder;
let mock_builder = MockMmioRegionBuilder::new(0x1000);§Declare expectations
Record expected MMIO operations using the ExpectedTraceBuilder API.
§Typed register operations
Use ExpectedTraceBuilder::read and ExpectedTraceBuilder::write for
expectations on register types defined with mmio::register!. The methods
deduce byte offsets and access widths.
use globally_ordered_mock_mmio::MockMmioRegionBuilder;
use mmio::{ReadableRegister, WritableRegister};
let mock_builder = MockMmioRegionBuilder::new(0x1000);
mock_builder.expect(|t| {
// Expect a read from Status returning 0x0000_0001
t.read::<registers::Status>(0x0000_0001);
// Expect a write to Command with value 0x0000_0002
t.write::<registers::Command>(0x0000_0002);
});
// Performed by the code under test.
let mut mmio = mock_builder.build();
assert_eq!(registers::Status::read(&mmio).0, 0x0000_0001);
registers::Command(0x0000_0002).write(&mut mmio);§Indexed register operations
Use ExpectedTraceBuilder::read_indexed and
ExpectedTraceBuilder::write_indexed for expectations on indexed register
types defined with #[indexed_register(...)].
use globally_ordered_mock_mmio::MockMmioRegionBuilder;
use mmio::{ReadableIndexedRegister, WritableIndexedRegister};
let mock_builder = MockMmioRegionBuilder::new(0x1000);
mock_builder.expect(|t| {
// Expect a read from IndexedData at index 2 returning 0x30
t.read_indexed::<registers::IndexedData>(2, 0x30);
// Expect a write to IndexedData at index 3 with value 0x40
t.write_indexed::<registers::IndexedData>(3, 0x40);
});
// Performed by the code under test.
let mut mmio = mock_builder.build();
assert_eq!(registers::IndexedData::read_index(&mmio, 2).0, 0x30);
registers::IndexedData(0x40).write_index(&mut mmio, 3);§Successful polling
Use ExpectedTraceBuilder::poll to model a status register that changes
value across successive reads.
use globally_ordered_mock_mmio::MockMmioRegionBuilder;
use mmio::ReadableRegister;
let mock_builder = MockMmioRegionBuilder::new(0x1000);
mock_builder.expect(|t| {
// First two reads return 0x01 (busy); subsequent reads return 0x02 (ready)
t.poll::<registers::Status>([0x0000_0001, 0x0000_0001, 0x0000_0002]);
});
// Performed by the code under test.
let mmio = mock_builder.build();
while registers::Status::read(&mmio).0 != 0x0000_0002 {}§Timed out polling
Use ExpectedTraceBuilder::poll_indefinitely to model hardware remaining
busy until the driver times out and executes recovery.
use globally_ordered_mock_mmio::MockMmioRegionBuilder;
use mmio::{ReadableRegister, WritableRegister};
let mock_builder = MockMmioRegionBuilder::new(0x1000);
mock_builder.expect(|t| {
// Returns 0x01 indefinitely until the driver executes a non-matching access
t.poll_indefinitely::<registers::Status>(0x0000_0001);
t.write::<registers::Command>(0x0000_0001); // Reset command after timeout
});
// Performed by the code under test.
let mut mmio = mock_builder.build();
for _ in 0..10 {
assert_eq!(registers::Status::read(&mmio).0, 0x0000_0001);
}
registers::Command(0x0000_0001).write(&mut mmio);§Raw numeric offsets
When the reference test data is a trace containing raw MMIO offsets and
values, pass the raw offset to ExpectedTraceBuilder::at and express the
operation and value using the RawOffsetTraceBuilder methods, such as
RawOffsetTraceBuilder::read32 and RawOffsetTraceBuilder::write32.
use globally_ordered_mock_mmio::MockMmioRegionBuilder;
use mmio::Mmio;
let mock_builder = MockMmioRegionBuilder::new(0x1000);
mock_builder.expect(|t| {
t.at(0x0).read8(0x12);
t.at(0x1).write8(0x34);
t.at(0x8).read32(0x1234_5678);
t.at(0xc).write32(0x9abc_def0);
});
// Performed by the code under test.
let mut mmio = mock_builder.build();
assert_eq!(mmio.load8(0x0), 0x12);
mmio.store8(0x1, 0x34);
assert_eq!(mmio.load32(0x8), 0x1234_5678);
mmio.store32(0xc, 0x9abc_def0);§Memory barriers
Use ExpectedTraceBuilder::write_barrier to expect a write barrier
between two MMIO accesses.
use globally_ordered_mock_mmio::MockMmioRegionBuilder;
use mmio::Mmio;
let mock_builder = MockMmioRegionBuilder::new(0x1000);
mock_builder.expect(|t| {
t.at(0x0).write32(0x1234_5678);
t.write_barrier();
t.at(0x4).write32(0x9abc_def0);
});
// Performed by the code under test.
let mut mmio = mock_builder.build();
mmio.store32(0x0, 0x1234_5678);
mmio.write_barrier();
mmio.store32(0x4, 0x9abc_def0);§Obtain and use the MMIO region
Call MockMmioRegionBuilder::build to obtain a MockMmioRegion, which
is an mmio::region::MmioRegion implementation.
The returned region implements mmio::Mmio and mmio::MmioSplit,
allowing driver code to split sub-regions across multiple threads. Accesses
from all threads are checked against a single global expectation list, in
the order in which the accesses reach the mock.
The mock does not impose any ordering on accesses issued by different threads. Tests that exercise concurrent driver code must establish their own ordering, for example by having the threads synchronize on a channel.
§Verification and teardown
Expectations are verified on Drop, after the MockMmioRegionBuilder
and all the MockMmioRegions it produced are dropped. Any unretired
expectation results in a test failure. No explicit verification call is
needed.
Verification is skipped while the thread is already panicking, so that the failure that caused the panic is not masked.
Structs§
- Expected
Trace Builder - Builder for recording expected MMIO access sequences within a closure.
- Mock
Mmio Region Builder - Strict thread-safe mock (interaction testing) for MMIO (
MmioRegion). - RawOffset
Trace Builder - Builder for recording expected MMIO accesses at a fixed raw byte offset.
Functions§
- mmio_
operand_ to_ u64 - Returns the numerical value for any
MmioOperand.
Type Aliases§
- Mock
Mmio Region MmioRegionproduced byMockMmioRegionBuilder.