blob: 64465a2c87b7009956b38fe2483d85de7985180d [file] [log] [blame]
// 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 failure::Fail;
use fuchsia_uri::pkg_uri::PkgUri;
use log::{error, warn};
use omaha_client::installer::Plan;
use omaha_client::protocol::response::{OmahaStatus, Response};
#[derive(Debug, PartialEq)]
pub struct FuchsiaInstallPlan {
/// The fuchsia TUF repo URI, e.g. fuchsia-pkg://fuchsia.com/update/0?hash=...
pub uri: PkgUri,
}
#[derive(Debug, Fail, PartialEq)]
pub enum InstallPlanErrors {
#[fail(display = "Fuchsia Install Plan could not be created from response")]
Failed,
}
impl Plan for FuchsiaInstallPlan {
type Error = InstallPlanErrors;
fn try_create_from(resp: &Response) -> Result<Self, Self::Error> {
let (app, rest) = if let Some((app, rest)) = resp.apps.split_first() {
(app, rest)
} else {
error!("No app in Omaha response.");
return Err(InstallPlanErrors::Failed);
};
if !rest.is_empty() {
warn!("Only 1 app is supported, found {}", resp.apps.len());
}
if app.status != OmahaStatus::Ok {
error!("Found non-ok app status: {:?}", app.status);
return Err(InstallPlanErrors::Failed);
}
let update_check = if let Some(update_check) = &app.update_check {
update_check
} else {
error!("No update_check in Omaha response.");
return Err(InstallPlanErrors::Failed);
};
let urls = match update_check.status {
OmahaStatus::Ok => {
if let Some(urls) = &update_check.urls {
&urls.url
} else {
error!("No urls in Omaha response.");
return Err(InstallPlanErrors::Failed);
}
}
OmahaStatus::NoUpdate => {
error!("Was asked to create an install plan for a NoUpdate Omaha response");
return Err(InstallPlanErrors::Failed);
}
_ => {
warn!("Unexpected update check status: {:?}", update_check.status);
if let Some(info) = &update_check.info {
warn!("update check status info: {}", info);
}
return Err(InstallPlanErrors::Failed);
}
};
let (url, rest) = if let Some((url, rest)) = urls.split_first() {
(url, rest)
} else {
error!("No url in Omaha response.");
return Err(InstallPlanErrors::Failed);
};
if !rest.is_empty() {
warn!("Only 1 url is supported, found {}", urls.len());
}
match PkgUri::parse(&url.codebase) {
Ok(uri) => Ok(FuchsiaInstallPlan { uri: uri }),
Err(err) => {
error!("Failed to parse {} to PkgUri: {}", url.codebase, err);
Err(InstallPlanErrors::Failed)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use omaha_client::protocol::response::{App, UpdateCheck};
const TEST_URI: &str = "fuchsia-pkg://fuchsia.com/update/0";
#[test]
fn test_simple_response() {
let response = Response {
apps: vec![App {
update_check: Some(UpdateCheck::ok(vec![TEST_URI.to_string()])),
..App::default()
}],
..Response::default()
};
let install_plan = FuchsiaInstallPlan::try_create_from(&response).unwrap();
assert_eq!(install_plan.uri.to_string(), TEST_URI);
}
#[test]
fn test_no_app() {
let response = Response::default();
assert_eq!(FuchsiaInstallPlan::try_create_from(&response), Err(InstallPlanErrors::Failed));
}
#[test]
fn test_multiple_app() {
let response = Response {
apps: vec![
App {
update_check: Some(UpdateCheck::ok(vec![TEST_URI.to_string()])),
..App::default()
},
App::default(),
],
..Response::default()
};
let install_plan = FuchsiaInstallPlan::try_create_from(&response).unwrap();
assert_eq!(install_plan.uri.to_string(), TEST_URI);
}
#[test]
fn test_no_update_check() {
let response = Response { apps: vec![App::default()], ..Response::default() };
assert_eq!(FuchsiaInstallPlan::try_create_from(&response), Err(InstallPlanErrors::Failed));
}
#[test]
fn test_no_urls() {
let response = Response {
apps: vec![App { update_check: Some(UpdateCheck::default()), ..App::default() }],
..Response::default()
};
assert_eq!(FuchsiaInstallPlan::try_create_from(&response), Err(InstallPlanErrors::Failed));
}
#[test]
fn test_app_error_status() {
let response = Response {
apps: vec![App {
status: OmahaStatus::Error("error-unknownApplication".to_string()),
..App::default()
}],
..Response::default()
};
assert_eq!(FuchsiaInstallPlan::try_create_from(&response), Err(InstallPlanErrors::Failed));
}
#[test]
fn test_no_update() {
let response = Response {
apps: vec![App { update_check: Some(UpdateCheck::no_update()), ..App::default() }],
..Response::default()
};
assert_eq!(FuchsiaInstallPlan::try_create_from(&response), Err(InstallPlanErrors::Failed));
}
#[test]
fn test_invalid_uri() {
let response = Response {
apps: vec![App {
update_check: Some(UpdateCheck::ok(vec!["invalid-uri".to_string()])),
..App::default()
}],
..Response::default()
};
assert_eq!(FuchsiaInstallPlan::try_create_from(&response), Err(InstallPlanErrors::Failed));
}
}