chore(tvix/store): move protos into separate mod.rs
This allows adding more stuff into this namespace, from different files. Also move tests on proto-related code from src/tests to src/proto/tests. Change-Id: I49e066fce90efbc18e16d68f94497b32ed5625c0 Reviewed-on: https://cl.tvl.fyi/c/depot/+/8091 Reviewed-by: tazjin <tazjin@tvl.su> Reviewed-by: raitobezarius <tvl@lahfa.xyz> Tested-by: BuildkiteCI
This commit is contained in:
parent
60abca1d8e
commit
80f68bf828
6 changed files with 6 additions and 3 deletions
|
|
@ -1,285 +0,0 @@
|
|||
use crate::proto::{Directory, DirectoryNode, FileNode, SymlinkNode, ValidateDirectoryError};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
static ref DUMMY_DIGEST: Vec<u8> = vec![
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
];
|
||||
}
|
||||
#[test]
|
||||
fn size() {
|
||||
{
|
||||
let d = Directory::default();
|
||||
assert_eq!(d.size(), 0);
|
||||
}
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![DirectoryNode {
|
||||
name: String::from("foo"),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 0,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(d.size(), 1);
|
||||
}
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![DirectoryNode {
|
||||
name: String::from("foo"),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 4,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(d.size(), 5);
|
||||
}
|
||||
{
|
||||
let d = Directory {
|
||||
files: vec![FileNode {
|
||||
name: String::from("foo"),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
executable: false,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(d.size(), 1);
|
||||
}
|
||||
{
|
||||
let d = Directory {
|
||||
symlinks: vec![SymlinkNode {
|
||||
name: String::from("foo"),
|
||||
target: String::from("bar"),
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(d.size(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn digest() {
|
||||
let d = Directory::default();
|
||||
|
||||
assert_eq!(
|
||||
d.digest(),
|
||||
vec![
|
||||
0xaf, 0x13, 0x49, 0xb9, 0xf5, 0xf9, 0xa1, 0xa6, 0xa0, 0x40, 0x4d, 0xea, 0x36, 0xdc,
|
||||
0xc9, 0x49, 0x9b, 0xcb, 0x25, 0xc9, 0xad, 0xc1, 0x12, 0xb7, 0xcc, 0x9a, 0x93, 0xca,
|
||||
0xe4, 0x1f, 0x32, 0x62
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_empty() {
|
||||
let d = Directory::default();
|
||||
assert_eq!(d.validate(), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_invalid_names() {
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![DirectoryNode {
|
||||
name: "".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::InvalidName(n) => {
|
||||
assert_eq!(n, "")
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![DirectoryNode {
|
||||
name: ".".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::InvalidName(n) => {
|
||||
assert_eq!(n, ".")
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
let d = Directory {
|
||||
files: vec![FileNode {
|
||||
name: "..".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
executable: false,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::InvalidName(n) => {
|
||||
assert_eq!(n, "..")
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
let d = Directory {
|
||||
symlinks: vec![SymlinkNode {
|
||||
name: "\x00".to_string(),
|
||||
target: "foo".to_string(),
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::InvalidName(n) => {
|
||||
assert_eq!(n, "\x00")
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
let d = Directory {
|
||||
symlinks: vec![SymlinkNode {
|
||||
name: "foo/bar".to_string(),
|
||||
target: "foo".to_string(),
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::InvalidName(n) => {
|
||||
assert_eq!(n, "foo/bar")
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_invalid_digest() {
|
||||
let d = Directory {
|
||||
directories: vec![DirectoryNode {
|
||||
name: "foo".to_string(),
|
||||
digest: vec![0x00, 0x42], // invalid length
|
||||
size: 42,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::InvalidDigestLen(n) => {
|
||||
assert_eq!(n, 2)
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_sorting() {
|
||||
// "b" comes before "a", bad.
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![
|
||||
DirectoryNode {
|
||||
name: "b".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
DirectoryNode {
|
||||
name: "a".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::WrongSorting(s) => {
|
||||
assert_eq!(s, "a".to_string());
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
}
|
||||
}
|
||||
|
||||
// "a" exists twice, bad.
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![
|
||||
DirectoryNode {
|
||||
name: "a".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
DirectoryNode {
|
||||
name: "a".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
match d.validate().expect_err("must fail") {
|
||||
ValidateDirectoryError::DuplicateName(s) => {
|
||||
assert_eq!(s, "a".to_string());
|
||||
}
|
||||
_ => panic!("unexpected error"),
|
||||
}
|
||||
}
|
||||
|
||||
// "a" comes before "b", all good.
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![
|
||||
DirectoryNode {
|
||||
name: "a".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
DirectoryNode {
|
||||
name: "b".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
d.validate().expect("validate shouldn't error");
|
||||
}
|
||||
|
||||
// [b, c] and [a] are both properly sorted.
|
||||
{
|
||||
let d = Directory {
|
||||
directories: vec![
|
||||
DirectoryNode {
|
||||
name: "b".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
DirectoryNode {
|
||||
name: "c".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 42,
|
||||
},
|
||||
],
|
||||
symlinks: vec![SymlinkNode {
|
||||
name: "a".to_string(),
|
||||
target: "foo".to_string(),
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
d.validate().expect("validate shouldn't error");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
use crate::proto::node::Node;
|
||||
use crate::proto::Directory;
|
||||
use crate::proto::DirectoryNode;
|
||||
use crate::proto::FileNode;
|
||||
use crate::proto::SymlinkNode;
|
||||
|
||||
#[test]
|
||||
fn iterator() -> anyhow::Result<()> {
|
||||
let d = Directory {
|
||||
directories: vec![
|
||||
DirectoryNode {
|
||||
name: "c".to_string(),
|
||||
..DirectoryNode::default()
|
||||
},
|
||||
DirectoryNode {
|
||||
name: "d".to_string(),
|
||||
..DirectoryNode::default()
|
||||
},
|
||||
DirectoryNode {
|
||||
name: "h".to_string(),
|
||||
..DirectoryNode::default()
|
||||
},
|
||||
DirectoryNode {
|
||||
name: "l".to_string(),
|
||||
..DirectoryNode::default()
|
||||
},
|
||||
],
|
||||
files: vec![
|
||||
FileNode {
|
||||
name: "b".to_string(),
|
||||
..FileNode::default()
|
||||
},
|
||||
FileNode {
|
||||
name: "e".to_string(),
|
||||
..FileNode::default()
|
||||
},
|
||||
FileNode {
|
||||
name: "g".to_string(),
|
||||
..FileNode::default()
|
||||
},
|
||||
FileNode {
|
||||
name: "j".to_string(),
|
||||
..FileNode::default()
|
||||
},
|
||||
],
|
||||
symlinks: vec![
|
||||
SymlinkNode {
|
||||
name: "a".to_string(),
|
||||
..SymlinkNode::default()
|
||||
},
|
||||
SymlinkNode {
|
||||
name: "f".to_string(),
|
||||
..SymlinkNode::default()
|
||||
},
|
||||
SymlinkNode {
|
||||
name: "i".to_string(),
|
||||
..SymlinkNode::default()
|
||||
},
|
||||
SymlinkNode {
|
||||
name: "k".to_string(),
|
||||
..SymlinkNode::default()
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let mut node_names: Vec<String> = vec![];
|
||||
|
||||
for node in d.nodes() {
|
||||
match node {
|
||||
Node::Directory(n) => node_names.push(n.name),
|
||||
Node::File(n) => node_names.push(n.name),
|
||||
Node::Symlink(n) => node_names.push(n.name),
|
||||
};
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"],
|
||||
node_names
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
mod directory;
|
||||
mod directory_nodes_iterator;
|
||||
mod directory_service;
|
||||
mod nar;
|
||||
mod path_info_service;
|
||||
mod pathinfo;
|
||||
|
|
|
|||
|
|
@ -1,207 +0,0 @@
|
|||
use crate::proto::{self, Node, PathInfo, ValidatePathInfoError};
|
||||
use lazy_static::lazy_static;
|
||||
use nix_compat::store_path::{ParseStorePathError, StorePath};
|
||||
use test_case::test_case;
|
||||
|
||||
lazy_static! {
|
||||
static ref DUMMY_DIGEST: Vec<u8> = vec![
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
];
|
||||
static ref DUMMY_DIGEST_2: Vec<u8> = vec![
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
];
|
||||
}
|
||||
|
||||
const DUMMY_NAME: &str = "00000000000000000000000000000000-dummy";
|
||||
|
||||
#[test_case(
|
||||
None,
|
||||
Err(ValidatePathInfoError::NoNodePresent()) ;
|
||||
"No node"
|
||||
)]
|
||||
#[test_case(
|
||||
Some(Node { node: None }),
|
||||
Err(ValidatePathInfoError::NoNodePresent());
|
||||
"No node 2"
|
||||
)]
|
||||
fn validate_no_node(
|
||||
t_node: Option<proto::Node>,
|
||||
t_result: Result<StorePath, ValidatePathInfoError>,
|
||||
) {
|
||||
// construct the PathInfo object
|
||||
let p = PathInfo {
|
||||
node: t_node,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(t_result, p.validate());
|
||||
}
|
||||
|
||||
#[test_case(
|
||||
proto::DirectoryNode {
|
||||
name: DUMMY_NAME.to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 0,
|
||||
},
|
||||
Ok(StorePath::from_string(DUMMY_NAME).expect("must succeed"));
|
||||
"ok"
|
||||
)]
|
||||
#[test_case(
|
||||
proto::DirectoryNode {
|
||||
name: DUMMY_NAME.to_string(),
|
||||
digest: vec![],
|
||||
size: 0,
|
||||
},
|
||||
Err(ValidatePathInfoError::InvalidDigestLen(0));
|
||||
"invalid digest length"
|
||||
)]
|
||||
#[test_case(
|
||||
proto::DirectoryNode {
|
||||
name: "invalid".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 0,
|
||||
},
|
||||
Err(ValidatePathInfoError::InvalidNodeName(
|
||||
"invalid".to_string(),
|
||||
ParseStorePathError::InvalidName("".to_string())
|
||||
));
|
||||
"invalid node name"
|
||||
)]
|
||||
fn validate_directory(
|
||||
t_directory_node: proto::DirectoryNode,
|
||||
t_result: Result<StorePath, ValidatePathInfoError>,
|
||||
) {
|
||||
// construct the PathInfo object
|
||||
let p = PathInfo {
|
||||
node: Some(Node {
|
||||
node: Some(proto::node::Node::Directory(t_directory_node)),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(t_result, p.validate());
|
||||
}
|
||||
|
||||
#[test_case(
|
||||
proto::FileNode {
|
||||
name: DUMMY_NAME.to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 0,
|
||||
executable: false,
|
||||
},
|
||||
Ok(StorePath::from_string(DUMMY_NAME).expect("must succeed"));
|
||||
"ok"
|
||||
)]
|
||||
#[test_case(
|
||||
proto::FileNode {
|
||||
name: DUMMY_NAME.to_string(),
|
||||
digest: vec![],
|
||||
..Default::default()
|
||||
},
|
||||
Err(ValidatePathInfoError::InvalidDigestLen(0));
|
||||
"invalid digest length"
|
||||
)]
|
||||
#[test_case(
|
||||
proto::FileNode {
|
||||
name: "invalid".to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
..Default::default()
|
||||
},
|
||||
Err(ValidatePathInfoError::InvalidNodeName(
|
||||
"invalid".to_string(),
|
||||
ParseStorePathError::InvalidName("".to_string())
|
||||
));
|
||||
"invalid node name"
|
||||
)]
|
||||
fn validate_file(t_file_node: proto::FileNode, t_result: Result<StorePath, ValidatePathInfoError>) {
|
||||
// construct the PathInfo object
|
||||
let p = PathInfo {
|
||||
node: Some(Node {
|
||||
node: Some(proto::node::Node::File(t_file_node)),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(t_result, p.validate());
|
||||
}
|
||||
|
||||
#[test_case(
|
||||
proto::SymlinkNode {
|
||||
name: DUMMY_NAME.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
Ok(StorePath::from_string(DUMMY_NAME).expect("must succeed"));
|
||||
"ok"
|
||||
)]
|
||||
#[test_case(
|
||||
proto::SymlinkNode {
|
||||
name: "invalid".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
Err(ValidatePathInfoError::InvalidNodeName(
|
||||
"invalid".to_string(),
|
||||
ParseStorePathError::InvalidName("".to_string())
|
||||
));
|
||||
"invalid node name"
|
||||
)]
|
||||
fn validate_symlink(
|
||||
t_symlink_node: proto::SymlinkNode,
|
||||
t_result: Result<StorePath, ValidatePathInfoError>,
|
||||
) {
|
||||
// construct the PathInfo object
|
||||
let p = PathInfo {
|
||||
node: Some(Node {
|
||||
node: Some(proto::node::Node::Symlink(t_symlink_node)),
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(t_result, p.validate());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_references() {
|
||||
// create a PathInfo without narinfo field.
|
||||
let path_info = PathInfo {
|
||||
node: Some(Node {
|
||||
node: Some(proto::node::Node::Directory(proto::DirectoryNode {
|
||||
name: DUMMY_NAME.to_string(),
|
||||
digest: DUMMY_DIGEST.to_vec(),
|
||||
size: 0,
|
||||
})),
|
||||
}),
|
||||
references: vec![DUMMY_DIGEST_2.to_vec()],
|
||||
narinfo: None,
|
||||
};
|
||||
assert!(path_info.validate().is_ok());
|
||||
|
||||
// create a PathInfo with a narinfo field, but an inconsistent set of references
|
||||
let path_info_with_narinfo_missing_refs = PathInfo {
|
||||
narinfo: Some(proto::NarInfo {
|
||||
nar_size: 0,
|
||||
nar_sha256: DUMMY_DIGEST.to_vec(),
|
||||
signatures: vec![],
|
||||
reference_names: vec![],
|
||||
}),
|
||||
..path_info.clone()
|
||||
};
|
||||
match path_info_with_narinfo_missing_refs
|
||||
.validate()
|
||||
.expect_err("must_fail")
|
||||
{
|
||||
ValidatePathInfoError::InconsistentNumberOfReferences(_, _) => {}
|
||||
_ => panic!("unexpected error"),
|
||||
};
|
||||
|
||||
// create a pathinfo with the correct number of references, should suceed
|
||||
let path_info_with_narinfo = PathInfo {
|
||||
narinfo: Some(proto::NarInfo {
|
||||
nar_size: 0,
|
||||
nar_sha256: DUMMY_DIGEST.to_vec(),
|
||||
signatures: vec![],
|
||||
reference_names: vec![format!("/nix/store/{}", DUMMY_NAME)],
|
||||
}),
|
||||
..path_info.clone()
|
||||
};
|
||||
assert!(path_info_with_narinfo.validate().is_ok());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue