blob: 46e02be71968746c9dd02ca096af7ad1dab0d93a [file] [log] [blame]
// Copyright 2023 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.
//! fuchsia io conformance testing harness for Fxfs
use {
anyhow::{Context as _, Error},
fidl_fuchsia_io as fio,
fidl_fuchsia_io_test::{
self as io_test, Io1Config, Io1HarnessRequest, Io1HarnessRequestStream,
},
fuchsia_component::server::ServiceFs,
futures::prelude::*,
fxfs_testing::{open_dir, open_file, TestFixture},
std::sync::atomic::{AtomicU64, Ordering},
tracing::error,
};
struct Harness(Io1HarnessRequestStream);
const FLAGS: fio::OpenFlags = fio::OpenFlags::CREATE
.union(fio::OpenFlags::RIGHT_READABLE)
.union(fio::OpenFlags::RIGHT_WRITABLE);
async fn add_entries(
dest: fio::DirectoryProxy,
entries: Vec<Option<Box<io_test::DirectoryEntry>>>,
) -> Result<(), Error> {
let mut queue = vec![(dest, entries)];
while let Some((dest, entries)) = queue.pop() {
for entry in entries {
match *entry.unwrap() {
io_test::DirectoryEntry::Directory(io_test::Directory {
name: Some(name),
entries,
..
}) => {
let new_dir = open_dir(&dest, FLAGS | fio::OpenFlags::DIRECTORY, &name)
.await
.context(format!("failed to create directory {name}"))?;
if let Some(entries) = entries {
queue.push((new_dir, entries));
}
}
io_test::DirectoryEntry::File(io_test::File {
name: Some(name), contents, ..
}) => {
let file = open_file(&dest, FLAGS, &name)
.await
.context(format!("failed to create file {name}"))?;
if let Some(contents) = contents {
fuchsia_fs::file::write(&file, contents)
.await
.context(format!("failed to write contents for {name}"))?;
}
}
io_test::DirectoryEntry::VmoFile(io_test::VmoFile {
name: Some(name),
vmo: Some(vmo),
..
}) => {
let file = open_file(&dest, FLAGS, &name)
.await
.context(format!("failed to create file {name}"))?;
fuchsia_fs::file::write(&file, &vmo.read_to_vec(0, vmo.get_content_size()?)?)
.await
.context(format!("failed to write contents for {name}"))?;
}
_ => panic!("Not supported"),
}
}
}
Ok(())
}
async fn run(mut stream: Io1HarnessRequestStream, fixture: &TestFixture) -> Result<(), Error> {
static COUNTER: AtomicU64 = AtomicU64::new(0);
while let Some(request) = stream.try_next().await.context("error running harness server")? {
match request {
Io1HarnessRequest::GetConfig { responder } => {
responder.send(&Io1Config {
supports_create: Some(true),
supports_executable_file: Some(false),
supports_vmo_file: Some(false),
supports_remote_dir: Some(false),
supports_rename: Some(true),
supports_link: Some(true),
supports_set_attr: Some(true),
supports_get_token: Some(true),
supports_unlink: Some(true),
supports_open2: Some(true),
supports_get_attributes: Some(true),
supports_update_attributes: Some(true),
supports_link_into: Some(true),
supports_directory_watchers: Some(true),
supports_append: Some(true),
..Default::default()
})?;
}
Io1HarnessRequest::GetDirectory {
root,
flags,
directory_request,
control_handle: _,
} => {
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
let dir = open_dir(
fixture.root(),
FLAGS | fio::OpenFlags::DIRECTORY,
&format!("test.{}", counter),
)
.await
.unwrap();
if let Some(entries) = root.entries {
add_entries(
fuchsia_fs::directory::clone_no_describe(&dir, None).expect("clone failed"),
entries,
)
.await
.expect("add_entries failed");
}
dir.open(
flags,
fio::ModeType::empty(),
".",
directory_request.into_channel().into(),
)
.unwrap();
}
};
}
Ok(())
}
#[fuchsia::main(threads = 4)]
async fn main() -> Result<(), Error> {
let mut fs = ServiceFs::new();
fs.dir("svc").add_fidl_service(Harness);
fs.take_and_serve_directory_handle()?;
let fixture = TestFixture::new().await;
fs.for_each_concurrent(10_000, |Harness(stream)| {
run(stream, &fixture).unwrap_or_else(|e| error!("Error processing request: {e:?}"))
})
.await;
fixture.close().await;
Ok(())
}