-
Notifications
You must be signed in to change notification settings - Fork 62
Description
Sled agent uses a lot of mocks to represent interactions with underlying resources. It uses a library named mockall to help with this interaction. We should use fakes instead.
- svc interface (sled-agent/src/illumos/svc.rs)
- dladm interface (sled-agent/src/illumos/dladm.rs)
- fstyp interface (sled-agent/src/illumos/fstyp.rs)
- zpool interface (sled-agent/src/illumos/zpool.rs)
- zfs interface (sled-agent/src/illumos/zfs.rs)
- some free functions (sled-agent/src/illumos/mod.rs)
- instances (sled-agent/src/instance.rs)
Background
When the sled agent is provisioning a zone, it "mocks" access to zones. This enables unit tests to verify "hey, you would have created a zone here", but in reality, make no such call.
This is okay-ish for some types of unit tests, where we have a module foo which depends on a interface resource:
foocan be conditionally compiled withcfg(test)to use themockResourcefoo's tests can then usemockall's API to set expectations about calls to themockResource
This is one such example of a test written in this style.
Problems
This testing strategy really breaks down when it gets nested. Suppose we have a module baz, which depends on foo and bar.
foo's dependency onmockResourcestill needs to be captured, sobazalso needs to set up "expectation" calls in tests- The same applies to
bar, and any other modules which contains mocks - This basically leaks implementation details, and makes tests really difficult to write
This is apparent for modules like the storage_manager, where we're interfacing with:
- ZFS provisioning
- Zpool provisioning
- Zone provisioning
and all of them would need to be mocked to actually write tests.
Proposal
We should implement fakes wherever these mocks are being used. This will give us a more flexible interface for testing, and make dependencies on "global-ish resources" much more apparent.
Admittedly, doing so will require providing the interfaces to these modules as up-front objects. I propose doing so with Arc-bound trait objects, rather than generics, to keep things relatively simple. The cost of a single Box + Arc's refcounting should be trivial compared with the cost of "provisioning a filesystem" or "managing a zone".