- DaemonBackend::put/get now round-trip the FULL record envelope (header+body) verbatim via rawput/rawget instead of stripping to a bare body. Before this, a socket-backed mount wrote the bare body but get returned it as if it were a record, breaking the FUSE read-back path (get_record could not decode it). This diverged from the in-memory backend and silently corrupted reads. - Cargo fmt --check now passes (was failing; the committed tree was never a clean ./check, which is why the durable mount could regress undetected). - Fix two new clippy lints (manual_is_multiple_of) in cubefs/backend.rs and cubesys/commands.rs so the -D warnings gate is green. - Daemon-backed integration tests (cubefs_daemon_smoke, daemon_backend_smoke) now use the real CubeStore<DaemonBackend> record path and are #[ignore]d so the default gate (no daemon) stays green, while ./check daemon spins up a live cube-server and runs them via --ignored. This makes the durable-socket contract an actual enforced test, not a manual ad-hoc script.
64 lines
2.8 KiB
Rust
64 lines
2.8 KiB
Rust
// Daemon-backed integration test for CubeFs<DaemonBackend> against a live
|
|
// cube-server. Proves a record written through the SAME path the FUSE mount
|
|
// uses (CubeStore::put_record -> DaemonBackend::put -> rawput) is readable
|
|
// back through a second CubeStore<DaemonBackend> (the FUSE read path,
|
|
// CubeStore::get_record -> DaemonBackend::get -> rawget), byte-for-byte.
|
|
//
|
|
// Requires a live cube-server at CUBE_SOCK. Marked `#[ignore]` so the default
|
|
// gate (no daemon) stays green; `./check daemon` spins up a daemon and runs it
|
|
// via `--ignored`.
|
|
// Run manually:
|
|
// CUBE_SOCK=<sock> cargo test --test cubefs_daemon_smoke -- --ignored --nocapture
|
|
use cubecoords::Czyx;
|
|
use cubefs::{CubeFs, DaemonBackend};
|
|
use cubestore::{CubeBackend, CubeStore};
|
|
|
|
#[test]
|
|
#[ignore = "requires a live cube-server; run via `./check daemon`"]
|
|
fn cubefs_create_write_reaches_daemon() {
|
|
let sock = std::env::var("CUBE_SOCK").expect("set CUBE_SOCK to a live cube-server socket");
|
|
let mut fs = CubeFs::new(CubeStore::new(DaemonBackend::new(sock.clone())));
|
|
fs.format("cube0");
|
|
let path = "/c011/z007/y003/x009";
|
|
fs.create(path, 0, 0, 0o644).expect("create");
|
|
fs.write(path, 0, b"fuse-proof-XYZ", 0, 0).expect("write");
|
|
|
|
// Ask the daemon directly via a SECOND CubeStore (the FUSE read path),
|
|
// which calls CubeStore::get_record -> DaemonBackend::get (rawget). The
|
|
// daemon must return the full record envelope, which get_record splits.
|
|
let probe = CubeStore::new(DaemonBackend::new(sock));
|
|
let k = Czyx::new(11, 7, 3, 9);
|
|
let (_, body) = probe
|
|
.get_record(&k)
|
|
.expect("record must be present in daemon store");
|
|
println!("daemon-side get_record(11,7,3,9) body => {:?}", body);
|
|
assert_eq!(
|
|
body.as_slice(),
|
|
b"fuse-proof-XYZ",
|
|
"CubeFs write must reach daemon store"
|
|
);
|
|
}
|
|
|
|
// Keep a direct raw-level check too, mirroring DaemonBackend::put/get semantics
|
|
// (full-envelope round-trip, NOT bare-body).
|
|
#[test]
|
|
#[ignore = "requires a live cube-server; run via `./check daemon`"]
|
|
fn daemon_backend_envelope_roundtrip() {
|
|
let sock = std::env::var("CUBE_SOCK").expect("set CUBE_SOCK to a live cube-server socket");
|
|
let mut b = DaemonBackend::new(sock);
|
|
let k = Czyx::new(9, 2, 2, 1);
|
|
// `put` receives the full envelope a CubeStore::put_record would emit
|
|
// (header length word + header bytes + body). We use a zero-length header
|
|
// here; the point is the envelope must survive the round-trip intact.
|
|
let mut env = Vec::new();
|
|
env.extend_from_slice(&(0u32).to_le_bytes());
|
|
env.extend_from_slice(b"fuse-persist-proof");
|
|
b.put(k, env.clone());
|
|
let got = b.get(&k).expect("envelope must round-trip");
|
|
println!("DaemonBackend::get(9,2,2,1) => {} bytes", got.len());
|
|
assert_eq!(
|
|
got, env,
|
|
"daemon backend put/get must preserve the full envelope"
|
|
);
|
|
}
|