From 5cdf2a19bd6ed32ab38397338c4b3148f08ecd59 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 15 Dec 2025 01:33:07 -0500 Subject: [PATCH] Add basic floating CA drv output subst unit test --- .../ca-drv/store-after.json | 58 ++++++++++ .../ca-drv/store-before.json | 27 +++++ .../ca-drv/substituter.json | 39 +++++++ src/libstore-tests/worker-substitution.cc | 104 +++++++++++++++++- 4 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 src/libstore-tests/data/worker-substitution/ca-drv/store-after.json create mode 100644 src/libstore-tests/data/worker-substitution/ca-drv/store-before.json create mode 100644 src/libstore-tests/data/worker-substitution/ca-drv/substituter.json diff --git a/src/libstore-tests/data/worker-substitution/ca-drv/store-after.json b/src/libstore-tests/data/worker-substitution/ca-drv/store-after.json new file mode 100644 index 000000000..7f0f62f87 --- /dev/null +++ b/src/libstore-tests/data/worker-substitution/ca-drv/store-after.json @@ -0,0 +1,58 @@ +{ + "buildTrace": { + "gnRuK+wfbXqRPzgO5MyiBebXrV10Kzv+tkZCEuPm7pY=": { + "out": { + "dependentRealisations": {}, + "outPath": "hrva7l0gsk67wffmks761mv4ks4vzsx7-test-ca-drv-out", + "signatures": [] + } + } + }, + "config": { + "store": "/nix/store" + }, + "contents": { + "hrva7l0gsk67wffmks761mv4ks4vzsx7-test-ca-drv-out": { + "contents": { + "contents": "I am the output of a CA derivation", + "executable": false, + "type": "regular" + }, + "info": { + "ca": { + "hash": "sha256-l0+gmYB0AK65UWuoSh7AbVRI4rAc5/VGqzBGTHgMsiU=", + "method": "nar" + }, + "deriver": null, + "narHash": "sha256-l0+gmYB0AK65UWuoSh7AbVRI4rAc5/VGqzBGTHgMsiU=", + "narSize": 152, + "references": [], + "registrationTime": null, + "signatures": [], + "storeDir": "/nix/store", + "ultimate": false, + "version": 2 + } + } + }, + "derivations": { + "vvyyj6h5ilinsv4q48q5y5vn7s3hxmhl-test-ca-drv.drv": { + "args": [], + "builder": "", + "env": {}, + "inputs": { + "drvs": {}, + "srcs": [] + }, + "name": "test-ca-drv", + "outputs": { + "out": { + "hashAlgo": "sha256", + "method": "nar" + } + }, + "system": "", + "version": 4 + } + } +} diff --git a/src/libstore-tests/data/worker-substitution/ca-drv/store-before.json b/src/libstore-tests/data/worker-substitution/ca-drv/store-before.json new file mode 100644 index 000000000..6d64d2327 --- /dev/null +++ b/src/libstore-tests/data/worker-substitution/ca-drv/store-before.json @@ -0,0 +1,27 @@ +{ + "buildTrace": {}, + "config": { + "store": "/nix/store" + }, + "contents": {}, + "derivations": { + "vvyyj6h5ilinsv4q48q5y5vn7s3hxmhl-test-ca-drv.drv": { + "args": [], + "builder": "", + "env": {}, + "inputs": { + "drvs": {}, + "srcs": [] + }, + "name": "test-ca-drv", + "outputs": { + "out": { + "hashAlgo": "sha256", + "method": "nar" + } + }, + "system": "", + "version": 4 + } + } +} diff --git a/src/libstore-tests/data/worker-substitution/ca-drv/substituter.json b/src/libstore-tests/data/worker-substitution/ca-drv/substituter.json new file mode 100644 index 000000000..93f4fb22a --- /dev/null +++ b/src/libstore-tests/data/worker-substitution/ca-drv/substituter.json @@ -0,0 +1,39 @@ +{ + "buildTrace": { + "gnRuK+wfbXqRPzgO5MyiBebXrV10Kzv+tkZCEuPm7pY=": { + "out": { + "dependentRealisations": {}, + "outPath": "hrva7l0gsk67wffmks761mv4ks4vzsx7-test-ca-drv-out", + "signatures": [] + } + } + }, + "config": { + "store": "/nix/store" + }, + "contents": { + "hrva7l0gsk67wffmks761mv4ks4vzsx7-test-ca-drv-out": { + "contents": { + "contents": "I am the output of a CA derivation", + "executable": false, + "type": "regular" + }, + "info": { + "ca": { + "hash": "sha256-l0+gmYB0AK65UWuoSh7AbVRI4rAc5/VGqzBGTHgMsiU=", + "method": "nar" + }, + "deriver": null, + "narHash": "sha256-l0+gmYB0AK65UWuoSh7AbVRI4rAc5/VGqzBGTHgMsiU=", + "narSize": 152, + "references": [], + "registrationTime": null, + "signatures": [], + "storeDir": "/nix/store", + "ultimate": false, + "version": 2 + } + } + }, + "derivations": {} +} diff --git a/src/libstore-tests/worker-substitution.cc b/src/libstore-tests/worker-substitution.cc index 7e94cc951..6a4ee46c8 100644 --- a/src/libstore-tests/worker-substitution.cc +++ b/src/libstore-tests/worker-substitution.cc @@ -2,6 +2,7 @@ #include #include "nix/store/build/worker.hh" +#include "nix/store/derivations.hh" #include "nix/store/dummy-store-impl.hh" #include "nix/store/globals.hh" #include "nix/util/memory-source-accessor.hh" @@ -97,7 +98,7 @@ TEST_F(WorkerSubstitutionTest, singleStoreObject) ASSERT_TRUE(dummyStore->isValidPath(pathInSubstituter)); // Verify the goal succeeded - ASSERT_EQ(goal->exitCode, Goal::ecSuccess); + ASSERT_EQ(upcast_goal(goal)->exitCode, Goal::ecSuccess); } TEST_F(WorkerSubstitutionTest, singleRootStoreObjectWithSingleDepStoreObject) @@ -170,7 +171,106 @@ TEST_F(WorkerSubstitutionTest, singleRootStoreObjectWithSingleDepStoreObject) ASSERT_TRUE(dummyStore->isValidPath(mainPath)); // Verify the goal succeeded - ASSERT_EQ(goal->exitCode, Goal::ecSuccess); + ASSERT_EQ(upcast_goal(goal)->exitCode, Goal::ecSuccess); +} + +TEST_F(WorkerSubstitutionTest, floatingDerivationOutput) +{ + // Enable CA derivations experimental feature + experimentalFeatureSettings.set("extra-experimental-features", "ca-derivations"); + + // Create a CA floating output derivation + Derivation drv; + drv.name = "test-ca-drv"; + drv.outputs = { + { + "out", + DerivationOutput{DerivationOutput::CAFloating{ + .method = ContentAddressMethod::Raw::NixArchive, + .hashAlgo = HashAlgorithm::SHA256, + }}, + }, + }; + + // Write the derivation to the destination store + auto drvPath = writeDerivation(*dummyStore, drv); + + // Snapshot the destination store before + checkpointJson("ca-drv/store-before", dummyStore); + + // Compute the hash modulo of the derivation + // For CA floating derivations, the kind is Deferred since outputs aren't known until build + auto hashModulo = hashDerivationModulo(*dummyStore, drv, true); + ASSERT_EQ(hashModulo.kind, DrvHash::Kind::Deferred); + auto drvHash = hashModulo.hashes.at("out"); + + // Create the output store object + auto outputPath = substituter->addToStore( + "test-ca-drv-out", + SourcePath{ + [] { + auto sc = make_ref(); + sc->root = MemorySourceAccessor::File{MemorySourceAccessor::File::Regular{ + .executable = false, + .contents = "I am the output of a CA derivation", + }}; + return sc; + }(), + }, + ContentAddressMethod::Raw::NixArchive, + HashAlgorithm::SHA256); + + // Add the realisation (build trace) to the substituter + substituter->buildTrace.insert_or_assign( + drvHash, + std::map{ + { + "out", + UnkeyedRealisation{ + .outPath = outputPath, + }, + }, + }); + + // Snapshot the substituter + checkpointJson("ca-drv/substituter", substituter); + + // The realisation should not exist in the destination store yet + DrvOutput drvOutput{drvHash, "out"}; + ASSERT_FALSE(dummyStore->queryRealisation(drvOutput)); + + // Create a worker with our custom substituter + Worker worker{*dummyStore, *dummyStore}; + + // Override the substituters to use our dummy store substituter + ref substituterAsStore = substituter; + worker.getSubstituters = [substituterAsStore]() -> std::list> { return {substituterAsStore}; }; + + // Create a derivation goal for the CA derivation output + // The worker should substitute the output rather than building + auto goal = worker.makeDerivationGoal(drvPath, drv, "out", bmNormal, true); + + // Run the worker + Goals goals; + goals.insert(upcast_goal(goal)); + worker.run(goals); + + // Snapshot the destination store after + checkpointJson("ca-drv/store-after", dummyStore); + + // The output path should now exist in the destination store + ASSERT_TRUE(dummyStore->isValidPath(outputPath)); + + // The realisation should now exist in the destination store + auto realisation = dummyStore->queryRealisation(drvOutput); + ASSERT_TRUE(realisation); + ASSERT_EQ(realisation->outPath, outputPath); + + // Verify the goal succeeded + ASSERT_EQ(upcast_goal(goal)->exitCode, Goal::ecSuccess); + + // Disable CA derivations experimental feature + experimentalFeatureSettings.set("extra-experimental-features", ""); } } // namespace nix