1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45//! Wrapper types for the Options table.
67use fuchsia_inspect as inspect;
8use proptest_derive::Arbitrary;
9use serde::{Deserialize, Serialize};
10use thiserror::Error;
1112/// Who or what initiated the update installation.
13#[derive(Clone, Debug, Copy, PartialEq, Arbitrary, Serialize, Deserialize)]
14pub enum Initiator {
15/// The install was initiated by an interactive user, or the user is
16 /// otherwise blocked and waiting for the result of this update.
17User,
1819/// The install was initiated by a service, in the background.
20Service,
21}
2223impl Initiator {
24fn name(&self) -> &'static str {
25match self {
26 Initiator::User => "User",
27 Initiator::Service => "Service",
28 }
29 }
30}
3132/// Configuration options for an update attempt.
33#[derive(Clone, Debug, PartialEq, Arbitrary, Serialize, Deserialize)]
34pub struct Options {
35/// What initiated this update attempt.
36pub initiator: Initiator,
3738/// If an update is already in progress, it's acceptable to instead attach a
39 /// Monitor to that in-progress update instead of failing this request to
40 /// install the update. Setting this option to true may convert situations
41 /// that would have resulted in the ALREADY_IN_PROGRESS to be treated as
42 /// non-error cases. A controller, if provided, will be ignored if the
43 /// running update attempt already has a controller.
44pub allow_attach_to_existing_attempt: bool,
4546/// Determines if the installer should update the recovery partition if an
47 /// update is available. Defaults to true.
48pub should_write_recovery: bool,
49}
5051impl Options {
52/// Serializes Options to a Fuchsia Inspect node.
53pub fn write_to_inspect(&self, node: &inspect::Node) {
54let Options { initiator, allow_attach_to_existing_attempt, should_write_recovery } = self;
55 node.record_string("initiator", initiator.name());
56 node.record_bool("allow_attach_to_existing_attempt", *allow_attach_to_existing_attempt);
57 node.record_bool("should_write_recovery", *should_write_recovery);
58 }
59}
6061/// Errors for parsing fidl_update_installer_ext Options struct.
62#[derive(Error, Debug, PartialEq)]
63pub enum OptionsParseError {
64/// Initiator is None.
65#[error("missing initiator")]
66MissingInitiator,
67}
6869impl TryFrom<fidl_fuchsia_update_installer::Options> for Options {
70type Error = OptionsParseError;
7172fn try_from(data: fidl_fuchsia_update_installer::Options) -> Result<Self, OptionsParseError> {
73let initiator =
74 data.initiator.map(|o| o.into()).ok_or(OptionsParseError::MissingInitiator)?;
7576Ok(Self {
77 initiator,
78 allow_attach_to_existing_attempt: data
79 .allow_attach_to_existing_attempt
80 .unwrap_or(false),
81 should_write_recovery: data.should_write_recovery.unwrap_or(true),
82 })
83 }
84}
8586impl From<&Options> for fidl_fuchsia_update_installer::Options {
87fn from(options: &Options) -> Self {
88Self {
89 initiator: Some(options.initiator.into()),
90 allow_attach_to_existing_attempt: Some(options.allow_attach_to_existing_attempt),
91 should_write_recovery: Some(options.should_write_recovery),
92 ..Default::default()
93 }
94 }
95}
9697impl From<Options> for fidl_fuchsia_update_installer::Options {
98fn from(data: Options) -> Self {
99 (&data).into()
100 }
101}
102103impl From<fidl_fuchsia_update_installer::Initiator> for Initiator {
104fn from(fidl_initiator: fidl_fuchsia_update_installer::Initiator) -> Self {
105match fidl_initiator {
106 fidl_fuchsia_update_installer::Initiator::User => Initiator::User,
107 fidl_fuchsia_update_installer::Initiator::Service => Initiator::Service,
108 }
109 }
110}
111112impl From<Initiator> for fidl_fuchsia_update_installer::Initiator {
113fn from(initiator: Initiator) -> Self {
114match initiator {
115 Initiator::User => fidl_fuchsia_update_installer::Initiator::User,
116 Initiator::Service => fidl_fuchsia_update_installer::Initiator::Service,
117 }
118 }
119}
120121#[cfg(test)]
122mod tests {
123124use super::*;
125use proptest::prelude::*;
126127proptest! {
128#[test]
129/// Verifies that converting any instance of Options to fidl_fuchsia_update_installer::Options
130 /// and back to Options produces exactly the same options that we started with.
131fn options_roundtrips_through_fidl(options: Options) {
132let as_fidl: fidl_fuchsia_update_installer::Options = options.clone().into();
133prop_assert_eq!(as_fidl.try_into(), Ok(options));
134 }
135136#[test]
137/// Verifies that a fidl_fuchsia_update_installer::Options without an Initiator raises an error.
138fn fidl_options_sans_initiator_error(options: Options) {
139let mut as_fidl: fidl_fuchsia_update_installer::Options = options.into();
140 as_fidl.initiator = None;
141prop_assert_eq!(Options::try_from(as_fidl), Err(OptionsParseError::MissingInitiator));
142 }
143 }
144}