about summary refs log tree commit diff
path: root/tvix/store/src/tests/pathinfo.rs
diff options
context:
space:
mode:
authorFlorian Klink <flokli@flokli.de>2022-12-29T20·37+0100
committerflokli <flokli@flokli.de>2023-01-03T13·03+0000
commit0b56d9f21bb5a857ee17ecc539c173926441a3fb (patch)
treead7c5cb3f66f7a57b4e18c01df8a4b209d4cca0b /tvix/store/src/tests/pathinfo.rs
parentceb2c0ba895554c7cabb0ac20d3a80ea2aba1ab1 (diff)
feat(src/proto): add PathInfo.validate() r/5570
This provides validation of PathInfo messages, and ensures the output
hashes are properly parsed from the root node names.

NixPath already has a more extensive test suite for various wrong
NixPaths, so it's omitted from here.

Change-Id: I5d69118df5816daabb521ddb19d178bddd1caacf
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7684
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to '')
-rw-r--r--tvix/store/src/tests/pathinfo.rs206
1 files changed, 206 insertions, 0 deletions
diff --git a/tvix/store/src/tests/pathinfo.rs b/tvix/store/src/tests/pathinfo.rs
new file mode 100644
index 0000000000..8f4e9d3990
--- /dev/null
+++ b/tvix/store/src/tests/pathinfo.rs
@@ -0,0 +1,206 @@
+use crate::{
+    nixpath::{NixPath, ParseNixPathError},
+    proto::{self, Node, PathInfo, ValidatePathInfoError},
+};
+use lazy_static::lazy_static;
+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<NixPath, 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(NixPath::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(),
+        ParseNixPathError::InvalidName("".to_string())
+    ));
+    "invalid node name"
+)]
+fn validate_directory(
+    t_directory_node: proto::DirectoryNode,
+    t_result: Result<NixPath, 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(NixPath::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(),
+        ParseNixPathError::InvalidName("".to_string())
+    ));
+    "invalid node name"
+)]
+fn validate_file(t_file_node: proto::FileNode, t_result: Result<NixPath, 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(NixPath::from_string(DUMMY_NAME).expect("must succeed"));
+    "ok"
+)]
+#[test_case(
+    proto::SymlinkNode {
+        name: "invalid".to_string(),
+        ..Default::default()
+    },
+    Err(ValidatePathInfoError::InvalidNodeName(
+        "invalid".to_string(),
+        ParseNixPathError::InvalidName("".to_string())
+    ));
+    "invalid node name"
+)]
+fn validate_symlink(
+    t_symlink_node: proto::SymlinkNode,
+    t_result: Result<NixPath, 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());
+}