chore(tvix/nix-compat): basic daemon handler tests
This change adds tests for basic request/response handling as per nix daemon STDERR_* protocol. Change-Id: Ia6a1904e14955551b11f776b6ccb595fa8984513 Reviewed-on: https://cl.tvl.fyi/c/depot/+/12852 Tested-by: BuildkiteCI Reviewed-by: flokli <flokli@flokli.de> Autosubmit: Vladimir Kryachko <v.kryachko@gmail.com>
This commit is contained in:
parent
8d4a0ac008
commit
88d51c9c16
5 changed files with 361 additions and 32 deletions
71
tvix/Cargo.lock
generated
71
tvix/Cargo.lock
generated
|
@ -1045,6 +1045,12 @@ dependencies = [
|
|||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "2.2.3"
|
||||
|
@ -1248,6 +1254,12 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fragile"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||
|
||||
[[package]]
|
||||
name = "fuse-backend-rs"
|
||||
version = "0.12.0"
|
||||
|
@ -2174,6 +2186,32 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockall"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"downcast",
|
||||
"fragile",
|
||||
"mockall_derive",
|
||||
"predicates",
|
||||
"predicates-tree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockall_derive"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
|
@ -2290,6 +2328,7 @@ dependencies = [
|
|||
"glob",
|
||||
"hex-literal",
|
||||
"mimalloc",
|
||||
"mockall",
|
||||
"nix-compat-derive",
|
||||
"nom",
|
||||
"num-traits",
|
||||
|
@ -2792,6 +2831,32 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "3.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"predicates-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.1"
|
||||
|
@ -3931,6 +3996,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termtree"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
|
||||
|
||||
[[package]]
|
||||
name = "test-strategy"
|
||||
version = "0.2.1"
|
||||
|
|
165
tvix/Cargo.nix
165
tvix/Cargo.nix
|
@ -3332,6 +3332,19 @@ rec {
|
|||
features = { };
|
||||
resolvedDefaultFeatures = [ "default" ];
|
||||
};
|
||||
"downcast" = rec {
|
||||
crateName = "downcast";
|
||||
version = "0.11.0";
|
||||
edition = "2018";
|
||||
sha256 = "1wa78ahlc57wmqyq2ncr80l7plrkgz57xsg7kfzgpcnqac8gld8l";
|
||||
authors = [
|
||||
"Felix Köpge <fkoep@mailbox.org>"
|
||||
];
|
||||
features = {
|
||||
"default" = [ "std" ];
|
||||
};
|
||||
resolvedDefaultFeatures = [ "default" "std" ];
|
||||
};
|
||||
"ed25519" = rec {
|
||||
crateName = "ed25519";
|
||||
version = "2.2.3";
|
||||
|
@ -3930,6 +3943,18 @@ rec {
|
|||
};
|
||||
resolvedDefaultFeatures = [ "alloc" "default" "std" ];
|
||||
};
|
||||
"fragile" = rec {
|
||||
crateName = "fragile";
|
||||
version = "2.0.0";
|
||||
edition = "2018";
|
||||
sha256 = "1ajfdnwdn921bhjlzyvsqvdgci8ab40ln6w9ly422lf8svb428bc";
|
||||
authors = [
|
||||
"Armin Ronacher <armin.ronacher@active-4.com>"
|
||||
];
|
||||
features = {
|
||||
"slab" = [ "dep:slab" ];
|
||||
};
|
||||
};
|
||||
"fuse-backend-rs" = rec {
|
||||
crateName = "fuse-backend-rs";
|
||||
version = "0.12.0";
|
||||
|
@ -6794,6 +6819,77 @@ rec {
|
|||
};
|
||||
resolvedDefaultFeatures = [ "net" "os-ext" "os-poll" ];
|
||||
};
|
||||
"mockall" = rec {
|
||||
crateName = "mockall";
|
||||
version = "0.13.1";
|
||||
edition = "2021";
|
||||
sha256 = "1lir70dd9cnsjlf20gi3i51ha9n7mlrkx74bx5gfszlcdk6bz9ir";
|
||||
authors = [
|
||||
"Alan Somers <asomers@gmail.com>"
|
||||
];
|
||||
dependencies = [
|
||||
{
|
||||
name = "cfg-if";
|
||||
packageId = "cfg-if";
|
||||
}
|
||||
{
|
||||
name = "downcast";
|
||||
packageId = "downcast";
|
||||
}
|
||||
{
|
||||
name = "fragile";
|
||||
packageId = "fragile";
|
||||
}
|
||||
{
|
||||
name = "mockall_derive";
|
||||
packageId = "mockall_derive";
|
||||
}
|
||||
{
|
||||
name = "predicates";
|
||||
packageId = "predicates";
|
||||
usesDefaultFeatures = false;
|
||||
}
|
||||
{
|
||||
name = "predicates-tree";
|
||||
packageId = "predicates-tree";
|
||||
}
|
||||
];
|
||||
features = {
|
||||
"nightly" = [ "mockall_derive/nightly_derive" "downcast/nightly" ];
|
||||
};
|
||||
};
|
||||
"mockall_derive" = rec {
|
||||
crateName = "mockall_derive";
|
||||
version = "0.13.1";
|
||||
edition = "2021";
|
||||
sha256 = "1608qajqrz23xbvv81alc6wm4l24as1bsqg4shdh3sggq8231ji5";
|
||||
procMacro = true;
|
||||
authors = [
|
||||
"Alan Somers <asomers@gmail.com>"
|
||||
];
|
||||
dependencies = [
|
||||
{
|
||||
name = "cfg-if";
|
||||
packageId = "cfg-if";
|
||||
}
|
||||
{
|
||||
name = "proc-macro2";
|
||||
packageId = "proc-macro2";
|
||||
}
|
||||
{
|
||||
name = "quote";
|
||||
packageId = "quote";
|
||||
}
|
||||
{
|
||||
name = "syn";
|
||||
packageId = "syn 2.0.79";
|
||||
features = [ "extra-traits" "full" ];
|
||||
}
|
||||
];
|
||||
features = {
|
||||
"nightly_derive" = [ "proc-macro2/nightly" ];
|
||||
};
|
||||
};
|
||||
"multimap" = rec {
|
||||
crateName = "multimap";
|
||||
version = "0.10.0";
|
||||
|
@ -7295,6 +7391,10 @@ rec {
|
|||
name = "mimalloc";
|
||||
packageId = "mimalloc";
|
||||
}
|
||||
{
|
||||
name = "mockall";
|
||||
packageId = "mockall";
|
||||
}
|
||||
{
|
||||
name = "pretty_assertions";
|
||||
packageId = "pretty_assertions";
|
||||
|
@ -8891,6 +8991,64 @@ rec {
|
|||
};
|
||||
resolvedDefaultFeatures = [ "simd" "std" ];
|
||||
};
|
||||
"predicates" = rec {
|
||||
crateName = "predicates";
|
||||
version = "3.1.2";
|
||||
edition = "2021";
|
||||
sha256 = "15rcyjax4ykflw5425wsyzcfkgl08c9zsa8sdlsrmhj0fv68d43y";
|
||||
authors = [
|
||||
"Nick Stevens <nick@bitcurry.com>"
|
||||
];
|
||||
dependencies = [
|
||||
{
|
||||
name = "anstyle";
|
||||
packageId = "anstyle";
|
||||
}
|
||||
{
|
||||
name = "predicates-core";
|
||||
packageId = "predicates-core";
|
||||
}
|
||||
];
|
||||
features = {
|
||||
"default" = [ "diff" "regex" "float-cmp" "normalize-line-endings" "color" ];
|
||||
"diff" = [ "dep:difflib" ];
|
||||
"float-cmp" = [ "dep:float-cmp" ];
|
||||
"normalize-line-endings" = [ "dep:normalize-line-endings" ];
|
||||
"regex" = [ "dep:regex" ];
|
||||
};
|
||||
};
|
||||
"predicates-core" = rec {
|
||||
crateName = "predicates-core";
|
||||
version = "1.0.8";
|
||||
edition = "2021";
|
||||
sha256 = "0c8rl6d7qkcl773fw539h61fhlgdg7v9yswwb536hpg7x2z7g0df";
|
||||
libName = "predicates_core";
|
||||
authors = [
|
||||
"Nick Stevens <nick@bitcurry.com>"
|
||||
];
|
||||
|
||||
};
|
||||
"predicates-tree" = rec {
|
||||
crateName = "predicates-tree";
|
||||
version = "1.0.11";
|
||||
edition = "2021";
|
||||
sha256 = "04zv0i9pjfrldnvyxf4y07n243nvk3n4g03w2k6nccgdjp8l1ds1";
|
||||
libName = "predicates_tree";
|
||||
authors = [
|
||||
"Nick Stevens <nick@bitcurry.com>"
|
||||
];
|
||||
dependencies = [
|
||||
{
|
||||
name = "predicates-core";
|
||||
packageId = "predicates-core";
|
||||
}
|
||||
{
|
||||
name = "termtree";
|
||||
packageId = "termtree";
|
||||
}
|
||||
];
|
||||
|
||||
};
|
||||
"pretty_assertions" = rec {
|
||||
crateName = "pretty_assertions";
|
||||
version = "1.4.1";
|
||||
|
@ -12654,6 +12812,13 @@ rec {
|
|||
}
|
||||
];
|
||||
|
||||
};
|
||||
"termtree" = rec {
|
||||
crateName = "termtree";
|
||||
version = "0.4.1";
|
||||
edition = "2018";
|
||||
sha256 = "0xkal5l2r3r9p9j90x35qy4npbdwxz4gskvbijs6msymaangas9k";
|
||||
|
||||
};
|
||||
"test-strategy" = rec {
|
||||
crateName = "test-strategy";
|
||||
|
|
|
@ -47,6 +47,7 @@ criterion = { workspace = true, features = ["html_reports"] }
|
|||
futures = { workspace = true }
|
||||
hex-literal = { workspace = true }
|
||||
mimalloc = { workspace = true }
|
||||
mockall = "0.13.1"
|
||||
pretty_assertions = { workspace = true }
|
||||
proptest = { workspace = true, features = ["std", "alloc", "tempfile"] }
|
||||
rstest = { workspace = true }
|
||||
|
|
|
@ -254,45 +254,17 @@ where
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{io::Result, sync::Arc};
|
||||
use std::{io::ErrorKind, sync::Arc};
|
||||
|
||||
use mockall::predicate;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::{
|
||||
nix_daemon::types::UnkeyedValidPathInfo,
|
||||
nix_daemon::MockNixDaemonIO,
|
||||
wire::ProtocolVersion,
|
||||
worker_protocol::{ClientSettings, WORKER_MAGIC_1, WORKER_MAGIC_2},
|
||||
};
|
||||
|
||||
struct MockDaemonIO {}
|
||||
|
||||
impl NixDaemonIO for MockDaemonIO {
|
||||
async fn query_path_info(
|
||||
&self,
|
||||
_path: &crate::store_path::StorePath<String>,
|
||||
) -> Result<Option<UnkeyedValidPathInfo>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn query_path_from_hash_part(
|
||||
&self,
|
||||
_hash: &[u8],
|
||||
) -> Result<Option<UnkeyedValidPathInfo>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn add_to_store_nar<R>(
|
||||
&self,
|
||||
_request: crate::nix_daemon::types::AddToStoreNarRequest,
|
||||
_reader: &mut R,
|
||||
) -> Result<()>
|
||||
where
|
||||
R: tokio::io::AsyncRead + Send + Unpin,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_daemon_initialization() {
|
||||
let mut builder = tokio_test::io::Builder::new();
|
||||
|
@ -332,10 +304,125 @@ mod tests {
|
|||
.write(&[115, 116, 108, 97, 0, 0, 0, 0])
|
||||
.build();
|
||||
|
||||
let daemon = NixDaemon::initialize(Arc::new(MockDaemonIO {}), test_conn)
|
||||
let mock = MockNixDaemonIO::new();
|
||||
let daemon = NixDaemon::initialize(Arc::new(mock), test_conn)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(daemon.client_settings, ClientSettings::default());
|
||||
assert_eq!(daemon.protocol_version, ProtocolVersion::from_parts(1, 35));
|
||||
}
|
||||
|
||||
async fn serialize<T>(req: &T, protocol_version: ProtocolVersion) -> Vec<u8>
|
||||
where
|
||||
T: NixSerialize + Send,
|
||||
{
|
||||
let mut result: Vec<u8> = Vec::new();
|
||||
let mut w = NixWriter::builder()
|
||||
.set_version(protocol_version)
|
||||
.build(&mut result);
|
||||
w.write_value(req).await.unwrap();
|
||||
w.flush().await.unwrap();
|
||||
result
|
||||
}
|
||||
|
||||
async fn respond<T>(
|
||||
resp: &Result<T, std::io::Error>,
|
||||
protocol_version: ProtocolVersion,
|
||||
) -> Vec<u8>
|
||||
where
|
||||
T: NixSerialize + Send,
|
||||
{
|
||||
let mut result: Vec<u8> = Vec::new();
|
||||
let mut w = NixWriter::builder()
|
||||
.set_version(protocol_version)
|
||||
.build(&mut result);
|
||||
match resp {
|
||||
Ok(value) => {
|
||||
w.write_value(&STDERR_LAST).await.unwrap();
|
||||
w.write_value(value).await.unwrap();
|
||||
}
|
||||
Err(e) => {
|
||||
w.write_value(&STDERR_ERROR).await.unwrap();
|
||||
w.write_value(&NixError::new(format!("{:?}", e)))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
w.flush().await.unwrap();
|
||||
result
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_is_valid_path_ok() {
|
||||
let version = ProtocolVersion::from_parts(1, 37);
|
||||
let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
|
||||
let mut mock = MockNixDaemonIO::new();
|
||||
let (reader, writer) = split(io);
|
||||
let path: StorePath<String> = StorePath::<String>::from_absolute_path(
|
||||
"/nix/store/33l4p0pn0mybmqzaxfkpppyh7vx1c74p-hello-2.12.1".as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
mock.expect_is_valid_path()
|
||||
.with(predicate::eq(path.clone()))
|
||||
.times(1)
|
||||
.returning(|_| Box::pin(async { Ok(true) }));
|
||||
|
||||
handle.read(&Into::<u64>::into(Operation::IsValidPath).to_le_bytes());
|
||||
handle.read(&serialize(&path, version).await);
|
||||
handle.write(&respond(&Ok(true), version).await);
|
||||
drop(handle);
|
||||
|
||||
let mut daemon = NixDaemon::new(
|
||||
Arc::new(mock),
|
||||
version,
|
||||
ClientSettings::default(),
|
||||
NixReader::new(reader),
|
||||
NixWriter::new(writer),
|
||||
);
|
||||
assert_eq!(
|
||||
ErrorKind::UnexpectedEof,
|
||||
daemon
|
||||
.handle_client()
|
||||
.await
|
||||
.expect_err("Expecting eof")
|
||||
.kind()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_is_valid_path_err() {
|
||||
let version = ProtocolVersion::from_parts(1, 37);
|
||||
let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
|
||||
let mut mock = MockNixDaemonIO::new();
|
||||
let (reader, writer) = split(io);
|
||||
let path: StorePath<String> = StorePath::<String>::from_absolute_path(
|
||||
"/nix/store/33l4p0pn0mybmqzaxfkpppyh7vx1c74p-hello-2.12.1".as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
mock.expect_is_valid_path()
|
||||
.with(predicate::eq(path.clone()))
|
||||
.times(1)
|
||||
.returning(|_| Box::pin(async { Err(std::io::Error::other("hello")) }));
|
||||
|
||||
handle.read(&Into::<u64>::into(Operation::IsValidPath).to_le_bytes());
|
||||
handle.read(&serialize(&path, version).await);
|
||||
handle.write(&respond::<bool>(&Err(std::io::Error::other("hello")), version).await);
|
||||
drop(handle);
|
||||
|
||||
let mut daemon = NixDaemon::new(
|
||||
Arc::new(mock),
|
||||
version,
|
||||
ClientSettings::default(),
|
||||
NixReader::new(reader),
|
||||
NixWriter::new(writer),
|
||||
);
|
||||
assert_eq!(
|
||||
ErrorKind::UnexpectedEof,
|
||||
daemon
|
||||
.handle_client()
|
||||
.await
|
||||
.expect_err("Expecting eof")
|
||||
.kind()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,11 @@ pub mod framing;
|
|||
pub mod handler;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(test)]
|
||||
use mockall::automock;
|
||||
|
||||
/// Represents all possible operations over the nix-daemon protocol.
|
||||
#[cfg_attr(test, automock)]
|
||||
pub trait NixDaemonIO: Sync {
|
||||
fn is_valid_path(
|
||||
&self,
|
||||
|
@ -62,6 +66,7 @@ pub trait NixDaemonIO: Sync {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(test, mockall::concretize)]
|
||||
fn add_to_store_nar<R>(
|
||||
&self,
|
||||
request: AddToStoreNarRequest,
|
||||
|
|
Loading…
Reference in a new issue