From b2ee6c36a0a47c0653b4e50d10d4f57bb85e384c Mon Sep 17 00:00:00 2001 From: "Commentator2.0" Date: Tue, 21 Oct 2025 19:26:27 +0200 Subject: [PATCH] tests/functional2: paritally migrate test_fixed.sh Change-Id: I3e4479b3ca718f24f604b52a6717ce18f793553b --- tests/functional/fixed.sh | 42 ----- tests/functional2/build/__init__.py | 0 tests/functional2/build/test_fixed.py | 143 ++++++++++++++++++ .../global_assets/fixed/fixed.builder1.sh | 3 + .../global_assets/fixed/fixed.builder2.sh | 6 + .../testlib/global_assets/fixed/fixed.nix | 79 ++++++++++ 6 files changed, 231 insertions(+), 42 deletions(-) create mode 100644 tests/functional2/build/__init__.py create mode 100644 tests/functional2/build/test_fixed.py create mode 100644 tests/functional2/testlib/global_assets/fixed/fixed.builder1.sh create mode 100644 tests/functional2/testlib/global_assets/fixed/fixed.builder2.sh create mode 100644 tests/functional2/testlib/global_assets/fixed/fixed.nix diff --git a/tests/functional/fixed.sh b/tests/functional/fixed.sh index 3faf092ed..9e90d6fa4 100644 --- a/tests/functional/fixed.sh +++ b/tests/functional/fixed.sh @@ -2,48 +2,6 @@ source common.sh clearStore -path=$(nix-store -q $(nix-instantiate fixed.nix -A good.0)) - -echo 'testing bad...' -nix-build fixed.nix -A bad --no-out-link && fail "should fail" - -# Building with the bad hash should produce the "good" output path as -# a side-effect. -[[ -e $path ]] -nix path-info --json $path | grep fixed:md5:2qk15sxzzjlnpjk9brn7j8ppcd - -echo 'testing good...' -nix-build fixed.nix -A good --no-out-link - -echo 'testing --check...' -nix-build fixed.nix -A check --check && fail "should fail" - -echo 'testing good2...' -nix-build fixed.nix -A good2 --no-out-link - -echo 'testing reallyBad...' -nix-instantiate fixed.nix -A reallyBad && fail "should fail" - -echo 'testing fixed with references...' -expectStderr 1 nix-build fixed.nix -A badReferences | grepQuiet "not allowed to refer to other store paths" - -echo 'testing illegal references...' -# Fixed FOD hashes cannot be asserted because: -# - the store directory varies between the "Lix build sandbox environment" and a user test run -# - *-darwin has a different store location on the top of this in the sandbox (/private/tmp/...) causing further changes. -# Regex matching is the best we can afford. -expectStderr 102 nix-build fixed.nix -A illegalReferences | grep -z "the fixed-output derivation '$TEST_ROOT/store/[a-z0-9]*-illegal-reference.drv' must not reference store paths but 1 such references were found:.*$TEST_ROOT/store/[a-z0-9]*-fixed" > /dev/null - -# While we're at it, check attribute selection a bit more. -echo 'testing attribute selection...' -test $(nix-instantiate fixed.nix -A good.1 | wc -l) = 1 - -# Test parallel builds of derivations that produce the same output. -# Only one should run at the same time. -echo 'testing parallelSame...' -clearStore -nix-build fixed.nix -A parallelSame --no-out-link -j2 - # Fixed-output derivations with a recursive SHA-256 hash should # produce the same path as "nix-store --add". echo 'testing sameAsAdd...' diff --git a/tests/functional2/build/__init__.py b/tests/functional2/build/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/functional2/build/test_fixed.py b/tests/functional2/build/test_fixed.py new file mode 100644 index 000000000..8580e6819 --- /dev/null +++ b/tests/functional2/build/test_fixed.py @@ -0,0 +1,143 @@ +import re +from pathlib import Path + +import pytest + +from functional2.testlib.fixtures.env import ManagedEnv +from functional2.testlib.fixtures.file_helper import with_files +from functional2.testlib.fixtures.nix import Nix +from functional2.testlib.utils import get_global_asset_pack + + +@pytest.fixture(autouse=True) +def impure_vars(env: ManagedEnv): + """ + Sets the IMPURE_VARs required by fixed.builder.sh + because I have no clue what Eelco was thinking when writing this stuff + """ + env["IMPURE_VAR1"] = "foo" + env["IMPURE_VAR2"] = "bar" + + +@with_files(get_global_asset_pack("fixed")) +def test_bad(nix: Nix): + res = nix.nix_instantiate(["fixed.nix", "-A", "good.0"]).run().ok() + store_path = nix.nix_store(["-q", res.stdout_plain]).run().ok().stdout_plain + path = Path(f"{nix.env.dirs.test_root}{store_path}") + assert not path.exists() + + # Building with the bad hash should produce the "good" output path as + # a sideeffect. + res = nix.nix_build(["fixed.nix", "-A", "bad", "--no-out-link"]).run().expect(102) + assert "hash mismatch in fixed-output derivation" in res.stderr_plain + assert path.exists() + + nix.settings.feature("nix-command") + res = nix.nix(["path-info", "--json", store_path]).run().ok() + assert res.json()[0]["ca"] == "fixed:md5:2qk15sxzzjlnpjk9brn7j8ppcd" + + +@with_files(get_global_asset_pack("fixed")) +def test_good(nix: Nix): + nix.nix_build(["fixed.nix", "-A", "good", "--no-out-link"]).run().ok() + + +@with_files(get_global_asset_pack("fixed")) +def test_check(nix: Nix): + res = nix.nix_build(["fixed.nix", "-A", "check", "--check"]).run().expect(1) + assert "some of the outputs of " in res.stderr_plain + assert "are not valid, so checking is not possible" in res.stderr_plain + + +@with_files(get_global_asset_pack("fixed")) +def test_good2(nix: Nix): + nix.nix_build(["fixed.nix", "-A", "good2", "--no-out-link"]).run().ok() + + +@with_files(get_global_asset_pack("fixed")) +def test_really_bad(nix: Nix): + res = nix.nix_instantiate(["fixed.nix", "-A", "reallyBad"]).run().expect(1) + assert ( + "error: hash 'ddd8be4b179a529afa5f2ffae4b9858' has wrong length for hash type 'md5'" + in res.stderr_plain + ) + + +@with_files(get_global_asset_pack("fixed")) +def test_other_store_references(nix: Nix): + res = nix.nix_build(["fixed.nix", "-A", "badReferences"]).run().expect(1) + assert "not allowed to refer to other store paths" in res.stderr_plain + + +@with_files(get_global_asset_pack("fixed")) +def test_illegal_references(nix: Nix): + """ + Fixed FOD hashes cannot be asserted because: + - the store directory varies between the "Lix build sandbox environment" and a user test run + - *-darwin has a different store location on the top of this in the sandbox (/private/tmp/...) causing further changes. + Regex matching is the best we can afford. + """ + res = nix.nix_build(["fixed.nix", "-A", "illegalReferences"]).run().expect(102) + assert re.findall( + rf"the fixed-output derivation '{nix.env.dirs.test_root}/nix/store/[a-z0-9]*-illegal-reference.drv' must not reference store paths but 1 such references were found:.*{nix.env.dirs.test_root}/nix/[a-z0-9]*-fixed", + res.stderr_plain, + ) + + +@with_files(get_global_asset_pack("fixed")) +def test_attribute_selection(nix: Nix): + res = nix.nix_instantiate(["fixed.nix", "-A", "good.1"]).run().ok() + assert res.stdout_plain == "/nix/store/6x8g4rpkb7lvhrj4vr81mflf4i424q3j-fixed.drv" + + +@with_files(get_global_asset_pack("fixed")) +def test_parallel_same(nix: Nix): + """ + Test parallel builds of derivations that produce the same output. + Only one should run at the same time. + """ + nix.nix_build(["fixed.nix", "-A", "parallelSame", "--no-out-link", "-j2"]).run().ok() + + +@pytest.mark.skip( + "TODO(Commentator2.0, 2025-10): Doesn't work for some reason, f1 test is kept for now" +) +@with_files(get_global_asset_pack("fixed")) +def test_same_as_add(nix: Nix, files: Path): + """ + Fixed-output derivations with a recursive SHA-256 hash should + produce the same path as "nix-store --add". + """ + res = nix.nix_build(["fixed.nix", "-A", "sameAsAdd", "--no-out-link"]).run().ok() + out = res.stdout_plain + + fixed = files / "fixed" + # is failing as this isn't created for f2: shutil.rmtree(fixed) + (fixed / "bla").mkdir(parents=True) + foo = fixed / "foo" + foo.write_text("Hello World!") + (fixed / "bar").symlink_to(foo) + + out2 = nix.nix_store(["--add", str(fixed)]).run().ok().stdout_plain + assert out == out2 + + out3 = ( + nix.nix_store(["--add-fixed", "--recursive", "sha256", str(fixed)]).run().ok().stdout_plain + ) + assert out == out3 + + out4 = ( + nix.nix_store( + [ + "--print-fixed-path", + "--recursive", + "sha256", + "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik", + "fixed", + ] + ) + .run() + .ok() + .stdout_plain + ) + assert out == out4 diff --git a/tests/functional2/testlib/global_assets/fixed/fixed.builder1.sh b/tests/functional2/testlib/global_assets/fixed/fixed.builder1.sh new file mode 100644 index 000000000..c41bb2b9a --- /dev/null +++ b/tests/functional2/testlib/global_assets/fixed/fixed.builder1.sh @@ -0,0 +1,3 @@ +if test "$IMPURE_VAR1" != "foo"; then exit 1; fi +if test "$IMPURE_VAR2" != "bar"; then exit 1; fi +echo "Hello World!" > $out diff --git a/tests/functional2/testlib/global_assets/fixed/fixed.builder2.sh b/tests/functional2/testlib/global_assets/fixed/fixed.builder2.sh new file mode 100644 index 000000000..31ea1579a --- /dev/null +++ b/tests/functional2/testlib/global_assets/fixed/fixed.builder2.sh @@ -0,0 +1,6 @@ +echo dummy: $dummy +if test -n "$dummy"; then sleep 2; fi +mkdir $out +mkdir $out/bla +echo "Hello World!" > $out/foo +ln -s foo $out/bar diff --git a/tests/functional2/testlib/global_assets/fixed/fixed.nix b/tests/functional2/testlib/global_assets/fixed/fixed.nix new file mode 100644 index 000000000..139b5bc3d --- /dev/null +++ b/tests/functional2/testlib/global_assets/fixed/fixed.nix @@ -0,0 +1,79 @@ +with import ./config.nix; + +rec { + + f2 = dummy: builder: mode: algo: hash: mkDerivation { + name = "fixed"; + inherit builder; + outputHashMode = mode; + outputHashAlgo = algo; + outputHash = hash; + inherit dummy; + impureEnvVars = ["IMPURE_VAR1" "IMPURE_VAR2"]; + }; + + f = f2 ""; + + good = [ + (f ./fixed.builder1.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858") + (f ./fixed.builder1.sh "flat" "sha1" "a0b65939670bc2c010f4d5d6a0b3e4e4590fb92b") + (f ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") + (f ./fixed.builder2.sh "recursive" "sha1" "vw46m23bizj4n8afrc0fj19wrp7mj3c0") + ]; + + # Expression to test that `nix-build --check` also throws an error if the hash of + # fixed-output derivation has changed even if the hash exists in the store (in this + # case the hash exists because of `fixed.builder2.sh`, but building a derivation + # with the same hash and a different result must throw an error). + check = [ + (f ./fixed.builder1.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") + ]; + + good2 = [ + # Yes, this looks fscked up: builder2 doesn't have that result. + # But Nix sees that an output with the desired hash already + # exists, and will refrain from building it. + (f ./fixed.builder2.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858") + ]; + + sameAsAdd = + f ./fixed.builder2.sh "recursive" "sha256" "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik"; + + bad = [ + (f ./fixed.builder1.sh "flat" "md5" "0ddd8be4b179a529afa5f2ffae4b9858") + ]; + + reallyBad = [ + # Hash too short, and not base-32 either. + (f ./fixed.builder1.sh "flat" "md5" "ddd8be4b179a529afa5f2ffae4b9858") + ]; + + badReferences = mkDerivation rec { + name = "bad-hash"; + builder = script; + script = builtins.toFile "installer.sh" "echo $script >$out"; + outputHash = "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik"; + outputHashAlgo = "sha256"; + outputHashMode = "flat"; + }; + + illegalReferences = mkDerivation { + name = "illegal-reference"; + ref = builtins.head good; + + builder = builtins.toFile "builder.sh" '' + mkdir $out + cp -R $ref $out + ''; + outputHashMode = "recursive"; + outputHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + }; + + # Test for building two derivations in parallel that produce the + # same output path because they're fixed-output derivations. + parallelSame = [ + (f2 "foo" ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") + (f2 "bar" ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") + ]; + +}