blob: 5cb10917d6f9c3b60a3c2b39e609833e2e24e6c4 [file] [log] [blame]
// Copyright 2024 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::testing::routing_test_helpers::*, cm_rust::*, cm_rust_testing::*,
fidl_fuchsia_io as fio, fuchsia_zircon as zx, moniker::Moniker,
routing_test_helpers::RoutingTestModel, std::path::PathBuf, test_case::test_case,
};
#[fuchsia::test]
async fn use_protocol_from_dictionary() {
// Test extracting a protocol from a dictionary with source parent, self and child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("parent_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("parent_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("parent_dict")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("self_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("A")
.from_dictionary("self_dict"),
)
.use_(UseBuilder::protocol().name("B").from_dictionary("parent_dict"))
.use_(
UseBuilder::protocol()
.source(UseSource::Child("leaf".into()))
.name("C")
.from_dictionary("child_dict"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("child_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
for path in ["/svc/A", "/svc/B", "/svc/C"] {
test.check_use(
"mid".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn use_protocol_from_dictionary_not_found() {
// Test extracting a protocol from a dictionary, but the protocol is missing from the
// dictionary.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("dict")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A").from_dictionary("dict"))
.child_default("leaf")
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/A".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
// Test extracting a protocol from a dictionary, but the dictionary is not routed to the
// target.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("dict")
.target_name("other_dict")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A").from_dictionary("dict"))
.child_default("leaf")
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/A".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
}
#[fuchsia::test]
async fn use_directory_from_dictionary_not_supported() {
// Routing a directory into a dictionary isn't supported yet, it should fail.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.capability(CapabilityBuilder::directory().name("bar_data").path("/data/bar"))
.dictionary_default("parent_dict")
.offer(
OfferBuilder::dictionary()
.name("parent_dict")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.offer(
OfferBuilder::directory()
.name("bar_data")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("parent_dict".parse().unwrap()))
.rights(fio::R_STAR_DIR),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.capability(CapabilityBuilder::directory().name("foo_data").path("/data/foo"))
.dictionary_default("self_dict")
.offer(
OfferBuilder::directory()
.name("foo_data")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap()))
.rights(fio::R_STAR_DIR),
)
.use_(
UseBuilder::directory()
.source(UseSource::Self_)
.name("A")
.from_dictionary("self_dict")
.path("/A"),
)
.use_(UseBuilder::directory().name("B").from_dictionary("parent_dict").path("/B"))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Directory {
path: "/A".parse().unwrap(),
file: PathBuf::from("hippo"),
expected_res: ExpectedResult::Err(zx::Status::NOT_SUPPORTED),
},
)
.await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Directory {
path: "/B".parse().unwrap(),
file: PathBuf::from("hippo"),
expected_res: ExpectedResult::Err(zx::Status::NOT_SUPPORTED),
},
)
.await;
}
#[fuchsia::test]
async fn expose_directory_from_dictionary_not_supported() {
// Routing a directory into a dictionary isn't supported yet, it should fail.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.use_(
UseBuilder::directory()
.source(UseSource::Child("mid".into()))
.name("A")
.path("/A"),
)
.use_(
UseBuilder::directory()
.source(UseSource::Child("mid".into()))
.name("B")
.path("/B"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.capability(CapabilityBuilder::directory().name("foo_data").path("/data/foo"))
.dictionary_default("self_dict")
.offer(
OfferBuilder::directory()
.name("foo_data")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap()))
.rights(fio::R_STAR_DIR),
)
.expose(
ExposeBuilder::directory()
.name("A")
.source(ExposeSource::Self_)
.from_dictionary("self_dict"),
)
.expose(
ExposeBuilder::directory()
.name("B")
.source(ExposeSource::Child("leaf".into()))
.from_dictionary("child_dict"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.capability(CapabilityBuilder::directory().name("bar_data").path("/data/bar"))
.dictionary_default("child_dict")
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.offer(
OfferBuilder::directory()
.name("bar_data")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap()))
.rights(fio::R_STAR_DIR),
)
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Directory {
path: "/A".parse().unwrap(),
file: PathBuf::from("hippo"),
expected_res: ExpectedResult::Err(zx::Status::NOT_SUPPORTED),
},
)
.await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Directory {
path: "/B".parse().unwrap(),
file: PathBuf::from("hippo"),
expected_res: ExpectedResult::Err(zx::Status::NOT_SUPPORTED),
},
)
.await;
}
#[fuchsia::test]
async fn use_protocol_from_nested_dictionary() {
// Test extracting a protocol from a dictionary nested in another dictionary with source
// parent, self and child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("nested")
.dictionary_default("parent_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("parent_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("parent_dict")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("nested")
.dictionary_default("self_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("A")
.from_dictionary("self_dict/nested"),
)
.use_(UseBuilder::protocol().name("B").from_dictionary("parent_dict/nested"))
.use_(
UseBuilder::protocol()
.source(UseSource::Child("leaf".into()))
.name("C")
.from_dictionary("child_dict/nested"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("nested")
.dictionary_default("child_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
for path in ["/svc/A", "/svc/B", "/svc/C"] {
test.check_use(
"mid".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn offer_protocol_from_dictionary() {
// Test extracting a protocol from a dictionary with source parent, self, and child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("parent_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("parent_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("parent_dict")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("self_dict")
.offer(
OfferBuilder::protocol()
.name("A")
.target_name("A_svc")
.source(OfferSource::Self_)
.target_static_child("leaf")
.from_dictionary("self_dict"),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("B")
.target_name("B_svc")
.source(OfferSource::Parent)
.target_static_child("leaf")
.from_dictionary("parent_dict"),
)
.offer(
OfferBuilder::protocol()
.name("C")
.target_name("C_svc")
.source_static_child("provider")
.target_static_child("leaf")
.from_dictionary("child_dict"),
)
.child_default("provider")
.child_default("leaf")
.build(),
),
(
"provider",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("child_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A_svc").path("/svc/A"))
.use_(UseBuilder::protocol().name("B_svc").path("/svc/B"))
.use_(UseBuilder::protocol().name("C_svc").path("/svc/C"))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
for path in ["/svc/A", "/svc/B", "/svc/C"] {
test.check_use(
"mid/leaf".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn offer_protocol_from_dictionary_not_found() {
// Test extracting a protocol from a dictionary, but the protocol is missing from the
// dictionary.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("dict")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.offer(
OfferBuilder::protocol()
.name("A")
.target_name("A_svc")
.source(OfferSource::Parent)
.target_static_child("leaf")
.from_dictionary("dict"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A_svc").path("/svc/A"))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"mid/leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/A".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
}
#[fuchsia::test]
async fn offer_protocol_from_nested_dictionary() {
// Test extracting a protocol from a dictionary nested in another dictionary with source
// parent, self, and child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("nested")
.dictionary_default("parent_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("parent_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("parent_dict")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("self_dict")
.dictionary_default("nested")
.offer(
OfferBuilder::protocol()
.name("A")
.target_name("A_svc")
.source(OfferSource::Self_)
.target_static_child("leaf")
.from_dictionary("self_dict/nested"),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("B")
.target_name("B_svc")
.source(OfferSource::Parent)
.target_static_child("leaf")
.from_dictionary("parent_dict/nested"),
)
.offer(
OfferBuilder::protocol()
.name("C")
.target_name("C_svc")
.source_static_child("provider")
.target_static_child("leaf")
.from_dictionary("child_dict/nested"),
)
.child_default("provider")
.child_default("leaf")
.build(),
),
(
"provider",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("child_dict")
.dictionary_default("nested")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A_svc").path("/svc/A"))
.use_(UseBuilder::protocol().name("B_svc").path("/svc/B"))
.use_(UseBuilder::protocol().name("C_svc").path("/svc/C"))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
for path in ["/svc/A", "/svc/B", "/svc/C"] {
test.check_use(
"mid/leaf".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn expose_protocol_from_dictionary() {
// Test extracting a protocol from a dictionary with source self and child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.use_(
UseBuilder::protocol()
.source(UseSource::Child("mid".into()))
.name("A_svc")
.path("/svc/A"),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Child("mid".into()))
.name("B_svc")
.path("/svc/B"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("self_dict")
.expose(
ExposeBuilder::protocol()
.name("A")
.target_name("A_svc")
.from_dictionary("self_dict")
.source(ExposeSource::Self_),
)
.expose(
ExposeBuilder::protocol()
.name("B")
.target_name("B_svc")
.from_dictionary("child_dict")
.source(ExposeSource::Child("leaf".into())),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("child_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
for path in ["/svc/A", "/svc/B"] {
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn expose_protocol_from_dictionary_not_found() {
// Test extracting a protocol from a dictionary, but the protocol is missing.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.use_(
UseBuilder::protocol()
.source(UseSource::Child("mid".into()))
.name("A_svc")
.path("/svc/A"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.expose(
ExposeBuilder::protocol()
.name("A")
.target_name("A_svc")
.source(ExposeSource::Self_)
.from_dictionary("dict")
.build(),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/A".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
}
#[fuchsia::test]
async fn expose_protocol_from_nested_dictionary() {
// Test extracting a protocol from a dictionary nested in a dictionary with source self and
// child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.use_(
UseBuilder::protocol()
.source(UseSource::Child("mid".into()))
.name("A_svc")
.path("/svc/A"),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Child("mid".into()))
.name("B_svc")
.path("/svc/B"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("self_dict")
.dictionary_default("nested")
.expose(
ExposeBuilder::protocol()
.name("A")
.target_name("A_svc")
.from_dictionary("self_dict/nested")
.source(ExposeSource::Self_),
)
.expose(
ExposeBuilder::protocol()
.name("B")
.target_name("B_svc")
.from_dictionary("child_dict/nested")
.source(ExposeSource::Child("leaf".into())),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("child_dict")
.dictionary_default("nested")
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
for path in ["/svc/A", "/svc/B"] {
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn dictionary_in_exposed_dir() {
// Test extracting a protocol from a dictionary with source self and child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("self_dict")
.expose(ExposeBuilder::dictionary().name("self_dict").source(ExposeSource::Self_))
.expose(
ExposeBuilder::dictionary()
.name("child_dict")
.source(ExposeSource::Child("leaf".into())),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("nested")
.dictionary_default("child_dict")
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
// The dictionaries in the exposed dir will be converted to subdirectories.
for path in ["/self_dict/A", "/child_dict/nested/B"] {
test.check_use_exposed_dir(
".".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn offer_dictionary_to_dictionary() {
// Tests dictionary nesting when the nested dictionary comes from parent, self, or child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("parent_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("parent_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("parent_dict")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("self_dict")
.dictionary_default("root_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("self_dict")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("root_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("parent_dict")
.source(OfferSource::Parent)
.target(OfferTarget::Capability("root_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("child_dict")
.source_static_child("leaf")
.target(OfferTarget::Capability("root_dict".parse().unwrap())),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("A")
.from_dictionary("root_dict/self_dict"),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("B")
.from_dictionary("root_dict/parent_dict"),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("C")
.from_dictionary("root_dict/child_dict"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("child_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
for path in ["/svc/A", "/svc/B", "/svc/C"] {
test.check_use(
"mid".try_into().unwrap(),
CheckUse::Protocol { path: path.parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
}
#[fuchsia::test]
async fn extend_from_self() {
// Tests extending a dictionary, when the source dictionary is defined by self.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("bar")
.offer(
OfferBuilder::protocol()
.name("bar")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("origin_dict")
.capability(
CapabilityBuilder::dictionary()
.name("self_dict")
.source_dictionary(DictionarySource::Self_, "origin_dict")
.build(),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Parent)
.target(OfferTarget::Capability("origin_dict".parse().unwrap())),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("A")
.from_dictionary("self_dict"),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("B")
.from_dictionary("self_dict"),
)
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
// Test using twice in a row
for _ in 0..2 {
for path in ["/svc/A", "/svc/B"] {
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol {
path: path.parse().unwrap(),
expected_res: ExpectedResult::Ok,
},
)
.await;
}
}
}
#[fuchsia::test]
async fn extend_from_parent() {
// Tests extending a dictionary, when the source dictionary is defined by parent.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("bar")
.dictionary_default("origin_dict")
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("origin_dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("origin_dict")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.capability(
CapabilityBuilder::dictionary()
.name("self_dict")
.source_dictionary(DictionarySource::Parent, "origin_dict")
.build(),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("A")
.from_dictionary("self_dict"),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("B")
.from_dictionary("self_dict"),
)
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
// Test using twice in a row
for _ in 0..2 {
for path in ["/svc/A", "/svc/B"] {
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol {
path: path.parse().unwrap(),
expected_res: ExpectedResult::Ok,
},
)
.await;
}
}
}
#[fuchsia::test]
async fn extend_from_child() {
// Tests extending a dictionary, when the source dictionary is defined by a child.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.capability(
CapabilityBuilder::dictionary()
.name("self_dict")
.source_dictionary(
DictionarySource::Child(ChildRef {
name: "leaf".parse().unwrap(),
collection: None,
}),
"origin_dict",
)
.build(),
)
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("self_dict".parse().unwrap())),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("A")
.from_dictionary("self_dict"),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Self_)
.name("B")
.from_dictionary("self_dict"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("bar")
.dictionary_default("origin_dict")
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("origin_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("origin_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
// Test using twice in a row
for _ in 0..2 {
for path in ["/svc/A", "/svc/B"] {
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol {
path: path.parse().unwrap(),
expected_res: ExpectedResult::Ok,
},
)
.await;
}
}
}
#[fuchsia::test]
async fn use_from_dictionary_availability_attenuated() {
// required -> optional downgrade allowed, of:
// - a capability in a dictionary
// - a capability in a dictionary in a dictionary
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.protocol_default("bar")
.dictionary_default("nested")
.dictionary_default("dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("dict")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(
UseBuilder::protocol()
.name("A")
.from_dictionary("dict")
.availability(Availability::Optional),
)
.use_(
UseBuilder::protocol()
.name("B")
.from_dictionary("dict/nested")
.availability(Availability::Optional),
)
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol { path: "/svc/A".parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol { path: "/svc/B".parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
#[fuchsia::test]
async fn use_from_dictionary_availability_invalid() {
// attempted optional -> required upgrade, disallowed, of:
// - an optional capability in a dictionary.
// - a capability in an optional dictionary.
// - a capability in a dictionary in an optional dictionary.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.protocol_default("bar")
.protocol_default("qux")
.dictionary_default("required_dict")
.dictionary_default("optional_dict")
.dictionary_default("nested")
.dictionary_default("dict_with_optional_nested")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap()))
.availability(Availability::Optional),
)
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("optional_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("qux")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability(
"dict_with_optional_nested".parse().unwrap(),
))
.availability(Availability::Optional),
)
.offer(
OfferBuilder::dictionary()
.name("required_dict")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.offer(
OfferBuilder::dictionary()
.name("optional_dict")
.source(OfferSource::Self_)
.target_static_child("leaf")
.availability(Availability::Optional),
)
.offer(
OfferBuilder::dictionary()
.name("dict_with_optional_nested")
.source(OfferSource::Self_)
.target_static_child("leaf"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A").from_dictionary("required_dict"))
.use_(UseBuilder::protocol().name("B").from_dictionary("optional_dict"))
.use_(
UseBuilder::protocol()
.name("C")
.from_dictionary("dict_with_optional_nested/nested"),
)
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/A".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/B".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/C".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
}
#[fuchsia::test]
async fn offer_from_dictionary_availability_attenuated() {
// required -> optional downgrade allowed, of:
// - a capability in a dictionary
// - a capability in a dictionary in a dictionary
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.protocol_default("bar")
.dictionary_default("nested")
.dictionary_default("dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("A")
.source(OfferSource::Self_)
.target_static_child("leaf")
.from_dictionary("dict"),
)
.offer(
OfferBuilder::protocol()
.name("B")
.source(OfferSource::Self_)
.target_static_child("leaf")
.from_dictionary("dict/nested"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A").availability(Availability::Optional))
.use_(UseBuilder::protocol().name("B").availability(Availability::Optional))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol { path: "/svc/A".parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
test.check_use(
"leaf".try_into().unwrap(),
CheckUse::Protocol { path: "/svc/B".parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
#[fuchsia::test]
async fn offer_from_dictionary_availability_invalid() {
// attempted optional -> required upgrade, disallowed, of:
// - an optional capability in a dictionary.
// - a capability in an optional dictionary.
// - a capability in a dictionary in an optional dictionary.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.protocol_default("foo")
.protocol_default("bar")
.protocol_default("qux")
.dictionary_default("required_dict")
.dictionary_default("optional_dict")
.dictionary_default("nested")
.dictionary_default("dict_with_optional_nested")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap()))
.availability(Availability::Optional),
)
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("optional_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("qux")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability(
"dict_with_optional_nested".parse().unwrap(),
))
.availability(Availability::Optional),
)
.offer(
OfferBuilder::dictionary()
.name("required_dict")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.offer(
OfferBuilder::dictionary()
.name("optional_dict")
.source(OfferSource::Self_)
.target_static_child("mid")
.availability(Availability::Optional),
)
.offer(
OfferBuilder::dictionary()
.name("dict_with_optional_nested")
.source(OfferSource::Self_)
.target_static_child("mid"),
)
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.offer(
OfferBuilder::protocol()
.name("A")
.source(OfferSource::Parent)
.target_static_child("leaf")
.from_dictionary("required_dict"),
)
.offer(
OfferBuilder::protocol()
.name("B")
.source(OfferSource::Parent)
.target_static_child("leaf")
.from_dictionary("optional_dict"),
)
.offer(
OfferBuilder::protocol()
.name("C")
.source(OfferSource::Parent)
.target_static_child("leaf")
.from_dictionary("dict_with_optional_nested/nested"),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().name("A"))
.use_(UseBuilder::protocol().name("B"))
.use_(UseBuilder::protocol().name("C"))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
"mid/leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/A".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
test.check_use(
"mid/leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/B".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
test.check_use(
"mid/leaf".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/C".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
}
#[fuchsia::test]
async fn expose_from_dictionary_availability_attenuated() {
// required -> optional downgrade allowed, of:
// - a capability in a dictionary
// - a capability in a dictionary in a dictionary
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.use_(
UseBuilder::protocol()
.source(UseSource::Child("leaf".into()))
.name("A")
.availability(Availability::Optional),
)
.use_(
UseBuilder::protocol()
.source(UseSource::Child("leaf".into()))
.name("B")
.availability(Availability::Optional),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.protocol_default("bar")
.dictionary_default("nested")
.dictionary_default("dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap())),
)
.expose(
ExposeBuilder::protocol()
.name("A")
.from_dictionary("dict")
.source(ExposeSource::Self_),
)
.expose(
ExposeBuilder::protocol()
.name("B")
.from_dictionary("dict/nested")
.source(ExposeSource::Self_),
)
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol { path: "/svc/A".parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol { path: "/svc/B".parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}
#[fuchsia::test]
async fn expose_from_dictionary_availability_invalid() {
// attempted optional -> required upgrade, disallowed, of:
// - an optional capability in a dictionary.
// - a capability in an optional dictionary.
// - a capability in a dictionary in an optional dictionary.
let components = vec![
(
"root",
ComponentDeclBuilder::new()
.use_(UseBuilder::protocol().source(UseSource::Child("mid".into())).name("A"))
.use_(UseBuilder::protocol().source(UseSource::Child("mid".into())).name("B"))
.use_(UseBuilder::protocol().source(UseSource::Child("mid".into())).name("C"))
.child_default("mid")
.build(),
),
(
"mid",
ComponentDeclBuilder::new()
.expose(
ExposeBuilder::protocol()
.name("A")
.from_dictionary("required_dict")
.source(ExposeSource::Child("leaf".into())),
)
.expose(
ExposeBuilder::protocol()
.name("B")
.from_dictionary("optional_dict")
.source(ExposeSource::Child("leaf".into())),
)
.expose(
ExposeBuilder::protocol()
.name("C")
.from_dictionary("dict_with_optional_nested/nested")
.source(ExposeSource::Child("leaf".into())),
)
.child_default("leaf")
.build(),
),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.protocol_default("bar")
.protocol_default("qux")
.dictionary_default("required_dict")
.dictionary_default("optional_dict")
.dictionary_default("nested")
.dictionary_default("dict_with_optional_nested")
.offer(
OfferBuilder::protocol()
.name("foo")
.target_name("A")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("dict".parse().unwrap()))
.availability(Availability::Optional),
)
.offer(
OfferBuilder::protocol()
.name("bar")
.target_name("B")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("optional_dict".parse().unwrap())),
)
.offer(
OfferBuilder::protocol()
.name("qux")
.target_name("C")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("nested".parse().unwrap())),
)
.offer(
OfferBuilder::dictionary()
.name("nested")
.source(OfferSource::Self_)
.target(OfferTarget::Capability(
"dict_with_optional_nested".parse().unwrap(),
))
.availability(Availability::Optional),
)
.expose(
ExposeBuilder::dictionary().name("required_dict").source(ExposeSource::Self_),
)
.expose(
ExposeBuilder::dictionary()
.name("optional_dict")
.source(ExposeSource::Self_)
.availability(Availability::Optional),
)
.expose(
ExposeBuilder::dictionary()
.name("dict_with_optional_nested")
.source(ExposeSource::Self_),
)
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/A".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/B".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
test.check_use(
".".try_into().unwrap(),
CheckUse::Protocol {
path: "/svc/C".parse().unwrap(),
expected_res: ExpectedResult::Err(zx::Status::NOT_FOUND),
},
)
.await;
}
enum Statement {
Declare,
Extend,
}
/// Tests extending a dictionary, when the source dictionary is defined by self.
/// Additionally, the source dictionary may be defined before or after the target dictionary.
#[test_case(Statement::Declare, Statement::Extend)]
#[test_case(Statement::Extend, Statement::Declare)]
#[fuchsia::test]
async fn dict_extend_from_self_different_decl_ordering(first: Statement, second: Statement) {
let mut root = ComponentDeclBuilder::new().child_default("leaf").use_(
UseBuilder::protocol().source(UseSource::Self_).name("foo").from_dictionary("target"),
);
for statement in [first, second] {
root = match statement {
Statement::Declare => root.capability(
CapabilityBuilder::dictionary()
.name("source")
.source_dictionary(
DictionarySource::Child(ChildRef {
name: "leaf".parse().unwrap(),
collection: None,
}),
"child_dict",
)
.build(),
),
Statement::Extend => root.capability(
CapabilityBuilder::dictionary()
.name("target")
.source_dictionary(DictionarySource::Self_, "source")
.build(),
),
}
}
let root = root.build();
let components = vec![
("root", root),
(
"leaf",
ComponentDeclBuilder::new()
.protocol_default("foo")
.dictionary_default("child_dict")
.offer(
OfferBuilder::protocol()
.name("foo")
.source(OfferSource::Self_)
.target(OfferTarget::Capability("child_dict".parse().unwrap())),
)
.expose(ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_))
.build(),
),
];
let test = RoutingTestBuilder::new("root", components).build().await;
test.check_use(
Moniker::default(),
CheckUse::Protocol { path: "/svc/foo".parse().unwrap(), expected_res: ExpectedResult::Ok },
)
.await;
}