From d45d6de561c23b2bac23e9290816846e6a248905 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Thu, 5 Oct 2023 11:57:05 +0300 Subject: test(tvix/store/pathinfo): add more tests for references This should cover all error cases produced. Change-Id: If31816d9b087551d86d7913df55df8f9f44bb554 Reviewed-on: https://cl.tvl.fyi/c/depot/+/9546 Autosubmit: flokli Reviewed-by: edef Tested-by: BuildkiteCI --- tvix/store/src/proto/tests/pathinfo.rs | 114 +++++++++++++++++++++------------ tvix/store/src/tests/fixtures.rs | 29 +++++++++ 2 files changed, 101 insertions(+), 42 deletions(-) (limited to 'tvix') diff --git a/tvix/store/src/proto/tests/pathinfo.rs b/tvix/store/src/proto/tests/pathinfo.rs index 3a9ce2e7e3..43a94e0d46 100644 --- a/tvix/store/src/proto/tests/pathinfo.rs +++ b/tvix/store/src/proto/tests/pathinfo.rs @@ -1,4 +1,4 @@ -use crate::proto::{NarInfo, PathInfo, ValidatePathInfoError}; +use crate::proto::{PathInfo, ValidatePathInfoError}; use crate::tests::fixtures::*; use bytes::Bytes; use nix_compat::store_path::{self, StorePath}; @@ -150,49 +150,79 @@ fn validate_symlink( assert_eq!(t_result, p.validate()); } +/// Ensure parsing a correct PathInfo without narinfo populated succeeds. #[test] -fn validate_references() { - // create a PathInfo without narinfo field. - let path_info = PathInfo { - node: Some(castorepb::Node { - node: Some(castorepb::node::Node::Directory(castorepb::DirectoryNode { - name: DUMMY_NAME.into(), - digest: DUMMY_DIGEST.clone().into(), - size: 0, - })), - }), - references: vec![DUMMY_OUTPUT_HASH.clone().into()], - 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(NarInfo { - nar_size: 0, - nar_sha256: DUMMY_DIGEST.clone().into(), - 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"), +fn validate_references_without_narinfo_ok() { + assert!(PATH_INFO_WITHOUT_NARINFO.validate().is_ok()); +} + +/// Ensure parsing a correct PathInfo with narinfo populated succeeds. +#[test] +fn validate_references_with_narinfo_ok() { + assert!(PATH_INFO_WITH_NARINFO.validate().is_ok()); +} + +/// Create a PathInfo with a wrong count of narinfo.reference_names, +/// and ensure validation fails. +#[test] +fn validate_inconsistent_num_refs_fail() { + let mut path_info = PATH_INFO_WITH_NARINFO.clone(); + path_info.narinfo.as_mut().unwrap().reference_names = vec![]; + + match path_info.validate().expect_err("must_fail") { + ValidatePathInfoError::InconsistentNumberOfReferences(1, 0) => {} + e => panic!("unexpected error: {:?}", e), }; +} - // create a pathinfo with the correct number of references, should suceed - let path_info_with_narinfo = PathInfo { - narinfo: Some(NarInfo { - nar_size: 0, - nar_sha256: DUMMY_DIGEST.clone().into(), - signatures: vec![], - reference_names: vec![DUMMY_NAME.to_string()], - }), - ..path_info +/// Create a PathInfo with a wrong digest length in references. +#[test] +fn validate_invalid_reference_digest_len() { + let mut path_info = PATH_INFO_WITHOUT_NARINFO.clone(); + path_info.references.push(vec![0xff, 0xff].into()); + + match path_info.validate().expect_err("must fail") { + ValidatePathInfoError::InvalidReferenceDigestLen( + 1, // position + 2, // unexpected digest len + ) => {} + e => panic!("unexpected error: {:?}", e), }; - assert!(path_info_with_narinfo.validate().is_ok()); +} + +/// Create a PathInfo with a narinfo.reference_name[1] that is no valid store path. +#[test] +fn validate_invalid_narinfo_reference_name() { + let mut path_info = PATH_INFO_WITH_NARINFO.clone(); + + // This is invalid, as the store prefix is not part of reference_names. + path_info.narinfo.as_mut().unwrap().reference_names[0] = + "/nix/store/00000000000000000000000000000000-dummy".to_string(); + + match path_info.validate().expect_err("must fail") { + ValidatePathInfoError::InvalidNarinfoReferenceName(0, reference_name) => { + assert_eq!( + "/nix/store/00000000000000000000000000000000-dummy", + reference_name + ); + } + e => panic!("unexpected error: {:?}", e), + } +} + +/// Create a PathInfo with a narinfo.reference_name[0] that doesn't match references[0]. +#[test] +fn validate_inconsistent_narinfo_reference_name_digest() { + let mut path_info = PATH_INFO_WITH_NARINFO.clone(); + + // mutate the first reference, they were all zeroes before + path_info.references[0] = vec![0xff; store_path::DIGEST_SIZE].into(); + + match path_info.validate().expect_err("must fail") { + ValidatePathInfoError::InconsistentNarinfoReferenceNameDigest(0, e_expected, e_actual) => { + assert_eq!(path_info.references[0][..], e_expected); + assert_eq!(DUMMY_OUTPUT_HASH[..], e_actual); + } + e => panic!("unexpected error: {:?}", e), + } } diff --git a/tvix/store/src/tests/fixtures.rs b/tvix/store/src/tests/fixtures.rs index 4d820af157..5ff37a5084 100644 --- a/tvix/store/src/tests/fixtures.rs +++ b/tvix/store/src/tests/fixtures.rs @@ -1,5 +1,8 @@ use lazy_static::lazy_static; pub use tvix_castore::fixtures::*; +use tvix_castore::proto as castorepb; + +use crate::proto::{NarInfo, PathInfo}; pub const DUMMY_NAME: &str = "00000000000000000000000000000000-dummy"; @@ -94,4 +97,30 @@ lazy_static! { 1, 0, 0, 0, 0, 0, 0, 0, b')', 0, 0, 0, 0, 0, 0, 0, // ")" 1, 0, 0, 0, 0, 0, 0, 0, b')', 0, 0, 0, 0, 0, 0, 0, // ")" ]; + + /// A PathInfo message without .narinfo populated. + pub static ref PATH_INFO_WITHOUT_NARINFO : PathInfo = PathInfo { + node: Some(castorepb::Node { + node: Some(castorepb::node::Node::Directory(castorepb::DirectoryNode { + name: DUMMY_NAME.into(), + digest: DUMMY_DIGEST.clone().into(), + size: 0, + })), + }), + references: vec![DUMMY_OUTPUT_HASH.clone().into()], + narinfo: None, + }; + + /// A PathInfo message with .narinfo populated. + /// The references in `narinfo.reference_names` aligns with what's in + /// `references`. + pub static ref PATH_INFO_WITH_NARINFO : PathInfo = PathInfo { + narinfo: Some(NarInfo { + nar_size: 0, + nar_sha256: DUMMY_DIGEST.clone().into(), + signatures: vec![], + reference_names: vec![DUMMY_NAME.to_string()], + }), + ..PATH_INFO_WITHOUT_NARINFO.clone() + }; } -- cgit 1.4.1