blob: 5a0d75ec5e55076e873578d093f81976ada40b5d [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 {
crate::model::{
rights,
testing::{routing_test_helpers::*, test_helpers::*},
},
cm_rust::*,
moniker::RelativeMoniker,
std::{
convert::{TryFrom, TryInto},
path::PathBuf,
},
};
/// a
/// / \
/// b c
///
/// a: has storage decl with name "data" with a source of self at path /data
/// a: offers data storage to b
/// a: offers a storage admin protocol to c from the "data" storage capability
/// b: uses data storage as /storage.
/// c: uses the storage admin protocol to access b's storage
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_to_one_child_admin_to_another() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Storage(OfferStorageDecl {
source: OfferStorageSource::Self_,
target: OfferTarget::Child("b".to_string()),
source_name: "data".into(),
target_name: "data".into(),
}))
.offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Capability("data".into()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: OfferTarget::Child("c".to_string()),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("b")
.add_lazy_child("c")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Storage(UseStorageDecl {
source_name: "data".into(),
target_path: "/storage".try_into().unwrap(),
}))
.build(),
),
(
"c",
ComponentDeclBuilder::new()
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec!["c:0"].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["b:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::Ok,
},
)
.await;
}
/// a
/// |
/// b
/// |
/// c
///
/// a: has directory decl with name "data" with a source of self at path /data subdir "foo"
/// a: offers data to b
/// b: has storage decl with name "storage" based on "data" from parent subdir "bar"
/// b: offers a storage admin protocol to c from the "storage" storage capability
/// c: uses the storage admin protocol to access its own storage
#[fuchsia_async::run_singlethreaded(test)]
async fn directory_from_grandparent_storage_and_admin_from_parent() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("data")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.offer(OfferDecl::Directory(OfferDirectoryDecl {
source: OfferDirectorySource::Self_,
source_name: "data".into(),
target_name: "data".into(),
target: OfferTarget::Child("b".to_string()),
rights: Some(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS),
subdir: Some(PathBuf::from("foo")),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("b")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.storage(StorageDecl {
name: "storage".into(),
backing_dir: "data".try_into().unwrap(),
source: StorageDirectorySource::Parent,
subdir: Some(PathBuf::from("bar")),
})
.offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Capability("storage".into()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: OfferTarget::Child("c".to_string()),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("c")
.build(),
),
(
"c",
ComponentDeclBuilder::new()
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec!["b:0", "c:0"].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["c:0".into()]),
from_cm_namespace: false,
storage_subdir: Some("foo/bar".to_string()),
expected_res: ExpectedResult::Ok,
},
)
.await;
}
/// a
/// / \
/// b c
/// |
/// d
///
/// c: has storage decl with name "data" with a source of self at path /data
/// c: has storage admin protocol from the "data" storage admin capability
/// c: offers data storage to d
/// d: uses data storage
/// a: offers storage admin protocol from c to b
/// b: uses the storage admin protocol
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_admin_from_sibling() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Child("c".to_string()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: OfferTarget::Child("b".to_string()),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("b")
.add_lazy_child("c")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.build(),
),
(
"c",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Storage(OfferStorageDecl {
source: OfferStorageSource::Self_,
target: OfferTarget::Child("d".to_string()),
source_name: "data".into(),
target_name: "data".into(),
}))
.expose(ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Capability("data".into()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: ExposeTarget::Parent,
}))
.add_lazy_child("d")
.build(),
),
(
"d",
ComponentDeclBuilder::new()
.use_(UseDecl::Storage(UseStorageDecl {
source_name: "data".into(),
target_path: "/storage".try_into().unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec!["b:0"].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["d:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::Ok,
},
)
.await;
}
/// a
/// |
/// b
///
/// a: has storage decl with name "data" with a source of self at path /data
/// a: offers data storage to b
/// a: uses a storage admin protocol from #data
/// b: uses data storage as /storage.
#[fuchsia_async::run_singlethreaded(test)]
async fn admin_protocol_used_in_the_same_place_storage_is_declared() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Storage(OfferStorageDecl {
source: OfferStorageSource::Self_,
target: OfferTarget::Child("b".to_string()),
source_name: "data".into(),
target_name: "data".into(),
}))
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Capability("data".into()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.add_lazy_child("b")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Storage(UseStorageDecl {
source_name: "data".into(),
target_path: "/storage".try_into().unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec![].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["b:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::Ok,
},
)
.await;
}
/// a
/// |
/// b
///
/// a: has storage decl with name "data" with a source of self at path /data
/// a: declares a protocol "unrelated.protocol"
/// a: offers data storage to b
/// a: uses a storage admin protocol from "unrelated.protocol"
/// b: uses data storage as /storage.
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_admin_from_protocol_on_self() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.protocol(ProtocolDeclBuilder::new("unrelated.protocol").build())
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Storage(OfferStorageDecl {
source: OfferStorageSource::Self_,
target: OfferTarget::Child("b".to_string()),
source_name: "data".into(),
target_name: "data".into(),
}))
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Capability("unrelated.protocol".into()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.add_lazy_child("b")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Storage(UseStorageDecl {
source_name: "data".into(),
target_path: "/storage".try_into().unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec![].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["b:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::ErrWithNoEpitaph,
},
)
.await;
}
/// a
/// |
/// b
///
/// a: has storage decl with name "data" with a source of self at path /data
/// a: declares a protocol "unrelated.protocol"
/// a: offers a storage admin protocol from "unrelated.protocol" to b
/// b: uses storage admin protocol
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_admin_from_protocol_from_parent() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.protocol(ProtocolDeclBuilder::new("unrelated.protocol").build())
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Capability("unrelated.protocol".into()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: OfferTarget::Child("b".to_string()),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("b")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec!["b:0"].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["b:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::ErrWithNoEpitaph,
},
)
.await;
}
/// a
/// / \
/// b c
/// |
/// d
///
/// c: has storage decl with name "data" with a source of self at path /data
/// c: has protocol decl with name "unrelated.protocol"
/// c: has storage admin protocol from the "unrelated.protocol" capability
/// c: offers data storage to d
/// d: uses data storage
/// a: offers storage admin protocol from c to b
/// b: uses the storage admin protocol
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_admin_from_protocol_on_sibling() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Child("c".to_string()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: OfferTarget::Child("b".to_string()),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("b")
.add_lazy_child("c")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.build(),
),
(
"c",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.protocol(ProtocolDeclBuilder::new("unrelated.protocol").build())
.offer(OfferDecl::Storage(OfferStorageDecl {
source: OfferStorageSource::Self_,
target: OfferTarget::Child("d".to_string()),
source_name: "data".into(),
target_name: "data".into(),
}))
.expose(ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Capability("unrelated.protocol".into()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: ExposeTarget::Parent,
}))
.add_lazy_child("d")
.build(),
),
(
"d",
ComponentDeclBuilder::new()
.use_(UseDecl::Storage(UseStorageDecl {
source_name: "data".into(),
target_path: "/storage".try_into().unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec!["b:0"].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["d:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::ErrWithNoEpitaph,
},
)
.await;
}
/// a
/// |
/// b
///
/// a: has storage decl with name "data" with a source of self at path /data
/// a: offers data storage to b
/// a: uses a "unrelated.protocol" protocol from "data"
/// b: uses data storage as /storage.
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_admin_from_storage_on_self_bad_protocol_name() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.protocol(ProtocolDeclBuilder::new("unrelated.protocol").build())
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Storage(OfferStorageDecl {
source: OfferStorageSource::Self_,
target: OfferTarget::Child("b".to_string()),
source_name: "data".into(),
target_name: "data".into(),
}))
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Capability("unrelated.protocol".into()),
source_name: "unrelated.protocol".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.add_lazy_child("b")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Storage(UseStorageDecl {
source_name: "data".into(),
target_path: "/storage".try_into().unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec![].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["b:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::ErrWithNoEpitaph,
},
)
.await;
}
/// a
/// |
/// b
///
/// a: has storage decl with name "data" with a source of self at path /data
/// a: offers a storage admin protocol from "data" to b with a source name of "unrelated.protocol"
/// b: uses storage admin protocol
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_admin_from_storage_on_parent_bad_protocol_name() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Capability("data".into()),
source_name: "unrelated.protocol".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: OfferTarget::Child("b".to_string()),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("b")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec!["b:0"].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["b:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::ErrWithNoEpitaph,
},
)
.await;
}
/// a
/// / \
/// b c
/// |
/// d
///
/// c: has storage decl with name "data" with a source of self at path /data
/// c: exposes storage admin protocol from "data" with a source name of "unrelated.protocol"
/// c: offers data storage to d
/// d: uses data storage
/// a: offers storage admin protocol from c to b
/// b: uses the storage admin protocol
#[fuchsia_async::run_singlethreaded(test)]
async fn storage_admin_from_protocol_on_sibling_bad_protocol_name() {
let components = vec![
(
"a",
ComponentDeclBuilder::new()
.offer(OfferDecl::Protocol(OfferProtocolDecl {
source: OfferServiceSource::Child("c".to_string()),
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: OfferTarget::Child("b".to_string()),
dependency_type: DependencyType::Strong,
}))
.add_lazy_child("b")
.add_lazy_child("c")
.build(),
),
(
"b",
ComponentDeclBuilder::new()
.use_(UseDecl::Protocol(UseProtocolDecl {
source: UseSource::Parent,
source_name: "fuchsia.sys2.StorageAdmin".into(),
target_path: CapabilityPath::try_from("/svc/fuchsia.sys2.StorageAdmin")
.unwrap(),
}))
.build(),
),
(
"c",
ComponentDeclBuilder::new()
.directory(
DirectoryDeclBuilder::new("tmpfs")
.path("/data")
.rights(*rights::READ_RIGHTS | *rights::WRITE_RIGHTS)
.build(),
)
.storage(StorageDecl {
name: "data".into(),
backing_dir: "tmpfs".try_into().unwrap(),
source: StorageDirectorySource::Self_,
subdir: None,
})
.offer(OfferDecl::Storage(OfferStorageDecl {
source: OfferStorageSource::Self_,
target: OfferTarget::Child("d".to_string()),
source_name: "data".into(),
target_name: "data".into(),
}))
.expose(ExposeDecl::Protocol(ExposeProtocolDecl {
source: ExposeSource::Capability("data".into()),
source_name: "unrelated.protocol".into(),
target_name: "fuchsia.sys2.StorageAdmin".into(),
target: ExposeTarget::Parent,
}))
.add_lazy_child("d")
.build(),
),
(
"d",
ComponentDeclBuilder::new()
.use_(UseDecl::Storage(UseStorageDecl {
source_name: "data".into(),
target_path: "/storage".try_into().unwrap(),
}))
.build(),
),
];
let test = RoutingTest::new("a", components).await;
test.check_use(
vec!["b:0"].into(),
CheckUse::StorageAdmin {
storage_relation: RelativeMoniker::new(vec![], vec!["d:0".into()]),
from_cm_namespace: false,
storage_subdir: None,
expected_res: ExpectedResult::ErrWithNoEpitaph,
},
)
.await;
}