feat(storage-server): add StorageServer<F: FileSystem> with BlockDevice trait, mock adapters, and tests
This commit is contained in:
2
crates/servers/storage-server/src/tests/mod.rs
Normal file
2
crates/servers/storage-server/src/tests/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
mod protocol;
|
||||
mod server;
|
||||
64
crates/servers/storage-server/src/tests/protocol.rs
Normal file
64
crates/servers/storage-server/src/tests/protocol.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use crate::filesystem::FileHandle;
|
||||
use crate::protocol::*;
|
||||
use server_framework::{Decode, Encode};
|
||||
|
||||
#[test]
|
||||
fn open_roundtrip() {
|
||||
let req = StorageRequest::Open { path_word0: 0x61626364, path_word1: 0 };
|
||||
assert_eq!(StorageRequest::decode(req.encode()), Some(req));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_roundtrip() {
|
||||
let req = StorageRequest::Read { handle: FileHandle::new(3), max_bytes: 512 };
|
||||
assert_eq!(StorageRequest::decode(req.encode()), Some(req));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_roundtrip() {
|
||||
let req = StorageRequest::Write { handle: FileHandle::new(1), data_word: 42 };
|
||||
assert_eq!(StorageRequest::decode(req.encode()), Some(req));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn close_roundtrip() {
|
||||
let req = StorageRequest::Close { handle: FileHandle::new(5) };
|
||||
assert_eq!(StorageRequest::decode(req.encode()), Some(req));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_size_roundtrip() {
|
||||
let req = StorageRequest::FileSize { handle: FileHandle::new(2) };
|
||||
assert_eq!(StorageRequest::decode(req.encode()), Some(req));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handle_response_roundtrip() {
|
||||
let resp = StorageResponse::Handle(FileHandle::new(7));
|
||||
assert_eq!(StorageResponse::decode(resp.encode()), Some(resp));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn data_response_roundtrip() {
|
||||
let resp = StorageResponse::Data { bytes_read: 256 };
|
||||
assert_eq!(StorageResponse::decode(resp.encode()), Some(resp));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_response_variants() {
|
||||
let variants = [
|
||||
StorageResponse::Ok,
|
||||
StorageResponse::NotFound,
|
||||
StorageResponse::Error,
|
||||
StorageResponse::Size(1024),
|
||||
StorageResponse::DirEntries { count: 3 },
|
||||
];
|
||||
for resp in variants {
|
||||
assert_eq!(StorageResponse::decode(resp.encode()), Some(resp));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_request_returns_none() {
|
||||
assert!(StorageRequest::decode([99, 0, 0, 0]).is_none());
|
||||
}
|
||||
95
crates/servers/storage-server/src/tests/server.rs
Normal file
95
crates/servers/storage-server/src/tests/server.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use crate::adapters::mock_fs::MockFileSystem;
|
||||
use crate::filesystem::FileHandle;
|
||||
use crate::protocol::*;
|
||||
use crate::server::StorageServer;
|
||||
use server_framework::Server;
|
||||
|
||||
fn test_server() -> StorageServer<MockFileSystem> {
|
||||
StorageServer::new(MockFileSystem::new())
|
||||
}
|
||||
|
||||
fn path_words(s: &[u8]) -> (usize, usize) {
|
||||
let mut w0 = [0u8; 8];
|
||||
let mut w1 = [0u8; 8];
|
||||
for (i, &b) in s.iter().enumerate() {
|
||||
if i < 8 { w0[i] = b; }
|
||||
else if i < 16 { w1[i - 8] = b; }
|
||||
}
|
||||
(usize::from_le_bytes(w0), usize::from_le_bytes(w1))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_and_open() {
|
||||
let mut server = test_server();
|
||||
let (w0, w1) = path_words(b"test.txt");
|
||||
|
||||
let resp = server.handle(StorageRequest::Create { path_word0: w0, path_word1: w1 });
|
||||
assert!(matches!(resp, StorageResponse::Handle(_)));
|
||||
|
||||
let resp = server.handle(StorageRequest::Open { path_word0: w0, path_word1: w1 });
|
||||
assert!(matches!(resp, StorageResponse::Handle(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_nonexistent_returns_not_found() {
|
||||
let mut server = test_server();
|
||||
let (w0, w1) = path_words(b"nope.txt");
|
||||
let resp = server.handle(StorageRequest::Open { path_word0: w0, path_word1: w1 });
|
||||
assert_eq!(resp, StorageResponse::NotFound);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_then_read() {
|
||||
let mut server = test_server();
|
||||
let (w0, w1) = path_words(b"data");
|
||||
|
||||
let handle = match server.handle(StorageRequest::Create { path_word0: w0, path_word1: w1 }) {
|
||||
StorageResponse::Handle(h) => h,
|
||||
_ => panic!("expected handle"),
|
||||
};
|
||||
|
||||
let resp = server.handle(StorageRequest::Write { handle, data_word: 0xDEADBEEF });
|
||||
assert!(matches!(resp, StorageResponse::Written { bytes_written: 8 }));
|
||||
|
||||
let resp = server.handle(StorageRequest::FileSize { handle });
|
||||
assert_eq!(resp, StorageResponse::Size(8));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_file() {
|
||||
let mut server = test_server();
|
||||
let (w0, w1) = path_words(b"del.txt");
|
||||
|
||||
server.handle(StorageRequest::Create { path_word0: w0, path_word1: w1 });
|
||||
let resp = server.handle(StorageRequest::Delete { path_word0: w0, path_word1: w1 });
|
||||
assert_eq!(resp, StorageResponse::Ok);
|
||||
|
||||
let resp = server.handle(StorageRequest::Open { path_word0: w0, path_word1: w1 });
|
||||
assert_eq!(resp, StorageResponse::NotFound);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_dir() {
|
||||
let mut server = test_server();
|
||||
let (w0a, w1a) = path_words(b"a.txt");
|
||||
let (w0b, w1b) = path_words(b"b.txt");
|
||||
|
||||
server.handle(StorageRequest::Create { path_word0: w0a, path_word1: w1a });
|
||||
server.handle(StorageRequest::Create { path_word0: w0b, path_word1: w1b });
|
||||
|
||||
let (w0r, w1r) = path_words(b"/");
|
||||
let resp = server.handle(StorageRequest::ListDir { path_word0: w0r, path_word1: w1r });
|
||||
assert_eq!(resp, StorageResponse::DirEntries { count: 2 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn close_succeeds() {
|
||||
let mut server = test_server();
|
||||
let (w0, w1) = path_words(b"c.txt");
|
||||
let handle = match server.handle(StorageRequest::Create { path_word0: w0, path_word1: w1 }) {
|
||||
StorageResponse::Handle(h) => h,
|
||||
_ => panic!("expected handle"),
|
||||
};
|
||||
let resp = server.handle(StorageRequest::Close { handle });
|
||||
assert_eq!(resp, StorageResponse::Ok);
|
||||
}
|
||||
Reference in New Issue
Block a user