mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-06 03:28:24 +00:00
Warn when a configured BLE instance cannot be built on this platform
The only warning for a BLE block that nothing could build sat under contradictory cfg gates: it was compiled only in test builds, where its warn! was compiled out. So macOS, Windows, FreeBSD, musl builds, and Android without an armed radio dropped a configured ble: block silently while the node reported healthy. A cfg-selected helper now says why the build cannot construct a BLE instance, and create_transports warns once per configured instance with that reason, as it already does for Ethernet. The BlueZ path's adapter initialisation warning is unchanged.
This commit is contained in:
+47
-8
@@ -1164,7 +1164,7 @@ impl Node {
|
||||
}
|
||||
|
||||
// Create BLE transport instances
|
||||
#[cfg(bluer_available)]
|
||||
#[cfg(all(bluer_available, not(test)))]
|
||||
{
|
||||
let ble_instances: Vec<_> = self
|
||||
.config()
|
||||
@@ -1174,7 +1174,6 @@ impl Node {
|
||||
.map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
|
||||
.collect();
|
||||
|
||||
#[cfg(all(bluer_available, not(test)))]
|
||||
for (name, ble_config) in ble_instances {
|
||||
let transport_id = self.allocate_transport_id();
|
||||
let adapter = ble_config.adapter().to_string();
|
||||
@@ -1196,12 +1195,6 @@ impl Node {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(not(bluer_available), test))]
|
||||
if !ble_instances.is_empty() {
|
||||
#[cfg(not(test))]
|
||||
tracing::warn!("BLE transport configured but this build lacks BlueZ support");
|
||||
}
|
||||
}
|
||||
|
||||
// Create BLE transport instances over an embedder-supplied radio.
|
||||
@@ -1230,10 +1223,56 @@ impl Node {
|
||||
transports.push(TransportHandle::Ble(ble));
|
||||
}
|
||||
}
|
||||
// `BleConfig` always parses, so on a build that cannot construct a
|
||||
// BLE transport a configured `ble:` block would otherwise be dropped
|
||||
// silently and the node would report healthy without it.
|
||||
if let Some(reason) = self.ble_blocker() {
|
||||
for (name, _) in self.config().transports.ble.iter() {
|
||||
tracing::warn!(
|
||||
instance = name.unwrap_or("default"),
|
||||
reason,
|
||||
"BLE transport unavailable; ignoring configured instance"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
transports
|
||||
}
|
||||
|
||||
/// Why this build cannot construct a configured BLE instance, or `None`
|
||||
/// when it can.
|
||||
///
|
||||
/// The three arms are disjoint and together cover every build, so a
|
||||
/// target matching none or two of them fails to compile rather than
|
||||
/// guessing.
|
||||
#[cfg(all(bluer_available, not(test)))]
|
||||
fn ble_blocker(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Why this build cannot construct a configured BLE instance, or `None`
|
||||
/// when it can. The embedder-supplied backend needs its radio slot armed
|
||||
/// before `start()`.
|
||||
#[cfg(all(target_os = "android", not(bluer_available), not(test)))]
|
||||
fn ble_blocker(&self) -> Option<&'static str> {
|
||||
if self.ble_radio.is_some() {
|
||||
None
|
||||
} else {
|
||||
Some("no BLE radio was armed before start")
|
||||
}
|
||||
}
|
||||
|
||||
/// Why this build cannot construct a configured BLE instance: it has no
|
||||
/// backend at all. A test build lands here too, since its BLE transport
|
||||
/// is the in-memory double and is never built from config.
|
||||
#[cfg(not(any(
|
||||
all(bluer_available, not(test)),
|
||||
all(target_os = "android", not(bluer_available), not(test))
|
||||
)))]
|
||||
fn ble_blocker(&self) -> Option<&'static str> {
|
||||
Some("this build has no BLE backend")
|
||||
}
|
||||
|
||||
/// Find an operational transport that matches the given transport type name.
|
||||
fn find_transport_for_type(&self, transport_type: &str) -> Option<TransportId> {
|
||||
self.transports
|
||||
|
||||
@@ -3630,6 +3630,74 @@ fn app_owned_ble_radio_seam_is_absent_until_armed() {
|
||||
assert!(node.ble_radio.is_none());
|
||||
}
|
||||
|
||||
/// A configured `ble:` block that this build cannot turn into a transport is
|
||||
/// named in a warning, once per instance, rather than dropped silently.
|
||||
///
|
||||
/// `BleConfig` parses on every platform, so a node on a build with no BLE
|
||||
/// backend (macOS, Windows, FreeBSD, musl, and a test build) would otherwise
|
||||
/// start and report healthy with the configured radio simply absent. Not
|
||||
/// `cfg`-gated: the warning is for exactly the builds that lack BLE.
|
||||
#[tokio::test]
|
||||
async fn configured_ble_instances_each_draw_a_warning_when_no_backend_can_build_them() {
|
||||
let mut config = crate::Config::new();
|
||||
config.node.control.enabled = false;
|
||||
config.transports.ble = crate::config::TransportInstances::Named(
|
||||
[
|
||||
("alpha".to_string(), crate::config::BleConfig::default()),
|
||||
("beta".to_string(), crate::config::BleConfig::default()),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
);
|
||||
let mut node = make_node_with(config);
|
||||
let (tx, _rx) = packet_channel(8);
|
||||
|
||||
let (logs, guard) = crate::testutil::capture_logs_scoped();
|
||||
let transports = node.create_transports(&tx).await;
|
||||
drop(guard);
|
||||
|
||||
assert!(
|
||||
transports.is_empty(),
|
||||
"no transport can be built from a BLE block on this build",
|
||||
);
|
||||
let warnings = logs.warnings();
|
||||
for instance in ["alpha", "beta"] {
|
||||
let field = format!("instance=\"{instance}\"");
|
||||
let hits = warnings
|
||||
.iter()
|
||||
.filter(|line| line.contains("ignoring configured instance") && line.contains(&field))
|
||||
.count();
|
||||
assert_eq!(
|
||||
hits, 1,
|
||||
"expected one warning naming BLE instance {instance}, got {warnings:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The healthy side of the check above: with no `ble:` block there is nothing
|
||||
/// to warn about, so the new warning must not fire on an ordinary config.
|
||||
#[tokio::test]
|
||||
async fn a_node_without_ble_config_draws_no_ble_warning() {
|
||||
let mut config = crate::Config::new();
|
||||
config.node.control.enabled = false;
|
||||
let mut node = make_node_with(config);
|
||||
let (tx, _rx) = packet_channel(8);
|
||||
|
||||
let (logs, guard) = crate::testutil::capture_logs_scoped();
|
||||
let transports = node.create_transports(&tx).await;
|
||||
drop(guard);
|
||||
|
||||
assert!(
|
||||
transports.is_empty(),
|
||||
"the default config builds no transport"
|
||||
);
|
||||
let warnings = logs.warnings();
|
||||
assert!(
|
||||
!warnings.iter().any(|line| line.contains("BLE transport")),
|
||||
"no BLE block is configured, got {warnings:?}",
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
mod test_radio {
|
||||
use crate::transport::ble::addr::BleAddr;
|
||||
|
||||
Reference in New Issue
Block a user