Skip to content

Commit 0476869

Browse files
BreakthroughCQ Bot
authored andcommitted
[package-directory] Rework tests to use VFS connections
Ensure package directory tests serve a connection to the directories being tested, and all child nodes are opened through fuchsia.io. This ensures that the VFS connection logic (including hierarchal rights enforcement and path handling) is also tested. This results in a few test-only changes: * Hierarchal rights are now enforced, so in cases where NOT_SUPPORTED was being checked before, we now need ACCESS_DENIED. * The VFS handles checking certain flags already reducing the verbosity of these tests. This includes attempts to create new nodes, which requires the parent connection to be served as writable. This is not possible with how the nodes are implemented, so these tests have been removed in lieu of assertions that guarantee we cannot create new files, and tests that ensure we cannot create mutable connections * Callers of the fuchsia.io/Directory.DeprecatedOpen method now reject requests to open files where the path ends with a trailing slash, since the VFS adds OpenFlags.DIRECTORY in these cases. This is NOT done for the new fuchsia.io/Directory.Open method, so that is still allowed for those tests. As we are now testing through a DirectoryProxy instead of calling the VFS Node trait methods directly, we can simplify a lot of test code by using the helpers in the fuchsia-fs crate. This improves test readability significantly in some cases, and also ensures that we test end-to-end behavior that clients will encounter. There should be no change to code coverage with these tests, but there is a small functional change: in certain cases when calling fuchsia.io/Directory.DeprecatedOpen, the APPEND flag was erroneously allowed. We cannot easily fix this without disabling the old CTF tests, so for now we just update them going forwards and leave the old behavior. We need to address this as part of the io2 migration soon. Remove redundant test cases where the VFS already enforces certain checks, and instead add assertions which ensure no regressions in behavior can occur. Bug: 324111518 Test: fx test package-directory-tests Change-Id: Idac8441d889ffdec3a3f93dc92ab0c7b0aaff036 Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1234244 Reviewed-by: Ben Keller <[email protected]> Commit-Queue: Brandon Castellano <[email protected]>
1 parent 35d6b31 commit 0476869

File tree

5 files changed

+558
-1070
lines changed

5 files changed

+558
-1070
lines changed

src/sys/pkg/lib/package-directory/src/lib.rs

Lines changed: 13 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ mod root_dir_cache;
2424
pub use root_dir::{PathError, ReadFileError, RootDir, SubpackagesError};
2525
pub use root_dir_cache::RootDirCache;
2626
pub use vfs::execution_scope::ExecutionScope;
27-
pub use vfs::path::Path as VfsPath;
2827

2928
pub(crate) const DIRECTORY_ABILITIES: fio::Abilities =
3029
fio::Abilities::GET_ATTRIBUTES.union(fio::Abilities::ENUMERATE).union(fio::Abilities::TRAVERSE);
3130

31+
pub(crate) const MUTABLE_FLAGS: fio::Flags =
32+
fio::Flags::PERM_MODIFY.union(fio::Flags::PERM_SET_ATTRIBUTES).union(fio::Flags::PERM_WRITE);
33+
3234
#[derive(thiserror::Error, Debug)]
3335
pub enum Error {
3436
#[error("the meta.far was not found")]
@@ -257,7 +259,7 @@ pub fn serve(
257259
non_meta_storage,
258260
meta_far,
259261
flags,
260-
VfsPath::dot(),
262+
vfs::Path::dot(),
261263
server_end.into_channel().into(),
262264
)
263265
}
@@ -273,7 +275,7 @@ pub async fn serve_path(
273275
non_meta_storage: impl NonMetaStorage,
274276
meta_far: fuchsia_hash::Hash,
275277
flags: fio::Flags,
276-
path: VfsPath,
278+
path: vfs::Path,
277279
server_end: ServerEnd<fio::NodeMarker>,
278280
) -> Result<(), Error> {
279281
let root_dir = match RootDir::new(non_meta_storage, meta_far).await {
@@ -365,9 +367,6 @@ mod tests {
365367
use fuchsia_pkg_testing::blobfs::Fake as FakeBlobfs;
366368
use fuchsia_pkg_testing::PackageBuilder;
367369
use futures::StreamExt;
368-
use std::any::Any;
369-
use std::sync::Arc;
370-
use vfs::directory::dirents_sink::{self, AppendResult, Sealed, Sink};
371370
use vfs::directory::helper::DirectlyMutable;
372371

373372
#[fuchsia_async::run_singlethreaded(test)]
@@ -410,7 +409,7 @@ mod tests {
410409
blobfs_client,
411410
metafar_blob.merkle,
412411
fio::PERM_READABLE,
413-
VfsPath::validate_and_split(".").unwrap(),
412+
vfs::Path::validate_and_split(".").unwrap(),
414413
server_end.into_channel().into(),
415414
)
416415
.await
@@ -438,7 +437,7 @@ mod tests {
438437
blobfs_client,
439438
metafar_blob.merkle,
440439
fio::PERM_READABLE | fio::Flags::PROTOCOL_FILE,
441-
VfsPath::validate_and_split("meta").unwrap(),
440+
vfs::Path::validate_and_split("meta").unwrap(),
442441
server_end.into_channel().into(),
443442
)
444443
.await
@@ -464,7 +463,7 @@ mod tests {
464463
blobfs_client,
465464
metafar_blob.merkle,
466465
fio::PERM_READABLE | fio::Flags::FLAG_SEND_REPRESENTATION,
467-
VfsPath::validate_and_split("not-present").unwrap(),
466+
vfs::Path::validate_and_split("not-present").unwrap(),
468467
server_end.into_channel().into(),
469468
)
470469
.await,
@@ -487,7 +486,7 @@ mod tests {
487486
blobfs_client,
488487
Hash::from([0u8; 32]),
489488
fio::PERM_READABLE | fio::Flags::FLAG_SEND_REPRESENTATION,
490-
VfsPath::validate_and_split(".").unwrap(),
489+
vfs::Path::validate_and_split(".").unwrap(),
491490
server_end.into_channel().into(),
492491
)
493492
.await,
@@ -561,77 +560,17 @@ mod tests {
561560
assert_eq!(get_dir_children(["a/b/c/d"], "a/"), vec![(dir(), "b".to_string())]);
562561
}
563562

564-
/// Implementation of vfs::directory::dirents_sink::Sink.
565-
/// Sink::append begins to fail (returns Sealed) after `max_entries` entries have been appended.
566-
#[derive(Clone)]
567-
pub(crate) struct FakeSink {
568-
max_entries: usize,
569-
pub(crate) entries: Vec<(String, EntryInfo)>,
570-
sealed: bool,
571-
}
572-
573-
impl FakeSink {
574-
pub(crate) fn new(max_entries: usize) -> Self {
575-
FakeSink { max_entries, entries: Vec::with_capacity(max_entries), sealed: false }
576-
}
577-
578-
pub(crate) fn from_sealed(sealed: Box<dyn dirents_sink::Sealed>) -> Box<FakeSink> {
579-
sealed.into()
580-
}
581-
}
582-
583-
impl From<Box<dyn dirents_sink::Sealed>> for Box<FakeSink> {
584-
fn from(sealed: Box<dyn dirents_sink::Sealed>) -> Self {
585-
sealed.open().downcast::<FakeSink>().unwrap()
586-
}
587-
}
588-
589-
impl Sink for FakeSink {
590-
fn append(mut self: Box<Self>, entry: &EntryInfo, name: &str) -> AppendResult {
591-
assert!(!self.sealed);
592-
if self.entries.len() == self.max_entries {
593-
AppendResult::Sealed(self.seal())
594-
} else {
595-
self.entries.push((name.to_owned(), entry.clone()));
596-
AppendResult::Ok(self)
597-
}
598-
}
599-
600-
fn seal(mut self: Box<Self>) -> Box<dyn Sealed> {
601-
self.sealed = true;
602-
self
603-
}
604-
}
605-
606-
impl Sealed for FakeSink {
607-
fn open(self: Box<Self>) -> Box<dyn Any> {
608-
self
609-
}
610-
}
611-
612563
const BLOB_CONTENTS: &[u8] = b"blob-contents";
613564

614565
fn blob_contents_hash() -> Hash {
615566
fuchsia_merkle::from_slice(BLOB_CONTENTS).root()
616567
}
617568

618-
fn serve_directory(directory: Arc<vfs::directory::immutable::Simple>) -> fio::DirectoryProxy {
619-
let (proxy, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
620-
vfs::directory::entry_container::Directory::open(
621-
directory,
622-
vfs::execution_scope::ExecutionScope::new(),
623-
fio::OpenFlags::RIGHT_READABLE,
624-
vfs::path::Path::dot(),
625-
fidl::endpoints::ServerEnd::new(server_end.into_channel()),
626-
);
627-
proxy
628-
}
629-
630569
#[fuchsia_async::run_singlethreaded(test)]
631570
async fn bootfs_get_vmo_blob() {
632571
let directory = vfs::directory::immutable::simple();
633572
directory.add_entry(blob_contents_hash(), vfs::file::read_only(BLOB_CONTENTS)).unwrap();
634-
let proxy = serve_directory(directory);
573+
let proxy = vfs::directory::serve_read_only(directory);
635574

636575
let vmo = proxy.get_blob_vmo(&blob_contents_hash()).await.unwrap();
637576
assert_eq!(vmo.read_to_vec(0, BLOB_CONTENTS.len() as u64).unwrap(), BLOB_CONTENTS);
@@ -641,15 +580,15 @@ mod tests {
641580
async fn bootfs_read_blob() {
642581
let directory = vfs::directory::immutable::simple();
643582
directory.add_entry(blob_contents_hash(), vfs::file::read_only(BLOB_CONTENTS)).unwrap();
644-
let proxy = serve_directory(directory);
583+
let proxy = vfs::directory::serve_read_only(directory);
645584

646585
assert_eq!(proxy.read_blob(&blob_contents_hash()).await.unwrap(), BLOB_CONTENTS);
647586
}
648587

649588
#[fuchsia_async::run_singlethreaded(test)]
650589
async fn bootfs_get_vmo_blob_missing_blob() {
651590
let directory = vfs::directory::immutable::simple();
652-
let proxy = serve_directory(directory);
591+
let proxy = vfs::directory::serve_read_only(directory);
653592

654593
let result = proxy.get_blob_vmo(&blob_contents_hash()).await;
655594
assert_matches!(result, Err(NonMetaStorageError::OpenBlob(e)) if e.is_not_found_error());
@@ -658,7 +597,7 @@ mod tests {
658597
#[fuchsia_async::run_singlethreaded(test)]
659598
async fn bootfs_read_blob_missing_blob() {
660599
let directory = vfs::directory::immutable::simple();
661-
let proxy = serve_directory(directory);
600+
let proxy = vfs::directory::serve_read_only(directory);
662601

663602
let result = proxy.read_blob(&blob_contents_hash()).await;
664603
assert_matches!(result, Err(NonMetaStorageError::ReadBlob(e)) if e.is_not_found_error());

0 commit comments

Comments
 (0)