|
@@ -4,9 +4,9 @@ use fuse_daemon::FuseDaemon;
|
|
mod config;
|
|
mod config;
|
|
mod fuse_fs;
|
|
mod fuse_fs;
|
|
|
|
|
|
-use config::{Config, ConfigRef, EnvVars};
|
|
|
|
|
|
+use config::{Config, ConfigRef, EnvVars, FsKind};
|
|
|
|
|
|
-use btfproto::{local_fs::LocalFs, server::FsProvider};
|
|
|
|
|
|
+use btfproto::{client::FsClient, local_fs::LocalFs, server::FsProvider};
|
|
use btlib::{
|
|
use btlib::{
|
|
config_helpers::from_envvar,
|
|
config_helpers::from_envvar,
|
|
crypto::{
|
|
crypto::{
|
|
@@ -15,6 +15,7 @@ use btlib::{
|
|
},
|
|
},
|
|
Result,
|
|
Result,
|
|
};
|
|
};
|
|
|
|
+use btmsg::{transmitter, BlockAddr};
|
|
use std::{
|
|
use std::{
|
|
fs::{self},
|
|
fs::{self},
|
|
io,
|
|
io,
|
|
@@ -24,8 +25,11 @@ use std::{
|
|
use tokio::sync::oneshot;
|
|
use tokio::sync::oneshot;
|
|
|
|
|
|
const ENVVARS: EnvVars = EnvVars {
|
|
const ENVVARS: EnvVars = EnvVars {
|
|
|
|
+ block_dir: "BT_BLOCKDIR",
|
|
tabrmd: "BT_TABRMD",
|
|
tabrmd: "BT_TABRMD",
|
|
mnt_options: "BT_MNTOPTS",
|
|
mnt_options: "BT_MNTOPTS",
|
|
|
|
+ remote_ip: "BT_REMOTEIP",
|
|
|
|
+ remote_path: "BT_REMOTEPATH",
|
|
};
|
|
};
|
|
|
|
|
|
const DEFAULT_CONFIG: ConfigRef<'static> = ConfigRef {
|
|
const DEFAULT_CONFIG: ConfigRef<'static> = ConfigRef {
|
|
@@ -58,7 +62,7 @@ fn node_creds(state_file: PathBuf, tabrmd_cfg: &str) -> Result<TpmCreds> {
|
|
cred_store.node_creds()
|
|
cred_store.node_creds()
|
|
}
|
|
}
|
|
|
|
|
|
-async fn provider<C: 'static + Creds + Send + Sync>(
|
|
|
|
|
|
+async fn local_provider<C: 'static + Creds + Send + Sync>(
|
|
btdir: PathBuf,
|
|
btdir: PathBuf,
|
|
node_creds: C,
|
|
node_creds: C,
|
|
) -> Result<impl FsProvider> {
|
|
) -> Result<impl FsProvider> {
|
|
@@ -71,6 +75,15 @@ async fn provider<C: 'static + Creds + Send + Sync>(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+async fn remote_provider<C: 'static + Creds + Send + Sync>(
|
|
|
|
+ remote_addr: BlockAddr,
|
|
|
|
+ node_creds: C,
|
|
|
|
+) -> Result<impl FsProvider> {
|
|
|
|
+ let tx = transmitter(Arc::new(remote_addr), Arc::new(node_creds)).await?;
|
|
|
|
+ let client = FsClient::new(tx);
|
|
|
|
+ Ok(client)
|
|
|
|
+}
|
|
|
|
+
|
|
async fn run_daemon(config: Config, mounted_signal: Option<oneshot::Sender<()>>) {
|
|
async fn run_daemon(config: Config, mounted_signal: Option<oneshot::Sender<()>>) {
|
|
let node_creds =
|
|
let node_creds =
|
|
node_creds(config.tpm_state_file, &config.tabrmd).expect("failed to get node creds");
|
|
node_creds(config.tpm_state_file, &config.tabrmd).expect("failed to get node creds");
|
|
@@ -81,17 +94,32 @@ async fn run_daemon(config: Config, mounted_signal: Option<oneshot::Sender<()>>)
|
|
.unwrap();
|
|
.unwrap();
|
|
Arc::new(writecap.bind_path())
|
|
Arc::new(writecap.bind_path())
|
|
};
|
|
};
|
|
- let provider = provider(config.block_dir, node_creds)
|
|
|
|
- .await
|
|
|
|
- .expect("failed to create FS provider");
|
|
|
|
-
|
|
|
|
- let mut daemon = FuseDaemon::new(
|
|
|
|
- config.mnt_dir,
|
|
|
|
- config.threads,
|
|
|
|
- fallback_path,
|
|
|
|
- mounted_signal,
|
|
|
|
- provider,
|
|
|
|
- )
|
|
|
|
|
|
+ let mut daemon = match config.fs_kind {
|
|
|
|
+ FsKind::Local(btdir) => {
|
|
|
|
+ let provider = local_provider(btdir, node_creds)
|
|
|
|
+ .await
|
|
|
|
+ .expect("failed to create local provider");
|
|
|
|
+ FuseDaemon::new(
|
|
|
|
+ config.mnt_dir,
|
|
|
|
+ config.threads,
|
|
|
|
+ fallback_path,
|
|
|
|
+ mounted_signal,
|
|
|
|
+ provider,
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ FsKind::Remote(remote_addr) => {
|
|
|
|
+ let provider = remote_provider(remote_addr, node_creds)
|
|
|
|
+ .await
|
|
|
|
+ .expect("failed to create remote provider");
|
|
|
|
+ FuseDaemon::new(
|
|
|
|
+ config.mnt_dir,
|
|
|
|
+ config.threads,
|
|
|
|
+ fallback_path,
|
|
|
|
+ mounted_signal,
|
|
|
|
+ provider,
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ }
|
|
.expect("failed to create FUSE daemon");
|
|
.expect("failed to create FUSE daemon");
|
|
daemon.finished().await
|
|
daemon.finished().await
|
|
}
|
|
}
|
|
@@ -101,7 +129,9 @@ async fn main() {
|
|
env_logger::init();
|
|
env_logger::init();
|
|
let mut args = std::env::args_os().skip(1).map(PathBuf::from);
|
|
let mut args = std::env::args_os().skip(1).map(PathBuf::from);
|
|
let builder = Config::builder()
|
|
let builder = Config::builder()
|
|
- .with_block_dir(args.next())
|
|
|
|
|
|
+ .with_block_dir(from_envvar(ENVVARS.block_dir).unwrap().map(PathBuf::from))
|
|
|
|
+ .with_remote_ip(from_envvar(ENVVARS.remote_ip).unwrap())
|
|
|
|
+ .with_remote_path(from_envvar(ENVVARS.remote_path).unwrap())
|
|
.with_mnt_dir(args.next())
|
|
.with_mnt_dir(args.next())
|
|
.with_tabrmd(from_envvar(ENVVARS.tabrmd).unwrap())
|
|
.with_tabrmd(from_envvar(ENVVARS.tabrmd).unwrap())
|
|
.with_mnt_options(from_envvar(ENVVARS.mnt_options).unwrap());
|
|
.with_mnt_options(from_envvar(ENVVARS.mnt_options).unwrap());
|
|
@@ -113,7 +143,9 @@ async fn main() {
|
|
mod test {
|
|
mod test {
|
|
use super::*;
|
|
use super::*;
|
|
|
|
|
|
|
|
+ use btfproto::{local_fs::ModeAuthorizer, server::new_fs_server};
|
|
use btlib::{crypto::Creds, log::BuilderExt, Epoch, Principaled};
|
|
use btlib::{crypto::Creds, log::BuilderExt, Epoch, Principaled};
|
|
|
|
+ use btmsg::Receiver;
|
|
use ctor::ctor;
|
|
use ctor::ctor;
|
|
use std::{
|
|
use std::{
|
|
ffi::{OsStr, OsString},
|
|
ffi::{OsStr, OsString},
|
|
@@ -122,6 +154,7 @@ mod test {
|
|
set_permissions, write, OpenOptions, Permissions, ReadDir,
|
|
set_permissions, write, OpenOptions, Permissions, ReadDir,
|
|
},
|
|
},
|
|
io::{Read, Seek, SeekFrom, Write},
|
|
io::{Read, Seek, SeekFrom, Write},
|
|
|
|
+ net::{IpAddr, Ipv6Addr},
|
|
os::unix::fs::PermissionsExt,
|
|
os::unix::fs::PermissionsExt,
|
|
thread::JoinHandle,
|
|
thread::JoinHandle,
|
|
time::Duration,
|
|
time::Duration,
|
|
@@ -130,7 +163,7 @@ mod test {
|
|
use tempdir::TempDir;
|
|
use tempdir::TempDir;
|
|
use tokio::sync::oneshot::error::TryRecvError;
|
|
use tokio::sync::oneshot::error::TryRecvError;
|
|
|
|
|
|
- /// An optional timeout to wait for the FUSE daemon to start in tests.
|
|
|
|
|
|
+ /// An optional timeout to limit the time spent waiting for the FUSE daemon to start in tests.
|
|
const TIMEOUT: Option<Duration> = Some(Duration::from_millis(1000));
|
|
const TIMEOUT: Option<Duration> = Some(Duration::from_millis(1000));
|
|
|
|
|
|
/// The log level to use when running tests.
|
|
/// The log level to use when running tests.
|
|
@@ -168,63 +201,84 @@ mod test {
|
|
|
|
|
|
const ROOT_PASSWD: &str = "password";
|
|
const ROOT_PASSWD: &str = "password";
|
|
|
|
|
|
- struct TestCase {
|
|
|
|
|
|
+ struct TestCase<R> {
|
|
config: Config,
|
|
config: Config,
|
|
handle: Option<JoinHandle<()>>,
|
|
handle: Option<JoinHandle<()>>,
|
|
node_principal: OsString,
|
|
node_principal: OsString,
|
|
// Note that the drop order of these fields is significant.
|
|
// Note that the drop order of these fields is significant.
|
|
|
|
+ _receiver: Option<R>,
|
|
_cred_store: TpmCredStore,
|
|
_cred_store: TpmCredStore,
|
|
_swtpm: SwtpmHarness,
|
|
_swtpm: SwtpmHarness,
|
|
_temp_dir: TempDir,
|
|
_temp_dir: TempDir,
|
|
}
|
|
}
|
|
|
|
|
|
- impl TestCase {
|
|
|
|
- fn new() -> TestCase {
|
|
|
|
- let tmp = TempDir::new("btfuse").unwrap();
|
|
|
|
- let (mounted_tx, mut mounted_rx) = oneshot::channel();
|
|
|
|
- let (swtpm, cred_store) = Self::swtpm();
|
|
|
|
- let config = Config::builder()
|
|
|
|
- .with_block_dir(Some(tmp.path().join("bt")))
|
|
|
|
- .with_mnt_dir(Some(tmp.path().join("mnt")))
|
|
|
|
- .with_tpm_state_file(Some(swtpm.state_path().to_owned().into()))
|
|
|
|
- .with_tabrmd(Some(swtpm.tabrmd_config().to_owned()))
|
|
|
|
- .build();
|
|
|
|
- let config_clone = config.clone();
|
|
|
|
- let handle = std::thread::spawn(move || Self::run(mounted_tx, config_clone));
|
|
|
|
- match TIMEOUT {
|
|
|
|
- Some(duration) => {
|
|
|
|
- let deadline = std::time::Instant::now() + duration;
|
|
|
|
- loop {
|
|
|
|
- if std::time::Instant::now() > deadline {
|
|
|
|
- panic!("timed out waiting for the mounted signal");
|
|
|
|
- }
|
|
|
|
- match mounted_rx.try_recv() {
|
|
|
|
- Ok(_) => break,
|
|
|
|
- Err(err) => match err {
|
|
|
|
- TryRecvError::Empty => {
|
|
|
|
- std::thread::sleep(Duration::from_millis(10));
|
|
|
|
- }
|
|
|
|
- TryRecvError::Closed => {
|
|
|
|
- panic!("channel was closed before mounted signal was sent")
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- }
|
|
|
|
|
|
+ async fn new_local() -> TestCase<impl Receiver> {
|
|
|
|
+ new(false).await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn new_remote() -> TestCase<impl Receiver> {
|
|
|
|
+ new(true).await
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async fn new(remote: bool) -> TestCase<impl Receiver> {
|
|
|
|
+ let tmp = TempDir::new("btfuse").unwrap();
|
|
|
|
+ let (mounted_tx, mut mounted_rx) = oneshot::channel();
|
|
|
|
+ let (swtpm, cred_store) = TestCase::<()>::swtpm();
|
|
|
|
+ let builder = Config::builder()
|
|
|
|
+ .with_mnt_dir(Some(tmp.path().join("mnt")))
|
|
|
|
+ .with_tpm_state_file(Some(swtpm.state_path().to_owned().into()))
|
|
|
|
+ .with_tabrmd(Some(swtpm.tabrmd_config().to_owned()));
|
|
|
|
+ let block_dir = tmp.path().join("bt");
|
|
|
|
+ let (config, receiver) = if remote {
|
|
|
|
+ let node_creds = Arc::new(cred_store.node_creds().unwrap());
|
|
|
|
+ let local_fs = LocalFs::new_empty(block_dir, 0, node_creds.clone(), ModeAuthorizer)
|
|
|
|
+ .await
|
|
|
|
+ .unwrap();
|
|
|
|
+ let ip_addr = IpAddr::V6(Ipv6Addr::LOCALHOST);
|
|
|
|
+ let receiver = new_fs_server(ip_addr, node_creds, Arc::new(local_fs)).unwrap();
|
|
|
|
+ let builder = builder.with_remote_ip(Some(ip_addr.to_string()));
|
|
|
|
+ (builder.build(), Some(receiver))
|
|
|
|
+ } else {
|
|
|
|
+ (builder.with_block_dir(Some(block_dir)).build(), None)
|
|
|
|
+ };
|
|
|
|
+ let config_clone = config.clone();
|
|
|
|
+ let handle = std::thread::spawn(move || TestCase::<()>::run(mounted_tx, config_clone));
|
|
|
|
+ match TIMEOUT {
|
|
|
|
+ Some(duration) => {
|
|
|
|
+ let deadline = std::time::Instant::now() + duration;
|
|
|
|
+ loop {
|
|
|
|
+ if std::time::Instant::now() > deadline {
|
|
|
|
+ panic!("timed out waiting for the mounted signal");
|
|
|
|
+ }
|
|
|
|
+ match mounted_rx.try_recv() {
|
|
|
|
+ Ok(_) => break,
|
|
|
|
+ Err(err) => match err {
|
|
|
|
+ TryRecvError::Empty => {
|
|
|
|
+ std::thread::sleep(Duration::from_millis(10));
|
|
|
|
+ }
|
|
|
|
+ TryRecvError::Closed => {
|
|
|
|
+ panic!("channel was closed before mounted signal was sent")
|
|
|
|
+ }
|
|
|
|
+ },
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- None => mounted_rx.blocking_recv().unwrap(),
|
|
|
|
- };
|
|
|
|
- let node_principal =
|
|
|
|
- OsString::from(cred_store.node_creds().unwrap().principal().to_string());
|
|
|
|
- Self {
|
|
|
|
- config,
|
|
|
|
- handle: Some(handle),
|
|
|
|
- node_principal,
|
|
|
|
- _temp_dir: tmp,
|
|
|
|
- _swtpm: swtpm,
|
|
|
|
- _cred_store: cred_store,
|
|
|
|
}
|
|
}
|
|
|
|
+ None => mounted_rx.blocking_recv().unwrap(),
|
|
|
|
+ };
|
|
|
|
+ let node_principal =
|
|
|
|
+ OsString::from(cred_store.node_creds().unwrap().principal().to_string());
|
|
|
|
+ TestCase {
|
|
|
|
+ config,
|
|
|
|
+ handle: Some(handle),
|
|
|
|
+ node_principal,
|
|
|
|
+ _receiver: receiver,
|
|
|
|
+ _temp_dir: tmp,
|
|
|
|
+ _swtpm: swtpm,
|
|
|
|
+ _cred_store: cred_store,
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ impl<R> TestCase<R> {
|
|
fn run(mounted_tx: oneshot::Sender<()>, config: Config) {
|
|
fn run(mounted_tx: oneshot::Sender<()>, config: Config) {
|
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
|
.build()
|
|
.build()
|
|
@@ -284,7 +338,7 @@ mod test {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- impl Drop for TestCase {
|
|
|
|
|
|
+ impl<R> Drop for TestCase<R> {
|
|
fn drop(&mut self) {
|
|
fn drop(&mut self) {
|
|
self.unmount_and_wait()
|
|
self.unmount_and_wait()
|
|
}
|
|
}
|
|
@@ -292,18 +346,32 @@ mod test {
|
|
|
|
|
|
/// Creates a new file system and mounts it at `/tmp/btfuse.<random>/mnt` so it can be
|
|
/// Creates a new file system and mounts it at `/tmp/btfuse.<random>/mnt` so it can be
|
|
/// tested manually.
|
|
/// tested manually.
|
|
- //#[test]
|
|
|
|
|
|
+ //#[tokio::test]
|
|
#[allow(dead_code)]
|
|
#[allow(dead_code)]
|
|
- fn manual_test() {
|
|
|
|
- let mut case = TestCase::new();
|
|
|
|
|
|
+ async fn manual_test() {
|
|
|
|
+ let mut case = new_local().await;
|
|
case.wait()
|
|
case.wait()
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn write_read() -> Result<()> {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn write_read() -> Result<()> {
|
|
|
|
+ const EXPECTED: &[u8] =
|
|
|
|
+ b"The paths to failure are uncountable, yet to success there is but one.";
|
|
|
|
+ let case = new_local().await;
|
|
|
|
+ let file_path = case.mnt_dir().join("file");
|
|
|
|
+
|
|
|
|
+ write(&file_path, EXPECTED)?;
|
|
|
|
+
|
|
|
|
+ let actual = read(&file_path)?;
|
|
|
|
+ assert_eq!(EXPECTED, actual);
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn write_read_remote() -> Result<()> {
|
|
const EXPECTED: &[u8] =
|
|
const EXPECTED: &[u8] =
|
|
b"The paths to failure are uncountable, yet to success there is but one.";
|
|
b"The paths to failure are uncountable, yet to success there is but one.";
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_remote().await;
|
|
let file_path = case.mnt_dir().join("file");
|
|
let file_path = case.mnt_dir().join("file");
|
|
|
|
|
|
write(&file_path, EXPECTED)?;
|
|
write(&file_path, EXPECTED)?;
|
|
@@ -313,11 +381,11 @@ mod test {
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn create_file_then_readdir() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn create_file_then_readdir() {
|
|
const DATA: &[u8] = b"Au revoir Shoshanna!";
|
|
const DATA: &[u8] = b"Au revoir Shoshanna!";
|
|
let file_name = OsStr::new("landa_dialog.txt");
|
|
let file_name = OsStr::new("landa_dialog.txt");
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let mut expected = case.initial_contents();
|
|
let mut expected = case.initial_contents();
|
|
expected.push(file_name);
|
|
expected.push(file_name);
|
|
let mnt_path = case.mnt_dir();
|
|
let mnt_path = case.mnt_dir();
|
|
@@ -331,11 +399,11 @@ mod test {
|
|
assert!(second.eq(expected));
|
|
assert!(second.eq(expected));
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn create_then_delete_file() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn create_then_delete_file() {
|
|
const DATA: &[u8] = b"The universe is hostile, so impersonal. Devour to survive";
|
|
const DATA: &[u8] = b"The universe is hostile, so impersonal. Devour to survive";
|
|
let file_name = OsStr::new("tool_lyrics.txt");
|
|
let file_name = OsStr::new("tool_lyrics.txt");
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let mnt_path = case.mnt_dir();
|
|
let mnt_path = case.mnt_dir();
|
|
let file_path = mnt_path.join(file_name);
|
|
let file_path = mnt_path.join(file_name);
|
|
write(&file_path, DATA).expect("write failed");
|
|
write(&file_path, DATA).expect("write failed");
|
|
@@ -347,12 +415,12 @@ mod test {
|
|
assert!(actual.eq(expected));
|
|
assert!(actual.eq(expected));
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn hard_link_then_remove() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn hard_link_then_remove() {
|
|
const EXPECTED: &[u8] = b"And the lives we've reclaimed";
|
|
const EXPECTED: &[u8] = b"And the lives we've reclaimed";
|
|
let name1 = OsStr::new("refugee_lyrics.txt");
|
|
let name1 = OsStr::new("refugee_lyrics.txt");
|
|
let name2 = OsStr::new("rise_against_lyrics.txt");
|
|
let name2 = OsStr::new("rise_against_lyrics.txt");
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let mnt_path = case.mnt_dir();
|
|
let mnt_path = case.mnt_dir();
|
|
let path1 = mnt_path.join(name1);
|
|
let path1 = mnt_path.join(name1);
|
|
let path2 = mnt_path.join(name2);
|
|
let path2 = mnt_path.join(name2);
|
|
@@ -365,12 +433,12 @@ mod test {
|
|
assert_eq!(EXPECTED, actual);
|
|
assert_eq!(EXPECTED, actual);
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn hard_link_then_remove_both() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn hard_link_then_remove_both() {
|
|
const EXPECTED: &[u8] = b"And the lives we've reclaimed";
|
|
const EXPECTED: &[u8] = b"And the lives we've reclaimed";
|
|
let name1 = OsStr::new("refugee_lyrics.txt");
|
|
let name1 = OsStr::new("refugee_lyrics.txt");
|
|
let name2 = OsStr::new("rise_against_lyrics.txt");
|
|
let name2 = OsStr::new("rise_against_lyrics.txt");
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let mnt_path = case.mnt_dir();
|
|
let mnt_path = case.mnt_dir();
|
|
let path1 = mnt_path.join(name1);
|
|
let path1 = mnt_path.join(name1);
|
|
let path2 = mnt_path.join(name2);
|
|
let path2 = mnt_path.join(name2);
|
|
@@ -384,10 +452,10 @@ mod test {
|
|
assert!(file_names(read_dir(&mnt_path).expect("read_dir failed")).eq(expected));
|
|
assert!(file_names(read_dir(&mnt_path).expect("read_dir failed")).eq(expected));
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn set_mode_bits() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn set_mode_bits() {
|
|
const EXPECTED: u32 = libc::S_IFREG | 0o777;
|
|
const EXPECTED: u32 = libc::S_IFREG | 0o777;
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let file_path = case.mnt_dir().join("bagobits");
|
|
let file_path = case.mnt_dir().join("bagobits");
|
|
write(&file_path, []).expect("write failed");
|
|
write(&file_path, []).expect("write failed");
|
|
let original = metadata(&file_path)
|
|
let original = metadata(&file_path)
|
|
@@ -406,10 +474,10 @@ mod test {
|
|
assert_eq!(EXPECTED, actual);
|
|
assert_eq!(EXPECTED, actual);
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn create_directory() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn create_directory() {
|
|
const EXPECTED: &str = "etc";
|
|
const EXPECTED: &str = "etc";
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let mnt_path = case.mnt_dir();
|
|
let mnt_path = case.mnt_dir();
|
|
let dir_path = mnt_path.join(EXPECTED);
|
|
let dir_path = mnt_path.join(EXPECTED);
|
|
let mut expected = case.initial_contents();
|
|
let mut expected = case.initial_contents();
|
|
@@ -421,11 +489,11 @@ mod test {
|
|
assert!(actual.eq(expected));
|
|
assert!(actual.eq(expected));
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn create_file_under_new_directory() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn create_file_under_new_directory() {
|
|
const DIR_NAME: &str = "etc";
|
|
const DIR_NAME: &str = "etc";
|
|
const FILE_NAME: &str = "file";
|
|
const FILE_NAME: &str = "file";
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let mnt_path = case.mnt_dir();
|
|
let mnt_path = case.mnt_dir();
|
|
let dir_path = mnt_path.join(DIR_NAME);
|
|
let dir_path = mnt_path.join(DIR_NAME);
|
|
let file_path = dir_path.join(FILE_NAME);
|
|
let file_path = dir_path.join(FILE_NAME);
|
|
@@ -437,10 +505,10 @@ mod test {
|
|
assert!(actual.eq([FILE_NAME]));
|
|
assert!(actual.eq([FILE_NAME]));
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn create_then_remove_directory() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn create_then_remove_directory() {
|
|
const DIR_NAME: &str = "etc";
|
|
const DIR_NAME: &str = "etc";
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let mnt_path = case.mnt_dir();
|
|
let mnt_path = case.mnt_dir();
|
|
let dir_path = mnt_path.join(DIR_NAME);
|
|
let dir_path = mnt_path.join(DIR_NAME);
|
|
|
|
|
|
@@ -451,10 +519,10 @@ mod test {
|
|
assert!(actual.eq(case.initial_contents()));
|
|
assert!(actual.eq(case.initial_contents()));
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn read_only_dir_cant_create_subdir() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn read_only_dir_cant_create_subdir() {
|
|
const DIR_NAME: &str = "etc";
|
|
const DIR_NAME: &str = "etc";
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let dir_path = case.mnt_dir().join(DIR_NAME);
|
|
let dir_path = case.mnt_dir().join(DIR_NAME);
|
|
create_dir(&dir_path).expect("create_dir failed");
|
|
create_dir(&dir_path).expect("create_dir failed");
|
|
set_permissions(&dir_path, Permissions::from_mode(libc::S_IFDIR | 0o444))
|
|
set_permissions(&dir_path, Permissions::from_mode(libc::S_IFDIR | 0o444))
|
|
@@ -467,10 +535,10 @@ mod test {
|
|
assert_eq!(os_err, libc::EACCES);
|
|
assert_eq!(os_err, libc::EACCES);
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn read_only_dir_cant_remove_subdir() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn read_only_dir_cant_remove_subdir() {
|
|
const DIR_NAME: &str = "etc";
|
|
const DIR_NAME: &str = "etc";
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let dir_path = case.mnt_dir().join(DIR_NAME);
|
|
let dir_path = case.mnt_dir().join(DIR_NAME);
|
|
let sub_path = dir_path.join("sub");
|
|
let sub_path = dir_path.join("sub");
|
|
create_dir(&dir_path).expect("create_dir failed");
|
|
create_dir(&dir_path).expect("create_dir failed");
|
|
@@ -485,11 +553,11 @@ mod test {
|
|
assert_eq!(os_err, libc::EACCES);
|
|
assert_eq!(os_err, libc::EACCES);
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn rename_file() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn rename_file() {
|
|
const FILE_NAME: &str = "parabola.txt";
|
|
const FILE_NAME: &str = "parabola.txt";
|
|
const EXPECTED: &[u8] = b"We are eternal all this pain is an illusion";
|
|
const EXPECTED: &[u8] = b"We are eternal all this pain is an illusion";
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let src_path = case.mnt_dir().join(FILE_NAME);
|
|
let src_path = case.mnt_dir().join(FILE_NAME);
|
|
let dst_path = case.mnt_dir().join("parabola_lyrics.txt");
|
|
let dst_path = case.mnt_dir().join("parabola_lyrics.txt");
|
|
|
|
|
|
@@ -500,8 +568,8 @@ mod test {
|
|
assert_eq!(EXPECTED, actual)
|
|
assert_eq!(EXPECTED, actual)
|
|
}
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
|
- fn write_read_with_file_struct() {
|
|
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn write_read_with_file_struct() {
|
|
const FILE_NAME: &str = "big.dat";
|
|
const FILE_NAME: &str = "big.dat";
|
|
const LEN: usize = btlib::SECTOR_SZ_DEFAULT + 1;
|
|
const LEN: usize = btlib::SECTOR_SZ_DEFAULT + 1;
|
|
fn fill(buf: &mut Vec<u8>, value: u8) {
|
|
fn fill(buf: &mut Vec<u8>, value: u8) {
|
|
@@ -509,7 +577,7 @@ mod test {
|
|
buf.extend(std::iter::repeat(value).take(buf.capacity()));
|
|
buf.extend(std::iter::repeat(value).take(buf.capacity()));
|
|
}
|
|
}
|
|
|
|
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let file_path = case.mnt_dir().join(FILE_NAME);
|
|
let file_path = case.mnt_dir().join(FILE_NAME);
|
|
let mut buf = vec![1u8; LEN];
|
|
let mut buf = vec![1u8; LEN];
|
|
let mut file = OpenOptions::new()
|
|
let mut file = OpenOptions::new()
|
|
@@ -530,17 +598,17 @@ mod test {
|
|
assert_eq!(buf, actual);
|
|
assert_eq!(buf, actual);
|
|
}
|
|
}
|
|
|
|
|
|
- //#[test]
|
|
|
|
|
|
+ //#[tokio::test]
|
|
#[allow(dead_code)]
|
|
#[allow(dead_code)]
|
|
/// KMC: This test is currently not working, and I've not been able to figure out why, nor
|
|
/// KMC: This test is currently not working, and I've not been able to figure out why, nor
|
|
/// reproduce it at a lower layer of the stack.
|
|
/// reproduce it at a lower layer of the stack.
|
|
- fn read_more_than_whats_buffered() {
|
|
|
|
|
|
+ async fn read_more_than_whats_buffered() {
|
|
const FILE_NAME: &str = "big.dat";
|
|
const FILE_NAME: &str = "big.dat";
|
|
const SECT_SZ: usize = btlib::SECTOR_SZ_DEFAULT;
|
|
const SECT_SZ: usize = btlib::SECTOR_SZ_DEFAULT;
|
|
const DIVISOR: usize = 8;
|
|
const DIVISOR: usize = 8;
|
|
const READ_SZ: usize = SECT_SZ / DIVISOR;
|
|
const READ_SZ: usize = SECT_SZ / DIVISOR;
|
|
|
|
|
|
- let case = TestCase::new();
|
|
|
|
|
|
+ let case = new_local().await;
|
|
let file_path = case.mnt_dir().join(FILE_NAME);
|
|
let file_path = case.mnt_dir().join(FILE_NAME);
|
|
let mut file = OpenOptions::new()
|
|
let mut file = OpenOptions::new()
|
|
.create(true)
|
|
.create(true)
|