blob: 18d5581251edcaeb9d379ed4a91e8981b4b73cf6 [file] [log] [blame]
// Copyright 2021 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 {
async_trait::async_trait,
fidl_fuchsia_io as fio, fuchsia_async as fasync,
fuchsia_zircon::Status,
futures::{SinkExt as _, StreamExt as _},
once_cell::sync::OnceCell,
storage_stress_test_utils::{data::FileFactory, io::Directory},
stress_test::actor::{Actor, ActorError},
tracing::info,
};
// TODO(https://fxbug.dev/42146417): This actor is very basic. At the moment, this is fine, since this is a
// v0 implementation of minfs stress tests. Eventually, we should write stress tests that exercise
// minfs as a true POSIX filesystem.
pub struct FileActor {
pub factory: FileFactory,
pub home_dir: Directory,
progress_channel_and_task:
OnceCell<(futures::channel::mpsc::UnboundedSender<()>, fasync::Task<()>)>,
}
impl FileActor {
pub fn new(factory: FileFactory, home_dir: Directory) -> Self {
Self { factory, home_dir, progress_channel_and_task: OnceCell::new() }
}
/// Arms a timer which will expire after `duration` and fail the test.
/// Each time a file is successfully created, the timer is reset. This ensures forward
/// progress.
pub async fn set_progress_timer(&self, duration: std::time::Duration) {
let (tx, mut rx) = futures::channel::mpsc::unbounded();
let task = fasync::Task::spawn(async move {
use futures::future::FutureExt;
loop {
let duration_clone = duration.clone();
futures::select! {
() = fuchsia_async::Timer::new(duration_clone).fuse() =>
{
panic!("No progress made after {:?}", duration_clone);
}
_ = rx.next() => continue,
}
}
});
self.progress_channel_and_task.set((tx, task)).expect("Failed to set timer channel");
}
async fn create_file(&mut self) -> Result<(), Status> {
let filename = self.factory.generate_filename();
let data_bytes = self.factory.generate_bytes();
// Write the file to disk
let file = self
.home_dir
.open_file(
&filename,
fio::OpenFlags::CREATE
| fio::OpenFlags::CREATE_IF_ABSENT
| fio::OpenFlags::RIGHT_WRITABLE,
)
.await?;
file.write(&data_bytes).await?;
file.close().await
}
}
#[async_trait]
impl Actor for FileActor {
async fn perform(&mut self) -> Result<(), ActorError> {
match self.create_file().await {
Ok(()) => {
self.progress_channel_and_task.get_mut().unwrap().0.send(()).await.unwrap();
Ok(())
}
Err(Status::NO_SPACE) => Ok(()),
// Any other error is assumed to come from an intentional crash.
// The environment verifies that an intentional crash occurred
// and will panic if that is not the case.
Err(s) => {
info!("File actor got status: {}", s);
Err(ActorError::ResetEnvironment)
}
}
}
}