about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/derivation/src/tests/mod.rs157
1 files changed, 156 insertions, 1 deletions
diff --git a/tvix/derivation/src/tests/mod.rs b/tvix/derivation/src/tests/mod.rs
index dbba6e521511..700a25860571 100644
--- a/tvix/derivation/src/tests/mod.rs
+++ b/tvix/derivation/src/tests/mod.rs
@@ -1,5 +1,6 @@
 use crate::derivation::Derivation;
-use crate::output::Output;
+use crate::output::{Hash, Output};
+use std::collections::BTreeMap;
 use std::fs::File;
 use std::io::Read;
 use std::path::Path;
@@ -160,3 +161,157 @@ fn output_paths(name: &str, drv_path: &str) {
     // The derivation should now look like it was before
     assert_eq!(expected_derivation, derivation);
 }
+
+/// Exercises the output path calculation functions like a constructing client
+/// (an implementation of builtins.derivation) would do:
+///
+/// ```nix
+/// rec {
+///   bar = builtins.derivation {
+///     name = "bar";
+///     builder = ":";
+///     system = ":";
+///     outputHash = "08813cbee9903c62be4c5027726a418a300da4500b2d369d3af9286f4815ceba";
+///     outputHashAlgo = "sha256";
+///     outputHashMode = "recursive";
+///   };
+///
+///   foo = builtins.derivation {
+///     name = "foo";
+///     builder = ":";
+///     system = ":";
+///     inherit bar;
+///   };
+/// }
+/// ```
+/// It first assembles the bar derivation, does the output path calculation on
+/// it, then continues with the foo derivation.
+///
+/// The code ensures the resulting Derivations match our fixtures.
+#[test]
+fn output_path_construction() {
+    // create the bar derivation
+    // assemble bar env
+    let mut bar_env: BTreeMap<String, String> = BTreeMap::new();
+    bar_env.insert("builder".to_string(), ":".to_string());
+    bar_env.insert("name".to_string(), "bar".to_string());
+    bar_env.insert("out".to_string(), "".to_string()); // will be calculated
+    bar_env.insert(
+        "outputHash".to_string(),
+        "08813cbee9903c62be4c5027726a418a300da4500b2d369d3af9286f4815ceba".to_string(),
+    );
+    bar_env.insert("outputHashAlgo".to_string(), "sha256".to_string());
+    bar_env.insert("outputHashMode".to_string(), "recursive".to_string());
+    bar_env.insert("system".to_string(), ":".to_string());
+
+    // assemble bar outputs
+    let mut bar_outputs: BTreeMap<String, Output> = BTreeMap::new();
+    bar_outputs.insert(
+        "out".to_string(),
+        Output {
+            path: "".to_string(), // will be calculated
+            hash: Some(Hash {
+                digest: "08813cbee9903c62be4c5027726a418a300da4500b2d369d3af9286f4815ceba"
+                    .to_string(),
+                algo: "r:sha256".to_string(),
+            }),
+        },
+    );
+
+    // assemble bar itself
+    let mut bar_drv = Derivation {
+        arguments: vec![],
+        builder: ":".to_string(),
+        environment: bar_env,
+        input_derivations: BTreeMap::new(),
+        input_sources: vec![],
+        outputs: bar_outputs,
+        system: ":".to_string(),
+    };
+
+    // calculate bar output paths
+    let bar_calc_result = bar_drv.calculate_output_paths(
+        "bar",
+        &bar_drv.calculate_drv_replacement_str(|_| panic!("is FOD, should not lookup")),
+    );
+    assert!(bar_calc_result.is_ok());
+
+    // ensure it matches our bar fixture
+    let bar_data = read_file(&format!(
+        "{}/{}.json",
+        RESOURCES_PATHS, "0hm2f1psjpcwg8fijsmr4wwxrx59s092-bar.drv"
+    ));
+    let bar_drv_expected: Derivation = serde_json::from_str(&bar_data).expect("must deserialize");
+    assert_eq!(bar_drv_expected, bar_drv);
+
+    // now construct foo, which requires bar_drv
+    // Note how we refer to the output path, drv name and replacement_str (with calculated output paths) of bar.
+    let bar_output_path = &bar_drv.outputs.get("out").expect("must exist").path;
+    let bar_drv_replacement_str =
+        &bar_drv.calculate_drv_replacement_str(|_| panic!("is FOD, should not lookup"));
+
+    let bar_drv_path = bar_drv
+        .calculate_derivation_path("bar")
+        .expect("must succeed")
+        .to_absolute_path();
+
+    // assemble foo env
+    let mut foo_env: BTreeMap<String, String> = BTreeMap::new();
+    foo_env.insert("bar".to_string(), bar_output_path.to_string());
+    foo_env.insert("builder".to_string(), ":".to_string());
+    foo_env.insert("name".to_string(), "foo".to_string());
+    foo_env.insert("out".to_string(), "".to_string()); // will be calculated
+    foo_env.insert("system".to_string(), ":".to_string());
+
+    // asssemble foo outputs
+    let mut foo_outputs: BTreeMap<String, Output> = BTreeMap::new();
+    foo_outputs.insert(
+        "out".to_string(),
+        Output {
+            path: "".to_string(), // will be calculated
+            hash: None,
+        },
+    );
+
+    // assemble foo input_derivations
+    let mut foo_input_derivations: BTreeMap<String, Vec<String>> = BTreeMap::new();
+    foo_input_derivations.insert(bar_drv_path.to_absolute_string(), vec!["out".to_string()]);
+
+    // assemble foo itself
+    let mut foo_drv = Derivation {
+        arguments: vec![],
+        builder: ":".to_string(),
+        environment: foo_env,
+        input_derivations: foo_input_derivations,
+        input_sources: vec![],
+        outputs: foo_outputs,
+        system: ":".to_string(),
+    };
+
+    // calculate foo output paths
+    let foo_calc_result = foo_drv.calculate_output_paths(
+        "foo",
+        &foo_drv.calculate_drv_replacement_str(|drv_name| {
+            if drv_name != "/nix/store/0hm2f1psjpcwg8fijsmr4wwxrx59s092-bar.drv" {
+                panic!("lookup called with unexpected drv_name: {}", drv_name);
+            }
+            bar_drv_replacement_str.clone()
+        }),
+    );
+    assert!(foo_calc_result.is_ok());
+
+    // ensure it matches our foo fixture
+    let foo_data = read_file(&format!(
+        "{}/{}.json",
+        RESOURCES_PATHS, "4wvvbi4jwn0prsdxb7vs673qa5h9gr7x-foo.drv",
+    ));
+    let foo_drv_expected: Derivation = serde_json::from_str(&foo_data).expect("must deserialize");
+    assert_eq!(foo_drv_expected, foo_drv);
+
+    assert_eq!(
+        NixPath::from_string("4wvvbi4jwn0prsdxb7vs673qa5h9gr7x-foo.drv").expect("must succeed"),
+        foo_drv
+            .calculate_derivation_path("foo")
+            .expect("must succeed")
+    );
+}