[system-health-check] check_and_set_system_health
Merges check_system_health and set_active_configuration_healthy into a
single new operation with the following semantics:
- If the current configuration is marked "Pending" according to the
paver, run health checks. If they fail, return an error. Eventually,
seeing this error will cause system-update-checker and omaha-client
to trigger reboot.
- Otherwise, mark the current configuration as healthy and the
alternate configuration as unbootable.
Test: did an OTA, checked that the system logs were as expected on
first boot (set healthy followed by set unbootable), and that
//src/sys/pkg:tests passed on the newly updated system. Rebooted the
machine and repeated this process, verifying the "skipping health
checks" message appeared.
Fixed: 51480
Change-Id: I90a0952b3fe702f1f90184bd4497b00c98438f80
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/442202
Reviewed-by: Aaron Wood <aaronwood@google.com>
Reviewed-by: Zach Kirschenbaum <zkbaum@google.com>
Reviewed-by: John Wittrock <wittrock@google.com>
Testability-Review: Zach Kirschenbaum <zkbaum@google.com>
Commit-Queue: Hunter Freyer <hjfreyer@google.com>
diff --git a/src/sys/pkg/bin/omaha-client/src/main.rs b/src/sys/pkg/bin/omaha-client/src/main.rs
index e119f6e..8dc5e2b 100644
--- a/src/sys/pkg/bin/omaha-client/src/main.rs
+++ b/src/sys/pkg/bin/omaha-client/src/main.rs
@@ -176,14 +176,15 @@
}
async fn check_and_set_system_health_impl() -> Result<(), Error> {
- system_health_check::check_system_health().await?;
-
let paver = fuchsia_component::client::connect_to_service::<PaverMarker>()?;
let (boot_manager, boot_manager_server_end) = ::fidl::endpoints::create_proxy()?;
paver
.find_boot_manager(boot_manager_server_end)
.context("transport error while calling find_boot_manager()")?;
-
- system_health_check::set_active_configuration_healthy(&boot_manager).await
+ // NOTE(fxbug.dev/63642): The docs for check_and_set_system_health say that we should respond to
+ // an error here by rebooting, but we'll be refactoring this away Soon™, so for now we just log
+ // it.
+ system_health_check::check_and_set_system_health(&boot_manager).await?;
+ Ok(())
}
diff --git a/src/sys/pkg/bin/system-update-checker/src/main.rs b/src/sys/pkg/bin/system-update-checker/src/main.rs
index 3f8d5cd..b6859a5 100644
--- a/src/sys/pkg/bin/system-update-checker/src/main.rs
+++ b/src/sys/pkg/bin/system-update-checker/src/main.rs
@@ -156,14 +156,15 @@
}
async fn check_and_set_system_health_impl() -> Result<(), Error> {
- system_health_check::check_system_health().await?;
-
let paver = fuchsia_component::client::connect_to_service::<PaverMarker>()?;
let (boot_manager, boot_manager_server_end) = fidl::endpoints::create_proxy()?;
paver
.find_boot_manager(boot_manager_server_end)
.context("transport error while calling find_boot_manager()")?;
-
- system_health_check::set_active_configuration_healthy(&boot_manager).await
+ // NOTE(fxbug.dev/63642): The docs for check_and_set_system_health say that we should respond to
+ // an error here by rebooting, but we'll be refactoring this away Soon™, so for now we just log
+ // it.
+ system_health_check::check_and_set_system_health(&boot_manager).await?;
+ Ok(())
}
diff --git a/src/sys/pkg/lib/system-health-check/BUILD.gn b/src/sys/pkg/lib/system-health-check/BUILD.gn
index 3f86efd..375aa94 100644
--- a/src/sys/pkg/lib/system-health-check/BUILD.gn
+++ b/src/sys/pkg/lib/system-health-check/BUILD.gn
@@ -23,13 +23,12 @@
"//third_party/rust_crates:thiserror",
]
- test_deps = [ "//src/sys/pkg/testing/mock-paver" ]
-
- sources = [
- "src/check.rs",
- "src/lib.rs",
- "src/mark.rs",
+ test_deps = [
+ "//src/sys/pkg/testing/mock-paver",
+ "//third_party/rust_crates:matches",
]
+
+ sources = [ "src/lib.rs" ]
}
fuchsia_unittest_package("system-health-check-tests") {
diff --git a/src/sys/pkg/lib/system-health-check/README.md b/src/sys/pkg/lib/system-health-check/README.md
index 6cc42cf..8fc27f8 100644
--- a/src/sys/pkg/lib/system-health-check/README.md
+++ b/src/sys/pkg/lib/system-health-check/README.md
@@ -1,11 +1,9 @@
# System Health Check
-This crate exposes 2 helper functions, one to determine if a running system is
-healthy after an OTA, and another to inform the paver service that the current
-system is healthy.
+This crate exposes a helper function that determines if a running system is
+healthy after an OTA, and if it is, informs the paver service.
Since a system can be configured to either use the system-update-checker or
omaha-client components to discover and initiate base package updates and both
-components need the ability to check the system health, this functionality is
-maintained in this crate shared by both components.
-
+components need the ability to check and update the system health, this
+functionality is maintained in this crate shared by both components.
\ No newline at end of file
diff --git a/src/sys/pkg/lib/system-health-check/src/check.rs b/src/sys/pkg/lib/system-health-check/src/check.rs
deleted file mode 100644
index 9cae81b..0000000
--- a/src/sys/pkg/lib/system-health-check/src/check.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use anyhow::Error;
-
-/// Future resolves once it has determined the system's health state.
-/// Returns Ok(()) on healthy and Err(reason) on unhealthy.
-/// Used after a system update to determine if the device should be rolled back.
-pub async fn check_system_health() -> Result<(), Error> {
- Ok(())
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use fuchsia_async::{self as fasync};
-
- #[fasync::run_singlethreaded(test)]
- async fn test_succeeds() -> Result<(), Error> {
- check_system_health().await
- }
-}
diff --git a/src/sys/pkg/lib/system-health-check/src/lib.rs b/src/sys/pkg/lib/system-health-check/src/lib.rs
index a5fa1f8..4966fc4 100644
--- a/src/sys/pkg/lib/system-health-check/src/lib.rs
+++ b/src/sys/pkg/lib/system-health-check/src/lib.rs
@@ -2,8 +2,336 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-mod check;
-mod mark;
+use {
+ fidl_fuchsia_paver as paver, fuchsia_syslog::fx_log_info, fuchsia_zircon::Status,
+ thiserror::Error,
+};
-pub use check::check_system_health;
-pub use mark::set_active_configuration_healthy;
+/// Error condition that may be returned by check_and_set_system_health.
+#[derive(Error, Debug)]
+pub enum Error {
+ #[error("health check failed")]
+ HealthCheck(#[source] anyhow::Error),
+
+ #[error("the current configuration ({_0:?}) is unbootable. This should never happen.")]
+ CurrentConfigurationUnbootable(paver::Configuration),
+
+ #[error("BootManager returned non-ok status while calling {method_name:}")]
+ BootManagerStatus {
+ method_name: &'static str,
+ #[source]
+ status: Status,
+ },
+
+ #[error("fidl error while calling BootManager method {method_name:}")]
+ BootManagerFidl {
+ method_name: &'static str,
+ #[source]
+ error: fidl::Error,
+ },
+}
+
+/// Helper to convert fidl's nested errors.
+trait BootManagerResultExt {
+ type T;
+
+ fn into_boot_manager_result(self, method_name: &'static str) -> Result<Self::T, Error>;
+}
+
+impl BootManagerResultExt for Result<i32, fidl::Error> {
+ type T = ();
+
+ fn into_boot_manager_result(
+ self: Result<i32, fidl::Error>,
+ method_name: &'static str,
+ ) -> Result<(), Error> {
+ match self.map(Status::ok) {
+ Ok(Ok(())) => Ok(()),
+ Ok(Err(status)) => Err(Error::BootManagerStatus { status, method_name }),
+ Err(error) => Err(Error::BootManagerFidl { error, method_name }),
+ }
+ }
+}
+
+impl<T> BootManagerResultExt for Result<Result<T, i32>, fidl::Error> {
+ type T = T;
+
+ fn into_boot_manager_result(
+ self: Result<Result<Self::T, i32>, fidl::Error>,
+ method_name: &'static str,
+ ) -> Result<Self::T, Error> {
+ match self {
+ Ok(Ok(value)) => Ok(value),
+ Ok(Err(raw)) => {
+ Err(Error::BootManagerStatus { status: Status::from_raw(raw), method_name })
+ }
+ Err(error) => Err(Error::BootManagerFidl { error, method_name }),
+ }
+ }
+}
+
+/// Puts BootManager metadata into a happy state, provided we believe the system can OTA.
+///
+/// The "happy state" is:
+/// - The current configuration is active and marked Healthy.
+/// - The alternate configuration is marked Unbootable.
+///
+/// First we decide whether the system is likely to be functional enough to apply an OTA:
+/// - If the current configuration is marked Pending, we run a variety of checks and return
+/// Error::HealthCheck if they fail.
+/// - If the current configuration is marked Healthy, it means the system already passed the health
+/// checks at some point. We assume they would still pass, and skip them.
+/// - If the current configuration is marked Unbootable, and this function returns
+/// Error::CurrentConfigurationUnbootable, because that should never happen.
+///
+/// Assuming we get through all that, we tell the paver to mark the current configuration Healthy
+/// and the alternate configuration Unbootable.
+///
+/// As a special case, if the current configuration is Recovery, we return Ok without performing any
+/// checks or making any changes.
+///
+/// If this returns an error, it likely means that the system is somehow busted, and that it should
+/// be rebooted. Rebooting will hopefully either fix the issue or decrement the boot counter,
+/// eventually leading to a rollback.
+pub async fn check_and_set_system_health(
+ boot_manager: &paver::BootManagerProxy,
+) -> Result<(), Error> {
+ let (current_config, alternate_config) = match boot_manager
+ .query_current_configuration()
+ .await
+ .into_boot_manager_result("query_current_configuration")
+ {
+ Err(Error::BootManagerFidl {
+ error: fidl::Error::ClientChannelClosed { status: Status::NOT_SUPPORTED, .. },
+ ..
+ }) => {
+ fx_log_info!("ABR not supported: skipping health checks and boot metadata updates");
+ return Ok(());
+ }
+ Err(e) => return Err(e),
+
+ Ok(paver::Configuration::Recovery) => {
+ fx_log_info!("System in recovery: skipping health checks and boot metadata updates");
+ return Ok(());
+ }
+
+ Ok(paver::Configuration::A) => (paver::Configuration::A, paver::Configuration::B),
+ Ok(paver::Configuration::B) => (paver::Configuration::B, paver::Configuration::A),
+ };
+
+ // Note: at this point, we know that ABR is supported and we're not in Recovery.
+ let current_config_status = boot_manager
+ .query_configuration_status(current_config)
+ .await
+ .into_boot_manager_result("query_configuration_status")?;
+
+ // Run the health checks if `current_config` isn't already marked `Healthy`, and pass any
+ // failures up to the caller.
+ match current_config_status {
+ paver::ConfigurationStatus::Healthy => {
+ fx_log_info!("current configuration is already healthy; skipping health checks");
+ }
+ paver::ConfigurationStatus::Unbootable => {
+ return Err(Error::CurrentConfigurationUnbootable(current_config))
+ }
+ paver::ConfigurationStatus::Pending => {
+ // Bail out if the system is unhealthy.
+ let () = check_system_health().await.map_err(Error::HealthCheck)?;
+ }
+ }
+
+ // Do all writes inside this function to ensure that we call flush no matter what.
+ async fn internal_write(
+ boot_manager: &paver::BootManagerProxy,
+ current_config: paver::Configuration,
+ alternate_config: paver::Configuration,
+ ) -> Result<(), Error> {
+ let () = boot_manager
+ .set_configuration_healthy(current_config)
+ .await
+ .into_boot_manager_result("set_configuration_healthy")?;
+ let () = boot_manager
+ .set_configuration_unbootable(alternate_config)
+ .await
+ .into_boot_manager_result("set_configuration_unbootable")?;
+ Ok(())
+ }
+
+ // Capture the result of the writes so we can return it after we flush.
+ let write_result = internal_write(boot_manager, current_config, alternate_config).await;
+
+ let () = boot_manager.flush().await.into_boot_manager_result("flush")?;
+
+ write_result
+}
+
+/// Dummy function to indicate where health checks will eventually go, and how to handle associated
+/// errors.
+async fn check_system_health() -> Result<(), anyhow::Error> {
+ Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+ #![cfg(test)]
+ use {
+ super::*,
+ fidl_fuchsia_paver::Configuration,
+ fuchsia_async as fasync,
+ fuchsia_zircon::Status,
+ matches::assert_matches,
+ mock_paver::{MockPaverServiceBuilder, PaverEvent},
+ std::sync::Arc,
+ };
+
+ async fn run_with_healthy_current(
+ current_config: Configuration,
+ alternate_config: Configuration,
+ ) {
+ let paver = Arc::new(
+ MockPaverServiceBuilder::new()
+ .current_config(current_config)
+ .config_status_hook(|_| paver::ConfigurationStatus::Healthy)
+ .build(),
+ );
+ check_and_set_system_health(&paver.spawn_boot_manager_service()).await.unwrap();
+ assert_eq!(
+ paver.take_events(),
+ vec![
+ PaverEvent::QueryCurrentConfiguration,
+ PaverEvent::QueryConfigurationStatus { configuration: current_config },
+ PaverEvent::SetConfigurationHealthy { configuration: current_config },
+ PaverEvent::SetConfigurationUnbootable { configuration: alternate_config },
+ PaverEvent::BootManagerFlush,
+ ]
+ );
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_check_and_set_healthy_config_a() {
+ run_with_healthy_current(Configuration::A, Configuration::B).await
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_check_and_set_healthy_config_b() {
+ run_with_healthy_current(Configuration::B, Configuration::A).await
+ }
+
+ async fn run_with_pending_current(
+ current_config: Configuration,
+ alternate_config: Configuration,
+ ) {
+ let paver = Arc::new(
+ MockPaverServiceBuilder::new()
+ .current_config(current_config)
+ .config_status_hook(|_| paver::ConfigurationStatus::Pending)
+ .build(),
+ );
+ check_and_set_system_health(&paver.spawn_boot_manager_service()).await.unwrap();
+ assert_eq!(
+ paver.take_events(),
+ vec![
+ PaverEvent::QueryCurrentConfiguration,
+ PaverEvent::QueryConfigurationStatus { configuration: current_config },
+ // The health check gets performed here, but we don't see any side-effects.
+ PaverEvent::SetConfigurationHealthy { configuration: current_config },
+ PaverEvent::SetConfigurationUnbootable { configuration: alternate_config },
+ PaverEvent::BootManagerFlush,
+ ]
+ );
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_check_and_set_pending_config_a() {
+ run_with_pending_current(Configuration::A, Configuration::B).await
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_check_and_set_pending_config_b() {
+ run_with_pending_current(Configuration::B, Configuration::A).await
+ }
+
+ async fn run_with_unbootable_current(current_config: Configuration) {
+ let paver = Arc::new(
+ MockPaverServiceBuilder::new()
+ .current_config(current_config)
+ .config_status_hook(|_| paver::ConfigurationStatus::Unbootable)
+ .build(),
+ );
+ assert_matches!(
+ check_and_set_system_health(&paver.spawn_boot_manager_service()).await,
+ Err(Error::CurrentConfigurationUnbootable(cc))
+ if cc == current_config
+ );
+ assert_eq!(
+ paver.take_events(),
+ vec![
+ PaverEvent::QueryCurrentConfiguration,
+ PaverEvent::QueryConfigurationStatus { configuration: current_config },
+ ]
+ );
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_check_and_set_unbootable_config_a_returns_error() {
+ run_with_unbootable_current(Configuration::A).await
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_check_and_set_unbootable_config_b_returns_error() {
+ run_with_unbootable_current(Configuration::B).await
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_does_not_change_metadata_when_device_does_not_support_abr() {
+ let paver = Arc::new(
+ MockPaverServiceBuilder::new()
+ .boot_manager_close_with_epitaph(Status::NOT_SUPPORTED)
+ .build(),
+ );
+
+ check_and_set_system_health(&paver.spawn_boot_manager_service()).await.unwrap();
+ assert_eq!(paver.take_events(), vec![]);
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_does_not_change_metadata_when_device_in_recovery() {
+ let paver = Arc::new(
+ MockPaverServiceBuilder::new()
+ .current_config(Configuration::Recovery)
+ .config_status_hook(|_| paver::ConfigurationStatus::Healthy)
+ .build(),
+ );
+ check_and_set_system_health(&paver.spawn_boot_manager_service()).await.unwrap();
+ assert_eq!(paver.take_events(), vec![PaverEvent::QueryCurrentConfiguration]);
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_fails_when_set_healthy_fails() {
+ let paver = Arc::new(
+ MockPaverServiceBuilder::new()
+ .call_hook(|e| match e {
+ PaverEvent::SetConfigurationHealthy { .. } => Status::OUT_OF_RANGE,
+ _ => Status::OK,
+ })
+ .build(),
+ );
+
+ assert_matches!(
+ check_and_set_system_health(&paver.spawn_boot_manager_service()).await,
+ Err(Error::BootManagerStatus {
+ method_name: "set_configuration_healthy",
+ status: Status::OUT_OF_RANGE
+ })
+ );
+ assert_eq!(
+ paver.take_events(),
+ vec![
+ PaverEvent::QueryCurrentConfiguration,
+ PaverEvent::QueryConfigurationStatus { configuration: Configuration::A },
+ PaverEvent::SetConfigurationHealthy { configuration: Configuration::A },
+ PaverEvent::BootManagerFlush,
+ ]
+ );
+ }
+}
diff --git a/src/sys/pkg/lib/system-health-check/src/mark.rs b/src/sys/pkg/lib/system-health-check/src/mark.rs
deleted file mode 100644
index 3714a7e..0000000
--- a/src/sys/pkg/lib/system-health-check/src/mark.rs
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use {
- anyhow::{format_err, Context},
- fidl_fuchsia_paver::{BootManagerProxy, Configuration},
- fuchsia_syslog::fx_log_info,
- fuchsia_zircon::Status,
-};
-
-/// Inform the Paver service that Fuchsia booted successfully, so it marks the partition healthy
-/// and stops decrementing the boot counter.
-pub async fn set_active_configuration_healthy(
- boot_manager: &BootManagerProxy,
-) -> Result<(), anyhow::Error> {
- // TODO(51480): This should use the "current" configuration, not active, when they differ.
- let active_config = match boot_manager
- .query_active_configuration()
- .await
- .map(|res| res.map_err(Status::from_raw))
- {
- Ok(Ok(active_config)) => active_config,
- Err(fidl::Error::ClientChannelClosed { status: Status::NOT_SUPPORTED, .. }) => {
- fx_log_info!("ABR not supported");
- return Ok(());
- }
- Ok(Err(Status::NOT_SUPPORTED)) => {
- fx_log_info!("no partition is active; we're in recovery");
- return Ok(());
- }
- Err(e) => {
- return Err(e).context("transport error while calling query_active_configuration()")
- }
- Ok(Err(e)) => {
- return Err(e).context("paver error while calling query_active_configuration()")
- }
- };
-
- // Note: at this point, we know that ABR is supported.
- boot_manager
- .set_configuration_healthy(active_config)
- .await
- .map(Status::ok)
- .with_context(|| {
- format!("transport error while calling set_configuration_healthy({:?})", active_config)
- })?
- .with_context(|| {
- format!("paver error while calling set_configuration_healthy({:?})", active_config)
- })?;
-
- // Find out the inactive partition and mark it as unbootable.
- let inactive_config = match active_config {
- Configuration::A => Configuration::B,
- Configuration::B => Configuration::A,
- Configuration::Recovery => return Err(format_err!("Recovery should not be active")),
- };
- boot_manager
- .set_configuration_unbootable(inactive_config)
- .await
- .map(Status::ok)
- .with_context(|| {
- format!(
- "transport error while calling set_configuration_unbootable({:?})",
- inactive_config
- )
- })?
- .with_context(|| {
- format!("paver error while calling set_configuration_unbootable({:?})", inactive_config)
- })?;
-
- boot_manager
- .flush()
- .await
- .map(Status::ok)
- .context("transport error while calling flush()")?
- .context("paver error while calling flush()")?;
-
- Ok(())
-}
-
-#[cfg(test)]
-mod tests {
- use {
- super::*,
- fidl_fuchsia_paver::Configuration,
- fuchsia_async as fasync,
- fuchsia_zircon::Status,
- mock_paver::{MockPaverServiceBuilder, PaverEvent},
- std::sync::Arc,
- };
-
- // We should call SetConfigurationUnbootable when the device supports ABR and is not in recovery
- #[fasync::run_singlethreaded(test)]
- async fn test_calls_set_configuration_unbootable_config_a_active() {
- let paver_service =
- Arc::new(MockPaverServiceBuilder::new().active_config(Configuration::A).build());
- set_active_configuration_healthy(&paver_service.spawn_boot_manager_service())
- .await
- .expect("setting active succeeds");
- assert_eq!(
- paver_service.take_events(),
- vec![
- PaverEvent::QueryActiveConfiguration,
- PaverEvent::SetConfigurationHealthy { configuration: Configuration::A },
- PaverEvent::SetConfigurationUnbootable { configuration: Configuration::B },
- PaverEvent::BootManagerFlush
- ]
- );
- }
-
- // We should call SetConfigurationUnbootable when the device supports ABR and is not in recovery
- #[fasync::run_singlethreaded(test)]
- async fn test_calls_set_configuration_unbootable_config_b_active() {
- let paver_service =
- Arc::new(MockPaverServiceBuilder::new().active_config(Configuration::B).build());
- set_active_configuration_healthy(&paver_service.spawn_boot_manager_service())
- .await
- .expect("setting active succeeds");
- assert_eq!(
- paver_service.take_events(),
- vec![
- PaverEvent::QueryActiveConfiguration,
- PaverEvent::SetConfigurationHealthy { configuration: Configuration::B },
- PaverEvent::SetConfigurationUnbootable { configuration: Configuration::A },
- PaverEvent::BootManagerFlush
- ]
- );
- }
-
- #[fasync::run_singlethreaded(test)]
- async fn test_does_not_change_metadata_when_device_does_not_support_abr() {
- let paver_service = Arc::new(
- MockPaverServiceBuilder::new()
- .boot_manager_close_with_epitaph(Status::NOT_SUPPORTED)
- .build(),
- );
- set_active_configuration_healthy(&paver_service.spawn_boot_manager_service())
- .await
- .expect("setting active succeeds");
- assert_eq!(paver_service.take_events(), Vec::new());
- }
-
- #[fasync::run_singlethreaded(test)]
- async fn test_does_not_change_metadata_when_device_in_recovery() {
- let paver_service =
- Arc::new(MockPaverServiceBuilder::new().active_config(Configuration::Recovery).build());
- set_active_configuration_healthy(&paver_service.spawn_boot_manager_service())
- .await
- .expect("setting active succeeds");
- assert_eq!(paver_service.take_events(), vec![PaverEvent::QueryActiveConfiguration]);
- }
-}
diff --git a/src/sys/pkg/tests/omaha-client/src/lib.rs b/src/sys/pkg/tests/omaha-client/src/lib.rs
index 088a0e5..286ffd7 100644
--- a/src/sys/pkg/tests/omaha-client/src/lib.rs
+++ b/src/sys/pkg/tests/omaha-client/src/lib.rs
@@ -337,46 +337,51 @@
}
}
-// Test will hang if omaha-client does not call set_configuration_healthy on the paver service.
+// Test will hang if omaha-client does not contact the paver service.
#[fasync::run_singlethreaded(test)]
-async fn test_calls_set_configuration_healthy() {
- let (send, recv) = oneshot::channel();
- let send = Mutex::new(Some(send));
+async fn test_calls_paver_service() {
+ let (send, recv) = mpsc::unbounded();
let paver = MockPaverServiceBuilder::new()
- .call_hook(move |event| {
- match event {
- PaverEvent::SetConfigurationHealthy { configuration } => {
- send.lock().take().unwrap().send(*configuration).unwrap();
- }
- _ => {}
- }
- Status::OK
- })
+ .current_config(Configuration::A)
+ .event_hook(move |e| send.unbounded_send(e.to_owned()).expect("channel stayed open"))
.build();
let _env = TestEnvBuilder::new().paver(paver).build();
- // wait for the call hook to notify `send`.
- assert_matches!(recv.await, Ok(Configuration::A));
+ assert_eq!(
+ recv.take(5).collect::<Vec<PaverEvent>>().await,
+ vec![
+ PaverEvent::QueryCurrentConfiguration,
+ PaverEvent::QueryConfigurationStatus { configuration: Configuration::A },
+ PaverEvent::SetConfigurationHealthy { configuration: Configuration::A },
+ PaverEvent::SetConfigurationUnbootable { configuration: Configuration::B },
+ PaverEvent::BootManagerFlush
+ ]
+ );
}
-// Test will hang if omaha-client does not call set_configuration_healthy on the paver service.
+// Test will hang if omaha-client does not contact the paver service.
#[fasync::run_singlethreaded(test)]
-async fn test_update_manager_checknow_works_after_set_configuration_healthy_fails() {
- let (send, recv) = oneshot::channel();
- let send = Mutex::new(Some(send));
+async fn test_update_manager_checknow_works_after_paver_service_fails() {
+ let (send, recv) = mpsc::unbounded();
let paver = MockPaverServiceBuilder::new()
+ .current_config(Configuration::B)
+ .event_hook(move |e| send.unbounded_send(e.to_owned()).expect("channel stayed open"))
.call_hook(move |event| match event {
- PaverEvent::SetConfigurationHealthy { configuration } => {
- send.lock().take().unwrap().send(*configuration).unwrap();
- Status::INTERNAL
- }
+ PaverEvent::SetConfigurationHealthy { .. } => Status::INTERNAL,
_ => Status::OK,
})
.build();
let env = TestEnvBuilder::new().paver(paver).build();
- // wait for the call hook to notify `send`.
- assert_matches!(recv.await, Ok(Configuration::A));
+ assert_eq!(
+ recv.take(4).collect::<Vec<PaverEvent>>().await,
+ vec![
+ PaverEvent::QueryCurrentConfiguration,
+ PaverEvent::QueryConfigurationStatus { configuration: Configuration::B },
+ PaverEvent::SetConfigurationHealthy { configuration: Configuration::B },
+ PaverEvent::BootManagerFlush
+ ]
+ );
let mut stream = env.check_now().await;
assert_matches!(stream.next().await, Some(_));
diff --git a/src/sys/pkg/tests/system-update-checker/src/lib.rs b/src/sys/pkg/tests/system-update-checker/src/lib.rs
index 5f56527..3cdd74e 100644
--- a/src/sys/pkg/tests/system-update-checker/src/lib.rs
+++ b/src/sys/pkg/tests/system-update-checker/src/lib.rs
@@ -215,8 +215,8 @@
assert_eq!(
env.proxies.paver_events.take(2).collect::<Vec<PaverEvent>>().await,
vec![
- PaverEvent::QueryActiveConfiguration,
- PaverEvent::SetConfigurationHealthy { configuration: Configuration::A }
+ PaverEvent::QueryCurrentConfiguration,
+ PaverEvent::QueryConfigurationStatus { configuration: Configuration::A }
]
);
}
@@ -228,7 +228,7 @@
assert_eq!(
env.proxies.paver_events.take(1).collect::<Vec<PaverEvent>>().await,
- vec![PaverEvent::QueryActiveConfiguration]
+ vec![PaverEvent::QueryCurrentConfiguration]
);
assert_eq!(
@@ -244,7 +244,7 @@
assert_eq!(
env.proxies.paver_events.take(1).collect::<Vec<PaverEvent>>().await,
- vec![PaverEvent::QueryActiveConfiguration]
+ vec![PaverEvent::QueryCurrentConfiguration]
);
let (client_end, request_stream) =