| // 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. |
| |
| mod bounded_node; |
| |
| use crate::fidl::State; |
| use chrono::{DateTime, Utc}; |
| use fuchsia_inspect::{Node, Property, StringProperty}; |
| use omaha_client::{ |
| common::{App, ProtocolState, UpdateCheckSchedule}, |
| configuration::{Config, Updater}, |
| protocol::request::OS, |
| state_machine::{update_check, UpdateCheckError}, |
| }; |
| use std::collections::VecDeque; |
| use std::time::SystemTime; |
| |
| pub use bounded_node::BoundedNode; |
| |
| pub struct ConfigurationNode { |
| _node: Node, |
| updater: UpdaterNode, |
| os: OsNode, |
| omaha: OmahaNode, |
| } |
| |
| impl ConfigurationNode { |
| pub fn new(configuration_node: Node) -> Self { |
| ConfigurationNode { |
| updater: UpdaterNode::new(configuration_node.create_child("updater")), |
| os: OsNode::new(configuration_node.create_child("os")), |
| omaha: OmahaNode::new(configuration_node.create_child("omaha")), |
| _node: configuration_node, |
| } |
| } |
| |
| pub fn set(&self, config: &Config) { |
| self.updater.set(&config.updater); |
| self.os.set(&config.os); |
| self.omaha.set(&config.service_url); |
| } |
| } |
| |
| struct UpdaterNode { |
| _node: Node, |
| name: StringProperty, |
| version: StringProperty, |
| } |
| |
| impl UpdaterNode { |
| fn new(updater_node: Node) -> Self { |
| UpdaterNode { |
| name: updater_node.create_string("name", ""), |
| version: updater_node.create_string("version", ""), |
| _node: updater_node, |
| } |
| } |
| |
| fn set(&self, updater: &Updater) { |
| self.name.set(&updater.name); |
| self.version.set(&updater.version.to_string()); |
| } |
| } |
| |
| struct OsNode { |
| _node: Node, |
| platform: StringProperty, |
| version: StringProperty, |
| service_pack: StringProperty, |
| arch: StringProperty, |
| } |
| |
| impl OsNode { |
| fn new(os_node: Node) -> Self { |
| OsNode { |
| platform: os_node.create_string("platform", ""), |
| version: os_node.create_string("version", ""), |
| service_pack: os_node.create_string("service_pack", ""), |
| arch: os_node.create_string("arch", ""), |
| _node: os_node, |
| } |
| } |
| |
| fn set(&self, os: &OS) { |
| self.platform.set(&os.platform); |
| self.version.set(&os.version); |
| self.service_pack.set(&os.service_pack); |
| self.arch.set(&os.arch); |
| } |
| } |
| |
| struct OmahaNode { |
| _node: Node, |
| service_url: StringProperty, |
| } |
| |
| impl OmahaNode { |
| fn new(omaha_node: Node) -> Self { |
| OmahaNode { service_url: omaha_node.create_string("service_url", ""), _node: omaha_node } |
| } |
| |
| fn set(&self, service_url: &str) { |
| self.service_url.set(service_url); |
| } |
| } |
| |
| pub struct AppsNode { |
| _node: Node, |
| apps: StringProperty, |
| } |
| |
| impl AppsNode { |
| pub fn new(apps_node: Node) -> Self { |
| AppsNode { apps: apps_node.create_string("apps", ""), _node: apps_node } |
| } |
| |
| pub fn set(&self, apps: &[App]) { |
| self.apps.set(&format!("{:?}", apps)); |
| } |
| } |
| |
| pub struct StateNode { |
| _node: Node, |
| state: StringProperty, |
| } |
| |
| impl StateNode { |
| pub fn new(state_node: Node) -> Self { |
| StateNode { state: state_node.create_string("state", ""), _node: state_node } |
| } |
| |
| pub fn set(&self, state: &State) { |
| self.state.set(&format!("{:?}", state)); |
| } |
| } |
| |
| pub struct ScheduleNode { |
| _node: Node, |
| schedule: StringProperty, |
| } |
| |
| impl ScheduleNode { |
| pub fn new(schedule_node: Node) -> Self { |
| ScheduleNode { schedule: schedule_node.create_string("schedule", ""), _node: schedule_node } |
| } |
| |
| pub fn set(&self, schedule: &UpdateCheckSchedule) { |
| self.schedule.set(&format!("{:?}", schedule)); |
| } |
| } |
| |
| pub struct ProtocolStateNode { |
| _node: Node, |
| protocol_state: StringProperty, |
| } |
| |
| impl ProtocolStateNode { |
| pub fn new(protocol_state_node: Node) -> Self { |
| ProtocolStateNode { |
| protocol_state: protocol_state_node.create_string("protocol_state", ""), |
| _node: protocol_state_node, |
| } |
| } |
| |
| pub fn set(&self, protocol_state: &ProtocolState) { |
| self.protocol_state.set(&format!("{:?}", protocol_state)); |
| } |
| } |
| |
| pub struct LastResultsNode { |
| node: Node, |
| last_results: VecDeque<StringProperty>, |
| } |
| |
| impl LastResultsNode { |
| pub fn new(last_results_node: Node) -> Self { |
| LastResultsNode { node: last_results_node, last_results: VecDeque::new() } |
| } |
| |
| pub fn add_result( |
| &mut self, |
| start_time: SystemTime, |
| result: &Result<update_check::Response, UpdateCheckError>, |
| ) { |
| // Use formatted time string as the name of the property. |
| let time_str = DateTime::<Utc>::from(start_time).to_rfc3339(); |
| let result_property = self.node.create_string(&time_str, format!("{:#?}", result)); |
| self.last_results.push_back(result_property); |
| // Dropping the string property will remove it from inspect. |
| if self.last_results.len() > 10 { |
| self.last_results.pop_front(); |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| use crate::configuration::get_config; |
| use fuchsia_async as fasync; |
| use fuchsia_inspect::{assert_inspect_tree, Inspector}; |
| use omaha_client::{common::UserCounting, protocol::Cohort, state_machine}; |
| use std::time::Duration; |
| |
| #[fasync::run_singlethreaded(test)] |
| async fn test_configuration_node() { |
| let inspector = Inspector::new(); |
| let node = ConfigurationNode::new(inspector.root().create_child("configuration")); |
| node.set(&get_config("0.1.2").await); |
| |
| assert_inspect_tree!( |
| inspector, |
| root: { |
| configuration: { |
| updater: { |
| name: "Fuchsia", |
| version: "0.0.1.0", |
| }, |
| os: { |
| platform: "Fuchsia", |
| version: "0.1.2", |
| service_pack: "", |
| arch: std::env::consts::ARCH, |
| }, |
| omaha: { |
| service_url: "https://clients2.google.com/service/update2/fuchsia/json", |
| }, |
| } |
| } |
| ); |
| } |
| |
| #[test] |
| fn test_apps_node() { |
| let inspector = Inspector::new(); |
| let node = AppsNode::new(inspector.root().create_child("apps")); |
| let apps = vec![ |
| App::new("id", [1, 0], Cohort::default()), |
| App::new("id_2", [1, 2, 4], Cohort::new("cohort")), |
| ]; |
| node.set(&apps); |
| |
| assert_inspect_tree!( |
| inspector, |
| root: { |
| apps: { |
| apps: format!("{:?}", apps), |
| } |
| } |
| ); |
| } |
| |
| #[test] |
| fn test_state_node() { |
| let inspector = Inspector::new(); |
| let node = StateNode::new(inspector.root().create_child("state")); |
| let state = State { |
| manager_state: state_machine::State::CheckingForUpdates, |
| version_available: Some("1.2.3.4".to_string()), |
| install_progress: None, |
| }; |
| node.set(&state); |
| |
| assert_inspect_tree!( |
| inspector, |
| root: { |
| state: { |
| state: format!("{:?}", state), |
| } |
| } |
| ); |
| } |
| |
| #[test] |
| fn test_schedule_node() { |
| let inspector = Inspector::new(); |
| let node = ScheduleNode::new(inspector.root().create_child("schedule")); |
| let schedule = UpdateCheckSchedule::default(); |
| node.set(&schedule); |
| |
| assert_inspect_tree!( |
| inspector, |
| root: { |
| schedule: { |
| schedule: format!("{:?}", schedule), |
| } |
| } |
| ); |
| } |
| |
| #[test] |
| fn test_protocol_state_node() { |
| let inspector = Inspector::new(); |
| let node = ProtocolStateNode::new(inspector.root().create_child("protocol_state")); |
| let protocol_state = ProtocolState::default(); |
| node.set(&protocol_state); |
| |
| assert_inspect_tree!( |
| inspector, |
| root: { |
| protocol_state: { |
| protocol_state: format!("{:?}", protocol_state), |
| } |
| } |
| ); |
| } |
| |
| #[test] |
| fn test_last_results_node() { |
| let inspector = Inspector::new(); |
| let mut node = LastResultsNode::new(inspector.root().create_child("last_results")); |
| let result = Ok(update_check::Response { |
| app_responses: vec![update_check::AppResponse { |
| app_id: "some_id".to_string(), |
| cohort: Cohort::default(), |
| user_counting: UserCounting::ClientRegulatedByDate(None), |
| result: update_check::Action::Updated, |
| }], |
| server_dictated_poll_interval: None, |
| }); |
| node.add_result(SystemTime::UNIX_EPOCH, &result); |
| node.add_result(SystemTime::UNIX_EPOCH + Duration::from_secs(100000), &result); |
| |
| assert_inspect_tree!( |
| inspector, |
| root: { |
| last_results: { |
| "1970-01-01T00:00:00+00:00": format!("{:#?}", result), |
| "1970-01-02T03:46:40+00:00": format!("{:#?}", result), |
| } |
| } |
| ); |
| |
| for i in 0..10 { |
| node.add_result(SystemTime::UNIX_EPOCH + Duration::from_secs(i * 1000000), &result); |
| } |
| assert_inspect_tree!( |
| inspector, |
| root: { |
| last_results: { |
| "1970-01-01T00:00:00+00:00": format!("{:#?}", result), |
| "1970-01-12T13:46:40+00:00": format!("{:#?}", result), |
| "1970-01-24T03:33:20+00:00": format!("{:#?}", result), |
| "1970-02-04T17:20:00+00:00": format!("{:#?}", result), |
| "1970-02-16T07:06:40+00:00": format!("{:#?}", result), |
| "1970-02-27T20:53:20+00:00": format!("{:#?}", result), |
| "1970-03-11T10:40:00+00:00": format!("{:#?}", result), |
| "1970-03-23T00:26:40+00:00": format!("{:#?}", result), |
| "1970-04-03T14:13:20+00:00": format!("{:#?}", result), |
| "1970-04-15T04:00:00+00:00": format!("{:#?}", result), |
| } |
| } |
| ); |
| } |
| } |