blob: a95187455505a85e0237f31f5788bae4cabadac9 [file] [log] [blame]
// Copyright 2022 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 {
fuchsia_async::TimeoutExt,
futures::{future::BoxFuture, lock::Mutex, prelude::*},
hyper::{client::ResponseFuture, Body, Client, Request, Response},
omaha_client::{
app_set::VecAppSet,
common::App,
configuration::{Config, Updater},
cup_ecdsa::{PublicKeyAndId, PublicKeyId, PublicKeys, StandardCupv2Handler},
http_request::{Error, HttpRequest},
installer::stub::StubInstaller,
metrics::StubMetricsReporter,
policy::StubPolicyEngine,
protocol::{request::OS, Cohort},
state_machine::{update_check, StateMachineBuilder, StateMachineEvent, UpdateCheckError},
storage::MemStorage,
time::{timers::StubTimer, StandardTimeSource},
},
std::{error, rc::Rc, time::Duration},
};
pub struct FuchsiaHyperHttpRequest {
client: Client<hyper_rustls::HttpsConnector<fuchsia_hyper::HyperConnector>, Body>,
}
impl HttpRequest for FuchsiaHyperHttpRequest {
fn request(&mut self, req: Request<Body>) -> BoxFuture<'_, Result<Response<Vec<u8>>, Error>> {
collect_from_future(self.client.request(req))
.on_timeout(Duration::from_secs(10), || Err(Error::new_timeout()))
.boxed()
}
}
async fn collect_from_future(response_future: ResponseFuture) -> Result<Response<Vec<u8>>, Error> {
let response = response_future.await?;
let (parts, body) = response.into_parts();
let bytes = hyper::body::to_bytes(body).await?;
Ok(Response::from_parts(parts, bytes.to_vec()))
}
impl FuchsiaHyperHttpRequest {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
FuchsiaHyperHttpRequest { client: fuchsia_hyper::new_https_client() }
}
}
#[derive(argh::FromArgs)]
#[argh(description = "Fake Omaha client")]
struct FakeOmahaClientArgs {
#[argh(option, description = "omaha server URL")]
server: String,
#[argh(option, description = "public key ID (integer)")]
key_id: PublicKeyId,
#[argh(option, description = "public key (ECDSA), .pem format")]
key: String,
#[argh(option, description = "omaha app ID")]
app_id: String,
#[argh(option, description = "omaha channel")]
channel: String,
}
fn main() -> Result<(), Box<dyn error::Error>> {
let args: FakeOmahaClientArgs = argh::from_env();
main_inner(args)
}
fn main_inner(args: FakeOmahaClientArgs) -> Result<(), Box<dyn error::Error>> {
let omaha_public_keys = PublicKeys {
latest: PublicKeyAndId { id: args.key_id, key: args.key.parse()? },
historical: vec![],
};
let config = Config {
updater: Updater { name: "updater".to_string(), version: [1, 2, 3, 4].into() },
os: OS {
platform: "platform".to_string(),
version: "0.1.2.3".to_string(),
service_pack: "sp".to_string(),
arch: "test_arch".to_string(),
},
service_url: args.server.to_string(),
omaha_public_keys: Some(omaha_public_keys.clone()),
};
let app_set = VecAppSet::new(vec![App::builder()
.id(args.app_id)
.version([20200101, 0, 0, 0])
.cohort(Cohort::new(&args.channel))
.build()]);
let state_machine = StateMachineBuilder::new(
/*policy_engine=*/ StubPolicyEngine::new(StandardTimeSource),
/*http=*/ FuchsiaHyperHttpRequest::new(),
/*installer=*/ StubInstaller { should_fail: false },
/*timer=*/ StubTimer {},
/*metrics_reporter=*/ StubMetricsReporter {},
/*storage=*/ Rc::new(Mutex::new(MemStorage::new())),
/*config=*/ config,
/*app_set=*/ Rc::new(Mutex::new(app_set)),
/*cup_handler=*/ Some(StandardCupv2Handler::new(&omaha_public_keys)),
);
let stream: Vec<StateMachineEvent> = fuchsia_async::LocalExecutor::new()
.run_singlethreaded(async { state_machine.oneshot_check().await.collect().await });
let mut result: Vec<Result<update_check::Response, UpdateCheckError>> = stream
.into_iter()
.filter_map(|p| match p {
StateMachineEvent::UpdateCheckResult(val) => Some(val),
_ => None,
})
.collect();
let _ = result.pop().unwrap()?;
Ok(())
}