blob: d90696e157cc667818e723a9f55a0b9c11a052fd [file] [log] [blame] [view] [edit]
# Testing utility reference
This document provides a central location for all of the test utilities
available to `bt-host` unit test developers. Many of these are test doubles of
commonly used `bt-host` objects, but there are a variety of other test
utilities.
**Note:{#test-loop-harness}** There's one non test-double pattern that pops up
in a few places in bt-host: a **test harness** which inherits from the
asynchronous dispatcher loop GTest fixture and instantiates a useful test double
member. This test harness provides an accessor to the test double and
(sometimes) other useful methods on top of the test double. Test fixtures for
layers dependent on $test_double can then inherit from the new harness for extra
convenience.
## Definitions
The bt-host code-base provides an extensive unit test suite and as such it
employs a variety of available test utilities. To better understand the
differences between test utilities, it is recommended to understand the
following terminology:
* **Test code**: Code written to test production code.
* Note: The `bt-host` C++ codebase uses the convention that for production
code in `foo.(h|cc)`, associated tests are written in
`foo_unittest.cc`.
* **Code under test**: The production code tested by **test code**.
* **Test Double**: A generic term for an object used to stand in for some piece
of production code in tests. Test doubles are often used with dependency
injection - objects depend only on an interface, and in test code, they are
constructed with a test double implementing that interface. Test doubles allow
for isolated (unit) testing of an individual piece of code. Each of the
following terms is a specific type of test double.
* **Stub**: A test double which provides canned responses to requests from code
under test. A related type of test double is a test **spy**, which also
provides canned responses, but allows test code to peek into the requests made
by the code under test.
* **Mock**: A test double which allows test code to set expectations on the
behavior of code under test. Once configured by test code, the mock will
verify that certain calls have been made by the code under test, and possibly
perform custom behavior based on these calls if configured to do so.
* **Fake**: A test double which implements a realistic, but simplified version
of a production object. Fakes are often used in place of difficult to
replicate, expensive, or slow dependencies, e.g. databases or hardware.
Note: For additional information, see
[Test Doubles — Fakes, Mocks and Stubs](https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da).
## Bluetooth controller test utilities
Consider the Core Bluetooth system architecture (i.e. not services or protocols
built on top of the Core Specification). The main three components are the
Bluetooth Controller, which is implemented in firmware and hardware on the
Bluetooth radio device, the Host-Controller-Interface (HCI) protocol, and the
Bluetooth Host, i.e. `bt-host` and the rest of
[the core stack](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/).
One way to test the Host subsystem without using a physical Bluetooth controller
would be to create a Controller test double which responds to HCI commands from
`bt-host`. As the Controller exists “below” the Host subsystem, this is the
lowest-level way to test `bt-host` functionality. Given the complexity of
Bluetooth controller software, there are a variety of test utilities available
for different use cases.
#### [ControllerTestDoubleBase](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/controller_test_double_base.h)
`ControllerTestDoubleBase` exists to provide basic functionality (mostly related
to opening and handing off Bluetooth data channels) needed by any Controller
test double. This class is not used directly, but subclassed by Controller test
doubles for shared functionality.
#### [FakeController](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/fake_controller.h)
`FakeController` is a test fake of the Bluetooth Controller. It emulates the HCI
protocol by employing reasonable default software logic to respond to HCI
commands from `bt-host`. It also provides some data plane emulation.
`FakeController` sees usage in tests of code one or more layers above explicit
HCI commands, where the controller is often an indirect dependency. As such,
`FakeController` uses [`FakePeer`](#fakepeer) along with the
[emulation utilties](#emulation-helpers) outlined below to emulate a full fake
piconet. `FakeController` allows indirect configuration through manipulation of
the fake piconet, such as adding or removing `FakePeer`s. It is a test fake in
the sense that its direct interactions with `bt-host` code, the HCI commands and
events, are not directly configured. Use `FakeController` when you want to
simulate a controller with standard behavior and your code under test does not
rely on specific HCI commands or responses.
##### [FakePeer](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/fake_peer.h)
`FakePeer`, used along with the `FakeController` utility, provides a deep level
of Bluetooth peer device control plane emulation. It aggregates a variety of
lower-level test doubles, such as `FakeL2cap`, `FakeLayer`,
`FakeSignalingServer`, and `FakeSdpServer`. `FakePeer` allows high-level
GAP-level production code to use the `FakeController` and emulate
realistically-behaved remote device. Multiple fake peers can be used to emulate
a full-fledge piconet. Use `FakePeer` in integration-style tests of integration
points between many objects.
#### [MockController](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/mock_controller.h)
`MockController` allows clients to dynamically mock out expected Controller
behavior. Clients queue up specific HCI commands and responses, and
`MockController` verifies that these transactions occur in the expected order.
`MockController` mostly sees usage in code that directly interacts with the HCI
protocol. Use `MockController` to simulate an exact flow of either ACL packets
or HCI commands, or to inject test-specific HCI behavior into a test.
#### [ControllerTest](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/controller_test.h)
`ControllerTest` is not a test double in itself, but a
[test harness of the type described above](#test-loop-harness). `ControllerTest`
is templated over a `ControllerTestDoubleBase`, so clients can access the same
fixture functionality with any concrete `ControllerTestDoubleBase` implementor
they provide. Test suites that depend on test double Controllers tend to
subclass this class (vs. explicitly creating `ControllerTestDouble` implementors
themselves), and then access their chosen Controller test double through this
class’s accessors.
## `bt-host` object test doubles
By nature, any test suite using Controller test doubles uses production
instances of some layers all the way down to the Controller interface. This is
clearly sensible for unit tests of controller-interfacing code and
integration-style tests.
The Bluetooth stack is built in the form of libraries, with each library
providing a collection of public interfaces and corresponding test doubles to
enable unit testing for their clients. For unit tests of `bt-host` layers well
above the Controller, it often makes more sense to use these higher-level test
doubles rather than production instances of layers all the way down to the
Controller. These higher-level utilities are detailed below, organized by which
production protocol they imitate in tests.
### Host controller interface (HCI)
The HCI library is responsible for direct interactions with the controller in
the form of HCI messages and events.
#### [FakeConnection](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/hci/fake_connection.h)
The
[`hci::Connection` class](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/hci/connection.cc)
represents a logical link to a peer device and is used by the host stack control
plane
([gap/](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gap),
[sm/](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/sm))
to keep track of connections. hci::Connection is specifically not a data
transport to the peer device; it strictly exposes control plane functionality
(e.g. connection state, security). While the production implementation interacts
with the Bluetooth controller using HCI commands, its test double
hci::FakeConnection allows for writing control plane unit tests without a
functional HCI backend.
#### [FakeLocalAddressDelegate](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/hci/fake_local_address_delegate.h)
The
[`hci::LocalAddressDelegate` class](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/hci/local_address_delegate.h)
provides a small interface exposing the local device's BD_ADDR address and the
Identity Resolving Key for LE Resolvable Private Addresses (RPAs), along with a
method to refresh the current RPA if needed. It is used in a variety of
situations where objects need knowledge of local address properties, including
advertising, connecting, and discovery. In production, its only implementor is
the GAP-level LocalAddressManager. Most usages of the device's local address
don't particularly depend on the rotating or private nature of local addresses,
so the FakeLocalAddressDelegate is used to have more isolated and repeatable
tests with simplified address behavior.
### Logical link control and adaption protocol (L2CAP)
L2CAP provides "higher level protocol multiplexing, packet segmentation and
reassembly, and the conveying of quality of service information." (Bluetooth
Core Specification v5.2 Vol. 3 Part A).
#### [FakeChannel](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/l2cap/fake_channel.h)([Test](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/l2cap/fake_channel_test.h))
`FakeChannel` is used as a test double for layers that directly use
[L2CAP channels](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/l2cap/channel.h).
L2CAP channels provide a logical connection to a peer service, so dependent
protocols include higher-level protocols like ATT, GATT, SMP, SDP. Based on our
[predefined terms](#Definitions), it would probably be more correct to call this
utility MockChannel, as most uses of `FakeChannel` are explicitly `Expect`ing
and `Receiv`ing specific L2CAP packets. `FakeChannelTest` is an example of the
[test harness pattern](#test-loop-harness), which provides additional
commonly-used functionality (e.g. `ReceiveAndExpect` to easily verify a specific
production response to a specific received message).
#### [FakeSignalingChannel](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/l2cap/fake_signaling_channel.h)
Used internally in L2CAP tests to mock production signaling channel behavior.
Like `FakeChannel`, it can more accurately be described as a test mock, as L2CAP
tests that use `FakeSignalingChannel` are expected to explicitly configure
packets to be expected and sent back to the production code.
### Generic attribute protocol (GATT)
GATT implements a database-like abstraction over Bluetooth connections, which
can be used to build higher-level applications and services.
#### [FakeLayer](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gatt/fake_layer.h)([Test](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gatt/fake_layer_test.h))
[`GATT`](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gatt/gatt.h)
is a host-stack singleton object which owns the ATT transport channels for LE
connections and stores the current GATT clients and servers communicating with
their associated peer. It is not responsible for directly supporting application
level GATT clients or servers, but provides a basic level of GATT functionality
on top of which GATT client and server roles are built. As such, `FakeLayer`
serves as a test double for this root GATT object, allowing for unit tests of
the GATT client and server implementations to be run without dependence on
production ATT code. The GATT library also exposes a `FakeLayerTest` harness
(per above [note](#test-loop-harness)).
#### [FakeClient](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gatt/fake_client.h)
[`gatt::Client`](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gatt/client.h)
implements GATT client role procedures on top of a real ATT bearer object.
`gatt::Client` mainly serves as an intermediary between the lower-level,
specification-defined ATT protocol and the higher-level GATT abstractions
exposed by `bt-host` to the rest of the Fuchsia system. `FakeClient` allows
these higher-level, GATT client-dependent classes to mock out GATT client
procedures without an underlying production ATT implementation for unit tests.
### Security manager protocol (SMP)
SM "defines the protocol and behavior to manage pairing, authentication, and
encryption between LE-only or BR/EDR/LE devices." (Bluetooth Core Specification
v5.2 Vol. 3 Part H).
#### [FakeListener](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/sm/fake_phase_listener.h)
`FakeListener` is used as a test double for
[`PairingPhase`](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/sm/pairing_phase.h#25)’s
`Listener` class, which in production code is their owning class,
[`PairingState`](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/sm/pairing_state.h).
`PairingPhase`s use a pointer to `Listener` to communicate with their owning
class. `FakeListener` is another example of using the word `Fake` where `Mock`
probably makes more sense, as the main test usage is to expect that certain
calls were made to the `FakeListener` class by production `PairingPhase`
instances.
#### [TestSecurityManager(Factory)](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/sm/test_security_manager.h)
A test implementation of SM's public interface, `SecurityManager`. Provides a
`TestSecurityManagerFactory` with a `CreateSm` method which stores a reference
to the created `TestSecurityManager`. A `TestSecurityManagerFactory` can be used
to inject `TestSecurityManager`s into production code while keeping them
accessible by unit tests. The current implementation is a very minimal test spy.
It provides basic argument snooping and stub responses for a few methods and
noop implementations for others.
### Generic access protocol (GAP)
GAP integrates many of the other components of the Core Subsystem and exposes
Bluetooth functionality to application-level services and clients.
#### [FakePairingDelegate](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gap/fake_pairing_delegate.h)
Pairing to peer devices often requires user input, but given the wide variety of
potential target devices for Fuchsia and possible input methods, there is no
consistent way for `bt-host` to directly obtain this user input.
[`gap::PairingDelegate`](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/gap/pairing_delegate.h)
provides an interface for `bt-host` to request this user i/o. This object
corresponds directly to the system-level
[`PairingDelegate` FIDL object](https://fuchsia.dev/reference/fidl/fuchsia.bluetooth.sys#PairingDelegate),
which products built on Fuchsia must implement in order to enable Bluetooth
pairing. `FakePairingDelegate` exists in order to enable unit tests of pairing
flows without real user interaction. Test code configures the test double to
expect and provide responses to pairing i/o requests from `bt-host` production
code.
#### [FakeL2cap](../core/bt-host/testing/fake_l2cap.h)
`l2cap::L2cap` mainly serves as the public interface to the L2CAP layer.
`FakeL2cap` aggregates a variety of faked out implementations of protocols
aggregated in production by `l2cap::L2cap` for unit testing of higher layers.
## `bt-host` emulation helpers
Besides mocks of single layers, `bt-host` provides the ability to emulate fake
piconets of Bluetooth peers. `bt-host` test code accesses this emulation through
the [`FakePeer`](#fakepeer-gap) and [`FakeController`](#fakecontroller) classes.
While this emulation is not quite as complex as an entire real Bluetooth stack,
there is a significant amount of behavior to emulate. As such, this behavior is
broken down into a number of "fakes" of the various Bluetooth protocols and
profiles. These test utilities are *not* injectable test doubles intended for
direct use in test case code, but abstractions within the emulation layer. As
such, reading about these test utilities will not necessarily help developers
adding feature test code. This section is for developers adding additional test
emulation features.
**Note**: For integration tests outside of `bt-host`, this emulation
functionality can through accessed through the
[HCI emulator](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/hci/emulator)
utilities.
#### [FakeSignalingServer](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/fake_signaling_server.h) (L2CAP)
L2CAP communicates channel-control messages with the peer device over L2CAP
signaling channels, which exist on a per-peer-and-transport basis. In the
FakeController emulation world, FakeSignalingServer provides canned responses
for these per-logical link signaling channel messages.
#### [FakeL2cap](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/fake_l2cap.h) (L2CAP)
FakeL2cap emulates the production L2CAP layer. It provides a simplified
implementation of L2CAP packet<->channel routing, as well as methods to
dynamically configure the behavior of routed packets. The behavioral
configuration exposed by FakeL2cap is not necessarily intended for direct use in
test code. Instead, FakeL2cap usually serves as an underlying emulation layer
for other test utilities in the FakeController world. These higher-level
emulation utilities see usage in test code more than one level above L2CAP.
#### [FakeDynamicChannel](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/fake_dynamic_channel.h) (L2CAP)
`FakeDynamicChannel` provides a simplified model of real dynamic channels in the
emulator. Services which use real dynamic channels in production use
`FakeDynamicChannel` to transmit and receive data in emulated environments.
#### [FakeSdpServer](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/fake_sdp_server.h) (SDP)
`FakeSdpServer` emulates SDP Server functionality for use in integration tests
of Bluetooth flows requiring specific SDP entries. It largely leverages the
production SDP server implementation to store services and generate response
packets as necessary.
#### [FakeGattServer](https://fuchsia.googlesource.com/fuchsia/+/f28eb81421883d215a654933acf69868dfc67295/src/connectivity/bluetooth/core/bt-host/testing/fake_gatt_server.h) (GATT)
`FakeGattServer` provides a basic level of GATT server emulation. This sees use
in integration-style LE tests which use the GATT client role and require peer
GATT server functionality.