about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorian Klink <flokli@flokli.de>2023-01-06T12·53+0100
committerflokli <flokli@flokli.de>2023-01-06T15·39+0000
commit999afd4be27619657a10d3031f289f627bb029b1 (patch)
treeff2d3897a35c926bc51586555137510f232cf18d
parentf73ab76fcedffa8b6892b95e90cbf77e55451b52 (diff)
test(tvix/derivation): add output_path_construction test r/5612
This exercises the output path calculation functions like a constructing
client (an implementation of builtins.derivation) would do.
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.

Change-Id: If93f89c6622fac1c1941085083931b6f657c04bc
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7775
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
-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")
+    );
+}