|
@@ -80,7 +80,9 @@ impl LocalFsTest {
|
|
|
.writecap()
|
|
|
.ok_or(BlockError::MissingWritecap)
|
|
|
.unwrap();
|
|
|
- let fs = LocalFs::new_empty(path, 0, root_creds, ModeAuthorizer).unwrap();
|
|
|
+ let fs = LocalFs::new_empty(path, 0, root_creds, ModeAuthorizer)
|
|
|
+ .await
|
|
|
+ .unwrap();
|
|
|
|
|
|
let proc_rec = IssuedProcRec {
|
|
|
addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
|
|
@@ -122,9 +124,9 @@ mod tests {
|
|
|
|
|
|
use btfproto::{local_fs::Error, msg::*};
|
|
|
use btlib::{Inode, Result, SECTOR_SZ_DEFAULT};
|
|
|
- use bytes::BytesMut;
|
|
|
use std::{
|
|
|
io::{self, Cursor, Write as IoWrite},
|
|
|
+ ops::Deref,
|
|
|
sync::Arc,
|
|
|
};
|
|
|
|
|
@@ -148,30 +150,24 @@ mod tests {
|
|
|
|
|
|
const LEN: usize = 32;
|
|
|
let expected = [1u8; LEN];
|
|
|
- let WriteReply { written, .. } = bt
|
|
|
- .write(
|
|
|
- from,
|
|
|
- inode,
|
|
|
- handle,
|
|
|
- 0,
|
|
|
- expected.len() as u64,
|
|
|
- expected.as_slice(),
|
|
|
- )
|
|
|
- .await
|
|
|
- .unwrap();
|
|
|
+ let write_msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: expected.as_slice(),
|
|
|
+ };
|
|
|
+ let WriteReply { written, .. } = bt.write(from, write_msg).await.unwrap();
|
|
|
assert_eq!(LEN as u64, written);
|
|
|
|
|
|
- let mut actual = [0u8; LEN];
|
|
|
let read_msg = Read {
|
|
|
inode,
|
|
|
handle,
|
|
|
offset: 0,
|
|
|
size: LEN as u64,
|
|
|
};
|
|
|
- bt.read(from, read_msg, |data| actual.copy_from_slice(data))
|
|
|
- .unwrap();
|
|
|
+ let guard = bt.read(from, read_msg).await.unwrap();
|
|
|
|
|
|
- assert_eq!(expected, actual)
|
|
|
+ assert_eq!(expected, guard.deref())
|
|
|
}
|
|
|
|
|
|
#[tokio::test]
|
|
@@ -220,10 +216,13 @@ mod tests {
|
|
|
};
|
|
|
let CreateReply { handle, inode, .. } = bt.create(from, create_msg).await.unwrap();
|
|
|
|
|
|
- let WriteReply { written, .. } = bt
|
|
|
- .write(from, inode, handle, 0, EXPECTED.len() as u64, EXPECTED)
|
|
|
- .await
|
|
|
- .unwrap();
|
|
|
+ let write_msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: EXPECTED,
|
|
|
+ };
|
|
|
+ let WriteReply { written, .. } = bt.write(from, write_msg).await.unwrap();
|
|
|
assert_eq!(EXPECTED.len() as u64, written);
|
|
|
|
|
|
let close_msg = Close { inode, handle };
|
|
@@ -246,17 +245,15 @@ mod tests {
|
|
|
};
|
|
|
let OpenReply { handle, .. } = bt.open(from, open_msg).await.unwrap();
|
|
|
|
|
|
- let mut actual = BytesMut::new();
|
|
|
let read_msg = Read {
|
|
|
inode,
|
|
|
handle,
|
|
|
offset: 0,
|
|
|
size: EXPECTED.len() as u64,
|
|
|
};
|
|
|
- bt.read(from, read_msg, |data| actual.extend_from_slice(data))
|
|
|
- .unwrap();
|
|
|
+ let guard = bt.read(from, read_msg).await.unwrap();
|
|
|
|
|
|
- assert_eq!(EXPECTED, &actual)
|
|
|
+ assert_eq!(EXPECTED, guard.deref())
|
|
|
}
|
|
|
|
|
|
/// Tests that an error is returned by the `Blocktree::write` method if the file was opened
|
|
@@ -287,9 +284,13 @@ mod tests {
|
|
|
let OpenReply { handle, .. } = bt.open(from, open_msg).await.unwrap();
|
|
|
|
|
|
let data = [1u8; 32];
|
|
|
- let result = bt
|
|
|
- .write(from, inode, handle, 0, data.len() as u64, data.as_slice())
|
|
|
- .await;
|
|
|
+ let write_msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: data.as_slice(),
|
|
|
+ };
|
|
|
+ let result = bt.write(from, write_msg).await;
|
|
|
|
|
|
let err = result.err().unwrap();
|
|
|
let err = err.downcast::<Error>().unwrap();
|
|
@@ -380,23 +381,24 @@ mod tests {
|
|
|
umask: 0,
|
|
|
};
|
|
|
let CreateReply { inode, handle, .. } = bt.create(from, create_msg).await.unwrap();
|
|
|
- let WriteReply { written, .. } = bt
|
|
|
- .write(from, inode, handle, 0, DATA.len() as u64, DATA.as_slice())
|
|
|
- .await
|
|
|
- .unwrap();
|
|
|
+ let write_msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: DATA.as_slice(),
|
|
|
+ };
|
|
|
+ let WriteReply { written, .. } = bt.write(from, write_msg).await.unwrap();
|
|
|
assert_eq!(DATA.len() as u64, written);
|
|
|
const SIZE: usize = DATA.len() / 2;
|
|
|
- let mut actual = Vec::with_capacity(SIZE);
|
|
|
let read_msg = Read {
|
|
|
inode,
|
|
|
handle,
|
|
|
offset: 0,
|
|
|
size: SIZE as u64,
|
|
|
};
|
|
|
- bt.read(from, read_msg, |data| actual.extend_from_slice(data))
|
|
|
- .unwrap();
|
|
|
+ let guard = bt.read(from, read_msg).await.unwrap();
|
|
|
|
|
|
- assert_eq!(&[0, 1, 2, 3], actual.as_slice());
|
|
|
+ assert_eq!(&[0, 1, 2, 3], guard.deref());
|
|
|
}
|
|
|
|
|
|
/// Returns an integer array starting at the given value and increasing by one for each
|
|
@@ -434,36 +436,35 @@ mod tests {
|
|
|
umask: 0,
|
|
|
};
|
|
|
let CreateReply { inode, handle, .. } = bt.create(from, create_msg).await.unwrap();
|
|
|
- let WriteReply { written, .. } = bt
|
|
|
- .write(from, inode, handle, 0, DATA.len() as u64, DATA.as_slice())
|
|
|
- .await
|
|
|
- .unwrap();
|
|
|
+ let write_msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: DATA.as_slice(),
|
|
|
+ };
|
|
|
+ let WriteReply { written, .. } = bt.write(from, write_msg).await.unwrap();
|
|
|
assert_eq!(DATA.len() as u64, written);
|
|
|
- let case = Box::new(case);
|
|
|
- let cb = Arc::new(Box::new(move |offset: usize| {
|
|
|
- // Notice that we have concurrent reads to different offsets using the same handle.
|
|
|
- // Without proper synchronization, this shouldn't work.
|
|
|
- let mut actual = Vec::with_capacity(SIZE);
|
|
|
- let read_msg = Read {
|
|
|
- inode,
|
|
|
- handle,
|
|
|
- offset: offset as u64,
|
|
|
- size: SIZE as u64,
|
|
|
- };
|
|
|
- case.fs
|
|
|
- .read(case.from(), read_msg, |data| actual.extend_from_slice(data))
|
|
|
- .unwrap();
|
|
|
- let expected = integer_array::<SIZE>(offset as u8);
|
|
|
- assert_eq!(&expected, actual.as_slice());
|
|
|
- }));
|
|
|
+ let case = Arc::new(case);
|
|
|
|
|
|
let mut handles = Vec::with_capacity(NREADS);
|
|
|
for offset in (0..NREADS).map(|e| e * SIZE) {
|
|
|
- let thread_cb = cb.clone();
|
|
|
- handles.push(std::thread::spawn(move || thread_cb(offset)));
|
|
|
+ let case = case.clone();
|
|
|
+ handles.push(tokio::spawn(async move {
|
|
|
+ // Notice that we have concurrent reads to different offsets using the same handle.
|
|
|
+ // Without proper synchronization, this shouldn't work.
|
|
|
+ let read_msg = Read {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: offset as u64,
|
|
|
+ size: SIZE as u64,
|
|
|
+ };
|
|
|
+ let guard = case.fs.read(case.from(), read_msg).await.unwrap();
|
|
|
+ let expected = integer_array::<SIZE>(offset as u8);
|
|
|
+ assert_eq!(&expected, guard.deref());
|
|
|
+ }));
|
|
|
}
|
|
|
for handle in handles {
|
|
|
- handle.join().unwrap();
|
|
|
+ handle.await.unwrap();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -665,9 +666,13 @@ mod tests {
|
|
|
umask: 0,
|
|
|
};
|
|
|
let CreateReply { inode, handle, .. } = bt.create(owner, create_msg).await.unwrap();
|
|
|
- let result = bt
|
|
|
- .write(&other, inode, handle, 0, 3, [1, 2, 3].as_slice())
|
|
|
- .await;
|
|
|
+ let write_msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: [1, 2, 3].as_slice(),
|
|
|
+ };
|
|
|
+ let result = bt.write(&other, write_msg).await;
|
|
|
|
|
|
let err = result.err().unwrap().downcast::<Error>().unwrap();
|
|
|
let matched = if let Error::WrongOwner = err {
|
|
@@ -693,30 +698,29 @@ mod tests {
|
|
|
umask: 0,
|
|
|
};
|
|
|
let CreateReply { inode, handle, .. } = bt.create(from, create_msg).await.unwrap();
|
|
|
- let mut actual = [0u8; 8];
|
|
|
+ const LEN: u64 = 8;
|
|
|
let alloc_msg = Allocate {
|
|
|
inode,
|
|
|
handle,
|
|
|
offset: None,
|
|
|
- size: actual.len() as u64,
|
|
|
+ size: LEN,
|
|
|
};
|
|
|
bt.allocate(from, alloc_msg).await.unwrap();
|
|
|
- let read_msg = Read {
|
|
|
- inode,
|
|
|
- handle,
|
|
|
- offset: 0,
|
|
|
- size: actual.len() as u64,
|
|
|
- };
|
|
|
- bt.read(from, read_msg, |data| actual.copy_from_slice(data))
|
|
|
- .unwrap();
|
|
|
let read_meta_msg = ReadMeta {
|
|
|
inode,
|
|
|
handle: Some(handle),
|
|
|
};
|
|
|
let ReadMetaReply { attrs, .. } = bt.read_meta(from, read_meta_msg).await.unwrap();
|
|
|
+ let read_msg = Read {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ size: LEN,
|
|
|
+ };
|
|
|
+ let guard = bt.read(from, read_msg).await.unwrap();
|
|
|
|
|
|
- assert_eq!([0u8; 8], actual);
|
|
|
- assert_eq!(actual.len() as u64, attrs.size);
|
|
|
+ assert_eq!([0u8; 8], guard.deref());
|
|
|
+ assert_eq!(guard.len() as u64, attrs.size);
|
|
|
}
|
|
|
|
|
|
#[tokio::test]
|
|
@@ -751,12 +755,10 @@ mod tests {
|
|
|
offset: 0,
|
|
|
size,
|
|
|
};
|
|
|
- let cb = |data: &[u8]| {
|
|
|
- actual.write(data)?;
|
|
|
- size -= data.len() as u64;
|
|
|
- Ok::<_, io::Error>(())
|
|
|
- };
|
|
|
- bt.read(from, read_msg, cb).unwrap().unwrap();
|
|
|
+ let guard = bt.read(from, read_msg).await.unwrap();
|
|
|
+ let data = guard.deref();
|
|
|
+ actual.write(data).unwrap();
|
|
|
+ size -= data.len() as u64;
|
|
|
}
|
|
|
let read_meta_msg = ReadMeta {
|
|
|
inode,
|
|
@@ -792,22 +794,20 @@ mod tests {
|
|
|
size,
|
|
|
};
|
|
|
bt.allocate(from, alloc_msg).await.unwrap();
|
|
|
- let mut actual = vec![0u8; LEN];
|
|
|
+ let read_meta_msg = ReadMeta {
|
|
|
+ inode,
|
|
|
+ handle: Some(handle),
|
|
|
+ };
|
|
|
+ let ReadMetaReply { attrs, .. } = bt.read_meta(from, read_meta_msg).await.unwrap();
|
|
|
let read_msg = Read {
|
|
|
inode,
|
|
|
handle,
|
|
|
offset: 0,
|
|
|
size,
|
|
|
};
|
|
|
- bt.read(from, read_msg, |data| actual.copy_from_slice(data))
|
|
|
- .unwrap();
|
|
|
- let read_meta_msg = ReadMeta {
|
|
|
- inode,
|
|
|
- handle: Some(handle),
|
|
|
- };
|
|
|
- let ReadMetaReply { attrs, .. } = bt.read_meta(from, read_meta_msg).await.unwrap();
|
|
|
+ let guard = bt.read(from, read_msg).await.unwrap();
|
|
|
|
|
|
- assert_eq!(vec![0u8; LEN], actual);
|
|
|
+ assert_eq!(vec![0u8; LEN], guard.deref());
|
|
|
assert_eq!(LEN as u64, attrs.size);
|
|
|
}
|
|
|
|
|
@@ -829,10 +829,13 @@ mod tests {
|
|
|
};
|
|
|
let CreateReply { inode, handle, .. } = bt.create(from, create_msg).await.unwrap();
|
|
|
const LEN: usize = 8;
|
|
|
- let WriteReply { written, .. } = bt
|
|
|
- .write(from, inode, handle, 0, LEN as u64, [1u8; LEN].as_slice())
|
|
|
- .await
|
|
|
- .unwrap();
|
|
|
+ let write_msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: [1u8; LEN].as_slice(),
|
|
|
+ };
|
|
|
+ let WriteReply { written, .. } = bt.write(from, write_msg).await.unwrap();
|
|
|
assert_eq!(LEN as u64, written);
|
|
|
let alloc_msg = Allocate {
|
|
|
inode,
|
|
@@ -841,22 +844,78 @@ mod tests {
|
|
|
size: (LEN / 2) as u64,
|
|
|
};
|
|
|
bt.allocate(from, alloc_msg).await.unwrap();
|
|
|
- let mut actual = [0u8; LEN];
|
|
|
+ let read_meta_msg = ReadMeta {
|
|
|
+ inode,
|
|
|
+ handle: Some(handle),
|
|
|
+ };
|
|
|
+ let ReadMetaReply { attrs, .. } = bt.read_meta(from, read_meta_msg).await.unwrap();
|
|
|
let read_msg = Read {
|
|
|
inode,
|
|
|
handle,
|
|
|
offset: 0,
|
|
|
size: LEN as u64,
|
|
|
};
|
|
|
- bt.read(from, read_msg, |data| actual.copy_from_slice(data))
|
|
|
- .unwrap();
|
|
|
- let read_meta_msg = ReadMeta {
|
|
|
+ let actual = bt.read(from, read_msg).await.unwrap();
|
|
|
+
|
|
|
+ assert_eq!([1u8; LEN], actual.deref());
|
|
|
+ assert_eq!(LEN as u64, attrs.size);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[tokio::test]
|
|
|
+ async fn read_at_non_current_position() {
|
|
|
+ const FILENAME: &str = "MANIFESTO.rtf";
|
|
|
+ let case = LocalFsTest::new_empty().await;
|
|
|
+ let bt = &case.fs;
|
|
|
+ let from = case.from();
|
|
|
+
|
|
|
+ let msg = Create {
|
|
|
+ parent: SpecInodes::RootDir.into(),
|
|
|
+ name: FILENAME,
|
|
|
+ flags: FlagValue::ReadWrite.into(),
|
|
|
+ mode: 0o644,
|
|
|
+ umask: 0,
|
|
|
+ };
|
|
|
+ let CreateReply {
|
|
|
inode,
|
|
|
- handle: Some(handle),
|
|
|
+ handle,
|
|
|
+ entry,
|
|
|
+ ..
|
|
|
+ } = bt.create(from, msg).await.unwrap();
|
|
|
+ let sect_sz64 = entry.attr.sect_sz;
|
|
|
+ let sect_sz: usize = sect_sz64.try_into().unwrap();
|
|
|
+ let mut data = vec![1u8; sect_sz];
|
|
|
+ let msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ data: data.as_slice(),
|
|
|
};
|
|
|
- let ReadMetaReply { attrs, .. } = bt.read_meta(from, read_meta_msg).await.unwrap();
|
|
|
+ let WriteReply { written, .. } = bt.write(from, msg).await.unwrap();
|
|
|
+ assert_eq!(sect_sz64, written);
|
|
|
+ data.truncate(0);
|
|
|
+ data.extend(std::iter::repeat(2).take(sect_sz));
|
|
|
+ let msg = Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: sect_sz64,
|
|
|
+ data: data.as_slice(),
|
|
|
+ };
|
|
|
+ let WriteReply { written, .. } = bt.write(from, msg).await.unwrap();
|
|
|
+ assert_eq!(sect_sz64, written);
|
|
|
+ // The Accessor for this block should now have the second sector loaded, so it will have to
|
|
|
+ // seek back to the first in order to respond to this read request.
|
|
|
+ let msg = Read {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset: 0,
|
|
|
+ size: sect_sz64,
|
|
|
+ };
|
|
|
+ let guard = bt.read(from, msg).await.unwrap();
|
|
|
|
|
|
- assert_eq!([1u8; LEN], actual);
|
|
|
- assert_eq!(LEN as u64, attrs.size);
|
|
|
+ assert!(guard
|
|
|
+ .deref()
|
|
|
+ .iter()
|
|
|
+ .map(|e| *e)
|
|
|
+ .eq(std::iter::repeat(1u8).take(sect_sz)));
|
|
|
}
|
|
|
}
|