blob: 14c1265c80a62afaa5c521bf5ad3c40ae65407fd [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.
/// This module tests pkg_resolver's RewriteManager when
/// dynamic rewrite rules have been disabled.
use {
crate::{DirOrProxy, Mounts, TestEnv},
fidl::endpoints::RequestStream,
fidl_fuchsia_io::{
DirectoryObject, DirectoryProxy, DirectoryRequest, DirectoryRequestStream,
OPEN_FLAG_DESCRIBE,
},
fidl_fuchsia_pkg_rewrite::EngineProxy as RewriteEngineProxy,
fuchsia_async as fasync,
fuchsia_url_rewrite::{Rule, RuleConfig},
fuchsia_zircon::Status,
futures::{
future::{BoxFuture, FutureExt},
stream::StreamExt,
},
parking_lot::Mutex,
serde_derive::Serialize,
std::{collections::HashMap, convert::TryInto, fs::File, io::BufWriter, sync::Arc},
};
#[derive(Serialize)]
struct Config {
disable_dynamic_configuration: bool,
}
impl Mounts {
fn add_dynamic_rewrite_rules(&self, rule_config: &RuleConfig) {
if let DirOrProxy::Dir(ref d) = self.pkg_resolver_data {
let f = File::create(d.path().join("rewrites.json")).unwrap();
serde_json::to_writer(BufWriter::new(f), rule_config).unwrap();
} else {
panic!("not supported");
}
}
fn add_config(&self, config: &Config) {
if let DirOrProxy::Dir(ref d) = self.pkg_resolver_config_data {
let f = File::create(d.path().join("config.json")).unwrap();
serde_json::to_writer(BufWriter::new(f), &config).unwrap();
} else {
panic!("not supported");
}
}
}
fn make_rule_config(rule: &Rule) -> RuleConfig {
RuleConfig::Version1(vec![rule.clone()])
}
fn make_rule() -> Rule {
Rule::new("example.com", "example.com", "/", "/").unwrap()
}
async fn get_rules(rewrite_engine: &RewriteEngineProxy) -> Vec<Rule> {
let (rule_iterator, rule_iterator_server) =
fidl::endpoints::create_proxy().expect("create rule iterator proxy");
rewrite_engine.list(rule_iterator_server).expect("list rules");
let mut ret = vec![];
loop {
let rules = rule_iterator.next().await.expect("advance rule iterator");
if rules.is_empty() {
return ret;
}
ret.extend(rules.into_iter().map(|r| r.try_into().unwrap()))
}
}
#[fasync::run_singlethreaded(test)]
async fn load_dynamic_rules() {
let mounts = Mounts::new();
let rule = make_rule();
mounts.add_dynamic_rewrite_rules(&make_rule_config(&rule));
mounts.add_config(&Config { disable_dynamic_configuration: false });
let env = TestEnv::new_with_mounts(mounts);
assert_eq!(get_rules(&env.proxies.rewrite_engine).await, vec![rule]);
env.stop().await;
}
#[fasync::run_singlethreaded(test)]
async fn no_load_dynamic_rules_if_disabled() {
let mounts = Mounts::new();
mounts.add_dynamic_rewrite_rules(&make_rule_config(&make_rule()));
mounts.add_config(&Config { disable_dynamic_configuration: true });
let env = TestEnv::new_with_mounts(mounts);
assert_eq!(get_rules(&env.proxies.rewrite_engine).await, vec![]);
env.stop().await;
}
#[fasync::run_singlethreaded(test)]
async fn commit_transaction_succeeds() {
let env = TestEnv::new();
let (edit_transaction, edit_transaction_server) = fidl::endpoints::create_proxy().unwrap();
env.proxies.rewrite_engine.start_edit_transaction(edit_transaction_server).unwrap();
let rule = make_rule();
Status::ok(edit_transaction.add(&mut rule.clone().into()).await.unwrap()).unwrap();
assert_eq!(Status::from_raw(edit_transaction.commit().await.unwrap()), Status::OK);
assert_eq!(get_rules(&env.proxies.rewrite_engine).await, vec![rule]);
env.stop().await;
}
#[fasync::run_singlethreaded(test)]
async fn commit_transaction_fails_if_disabled() {
let mounts = Mounts::new();
mounts.add_config(&Config { disable_dynamic_configuration: true });
let env = TestEnv::new_with_mounts(mounts);
let (edit_transaction, edit_transaction_server) = fidl::endpoints::create_proxy().unwrap();
env.proxies.rewrite_engine.start_edit_transaction(edit_transaction_server).unwrap();
Status::ok(edit_transaction.add(&mut make_rule().into()).await.unwrap()).unwrap();
assert_eq!(Status::from_raw(edit_transaction.commit().await.unwrap()), Status::ACCESS_DENIED);
assert_eq!(get_rules(&env.proxies.rewrite_engine).await, vec![]);
env.stop().await;
}
type OpenCounter = Arc<Mutex<HashMap<String, u64>>>;
fn handle_directory_request_stream(
mut stream: DirectoryRequestStream,
open_counts: OpenCounter,
) -> BoxFuture<'static, ()> {
async move {
while let Some(req) = stream.next().await {
handle_directory_request(req.unwrap(), Arc::clone(&open_counts)).await;
}
}
.boxed()
}
async fn handle_directory_request(req: DirectoryRequest, open_counts: OpenCounter) {
match req {
DirectoryRequest::Clone { flags, object, control_handle: _control_handle } => {
let stream = DirectoryRequestStream::from_channel(
fasync::Channel::from_channel(object.into_channel()).unwrap(),
);
describe_dir(flags, &stream);
fasync::spawn(handle_directory_request_stream(stream, Arc::clone(&open_counts)));
}
DirectoryRequest::Open {
flags: _flags,
mode: _mode,
path,
object: _object,
control_handle: _control_handle,
} => {
*open_counts.lock().entry(path).or_insert(0) += 1;
}
other => panic!("unhandled request type: {:?}", other),
}
}
fn describe_dir(flags: u32, stream: &DirectoryRequestStream) {
let ch = stream.control_handle();
if flags & OPEN_FLAG_DESCRIBE != 0 {
let mut ni = fidl_fuchsia_io::NodeInfo::Directory(DirectoryObject);
ch.send_on_open_(Status::OK.into_raw(), Some(fidl::encoding::OutOfLine(&mut ni)))
.expect("send_on_open");
}
}
fn spawn_directory_handler() -> (DirectoryProxy, OpenCounter) {
let (proxy, stream) =
fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_io::DirectoryMarker>().unwrap();
let open_counts = Arc::new(Mutex::new(HashMap::<String, u64>::new()));
fasync::spawn(handle_directory_request_stream(stream, Arc::clone(&open_counts)));
(proxy, open_counts)
}
#[fasync::run_singlethreaded(test)]
async fn attempt_to_open_persisted_dynamic_rules() {
let (proxy, open_counts) = spawn_directory_handler();
let mounts = Mounts {
pkg_resolver_data: DirOrProxy::Proxy(proxy),
pkg_resolver_config_data: DirOrProxy::Dir(tempfile::tempdir().expect("/tmp to exist")),
};
let env = TestEnv::new_with_mounts(mounts);
// Waits for pkg_resolver to be initialized
get_rules(&env.proxies.rewrite_engine).await;
assert_eq!(open_counts.lock().get("rewrites.json"), Some(&1));
env.stop().await;
}
#[fasync::run_singlethreaded(test)]
async fn no_attempt_to_open_persisted_dynamic_rules_if_disabled() {
let (proxy, open_counts) = spawn_directory_handler();
let mounts = Mounts {
pkg_resolver_data: DirOrProxy::Proxy(proxy),
pkg_resolver_config_data: DirOrProxy::Dir(tempfile::tempdir().expect("/tmp to exist")),
};
mounts.add_config(&Config { disable_dynamic_configuration: true });
let env = TestEnv::new_with_mounts(mounts);
// Waits for pkg_resolver to be initialized
get_rules(&env.proxies.rewrite_engine).await;
assert_eq!(open_counts.lock().get("rewrites.json"), None);
env.stop().await;
}