Merge pull request #9247 from obsidiansystems/derivation-test-with-files

Turn derivation unit tests into unit characterization tests

(cherry picked from commit a6e587923c)
Change-Id: Ia2a2e65aabfee8d5d52142b8fdaacbae4a27242c
This commit is contained in:
eldritch horrors 2024-03-04 05:21:10 +01:00
parent 4206441a12
commit 7ff1dca1fa
17 changed files with 228 additions and 155 deletions

View file

@ -20,4 +20,9 @@ static bool testAccept() {
return getEnv("_NIX_TEST_ACCEPT") == "1"; return getEnv("_NIX_TEST_ACCEPT") == "1";
} }
constexpr std::string_view cannotReadGoldenMaster =
"Cannot read golden master because another test is also updating it";
constexpr std::string_view updatingGoldenMaster =
"Updating golden master";
} }

View file

@ -24,14 +24,14 @@ public:
{ {
if (testAccept()) if (testAccept())
{ {
GTEST_SKIP() << "Cannot read golden master because another test is also updating it"; GTEST_SKIP() << cannotReadGoldenMaster;
} }
else else
{ {
auto expected = readFile(goldenMaster(testStem)); auto encoded = readFile(goldenMaster(testStem));
T got = ({ T got = ({
StringSource from { expected }; StringSource from { encoded };
CommonProto::Serialise<T>::read( CommonProto::Serialise<T>::read(
*store, *store,
CommonProto::ReadConn { .from = from }); CommonProto::ReadConn { .from = from });
@ -59,7 +59,7 @@ public:
{ {
createDirs(dirOf(file)); createDirs(dirOf(file));
writeFile(file, to.s); writeFile(file, to.s);
GTEST_SKIP() << "Updating golden master"; GTEST_SKIP() << updatingGoldenMaster;
} }
else else
{ {

View file

@ -5,9 +5,12 @@
#include "derivations.hh" #include "derivations.hh"
#include "tests/libstore.hh" #include "tests/libstore.hh"
#include "characterization.hh"
namespace nix { namespace nix {
using nlohmann::json;
class DerivationTest : public LibStoreTest class DerivationTest : public LibStoreTest
{ {
public: public:
@ -16,6 +19,12 @@ public:
* to worry about race conditions if the tests run concurrently. * to worry about race conditions if the tests run concurrently.
*/ */
ExperimentalFeatureSettings mockXpSettings; ExperimentalFeatureSettings mockXpSettings;
Path unitTestData = getUnitTestData() + "/libstore/derivation";
Path goldenMaster(std::string_view testStem) {
return unitTestData + "/" + testStem;
}
}; };
class CaDerivationTest : public DerivationTest class CaDerivationTest : public DerivationTest
@ -46,7 +55,7 @@ TEST_F(DerivationTest, BadATerm_version) {
ASSERT_THROW( ASSERT_THROW(
parseDerivation( parseDerivation(
*store, *store,
R"(DrvWithVersion("invalid-version",[],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))", readFile(goldenMaster("bad-version.drv")),
"whatever", "whatever",
mockXpSettings), mockXpSettings),
FormatError); FormatError);
@ -56,50 +65,61 @@ TEST_F(DynDerivationTest, BadATerm_oldVersionDynDeps) {
ASSERT_THROW( ASSERT_THROW(
parseDerivation( parseDerivation(
*store, *store,
R"(Derive([],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",(["cat","dog"],[("cat",["kitten"]),("goose",["gosling"])]))],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))", readFile(goldenMaster("bad-old-version-dyn-deps.drv")),
"dyn-dep-derivation", "dyn-dep-derivation",
mockXpSettings), mockXpSettings),
FormatError); FormatError);
} }
#define TEST_JSON(FIXTURE, NAME, STR, VAL, DRV_NAME, OUTPUT_NAME) \ #define TEST_JSON(FIXTURE, NAME, VAL, DRV_NAME, OUTPUT_NAME) \
TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _to_json) { \ TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _from_json) { \
using nlohmann::literals::operator "" _json; \ if (testAccept()) \
ASSERT_EQ( \ { \
STR ## _json, \ GTEST_SKIP() << cannotReadGoldenMaster; \
(DerivationOutput { VAL }).toJSON( \ } \
*store, \ else \
DRV_NAME, \ { \
OUTPUT_NAME)); \ auto encoded = json::parse( \
} \ readFile(goldenMaster("output-" #NAME ".json"))); \
\ DerivationOutput got = DerivationOutput::fromJSON( \
TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _from_json) { \ *store, \
using nlohmann::literals::operator "" _json; \ DRV_NAME, \
ASSERT_EQ( \ OUTPUT_NAME, \
DerivationOutput { VAL }, \ encoded, \
DerivationOutput::fromJSON( \ mockXpSettings); \
*store, \ DerivationOutput expected { VAL }; \
DRV_NAME, \ ASSERT_EQ(got, expected); \
OUTPUT_NAME, \ } \
STR ## _json, \ } \
mockXpSettings)); \ \
TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _to_json) { \
auto file = goldenMaster("output-" #NAME ".json"); \
\
json got = DerivationOutput { VAL }.toJSON( \
*store, \
DRV_NAME, \
OUTPUT_NAME); \
\
if (testAccept()) \
{ \
createDirs(dirOf(file)); \
writeFile(file, got.dump(2) + "\n"); \
GTEST_SKIP() << updatingGoldenMaster; \
} \
else \
{ \
auto expected = json::parse(readFile(file)); \
ASSERT_EQ(got, expected); \
} \
} }
TEST_JSON(DerivationTest, inputAddressed, TEST_JSON(DerivationTest, inputAddressed,
R"({
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
})",
(DerivationOutput::InputAddressed { (DerivationOutput::InputAddressed {
.path = store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"), .path = store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"),
}), }),
"drv-name", "output-name") "drv-name", "output-name")
TEST_JSON(DerivationTest, caFixedFlat, TEST_JSON(DerivationTest, caFixedFlat,
R"({
"hashAlgo": "sha256",
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name"
})",
(DerivationOutput::CAFixed { (DerivationOutput::CAFixed {
.ca = { .ca = {
.method = FileIngestionMethod::Flat, .method = FileIngestionMethod::Flat,
@ -109,11 +129,6 @@ TEST_JSON(DerivationTest, caFixedFlat,
"drv-name", "output-name") "drv-name", "output-name")
TEST_JSON(DerivationTest, caFixedNAR, TEST_JSON(DerivationTest, caFixedNAR,
R"({
"hashAlgo": "r:sha256",
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
})",
(DerivationOutput::CAFixed { (DerivationOutput::CAFixed {
.ca = { .ca = {
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
@ -123,11 +138,6 @@ TEST_JSON(DerivationTest, caFixedNAR,
"drv-name", "output-name") "drv-name", "output-name")
TEST_JSON(DynDerivationTest, caFixedText, TEST_JSON(DynDerivationTest, caFixedText,
R"({
"hashAlgo": "text:sha256",
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name"
})",
(DerivationOutput::CAFixed { (DerivationOutput::CAFixed {
.ca = { .ca = {
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
@ -136,9 +146,6 @@ TEST_JSON(DynDerivationTest, caFixedText,
"drv-name", "output-name") "drv-name", "output-name")
TEST_JSON(CaDerivationTest, caFloating, TEST_JSON(CaDerivationTest, caFloating,
R"({
"hashAlgo": "r:sha256"
})",
(DerivationOutput::CAFloating { (DerivationOutput::CAFloating {
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
.hashType = htSHA256, .hashType = htSHA256,
@ -146,15 +153,10 @@ TEST_JSON(CaDerivationTest, caFloating,
"drv-name", "output-name") "drv-name", "output-name")
TEST_JSON(DerivationTest, deferred, TEST_JSON(DerivationTest, deferred,
R"({ })",
DerivationOutput::Deferred { }, DerivationOutput::Deferred { },
"drv-name", "output-name") "drv-name", "output-name")
TEST_JSON(ImpureDerivationTest, impure, TEST_JSON(ImpureDerivationTest, impure,
R"({
"hashAlgo": "r:sha256",
"impure": true
})",
(DerivationOutput::Impure { (DerivationOutput::Impure {
.method = FileIngestionMethod::Recursive, .method = FileIngestionMethod::Recursive,
.hashType = htSHA256, .hashType = htSHA256,
@ -163,43 +165,79 @@ TEST_JSON(ImpureDerivationTest, impure,
#undef TEST_JSON #undef TEST_JSON
#define TEST_JSON(FIXTURE, NAME, STR, VAL) \ #define TEST_JSON(FIXTURE, NAME, VAL) \
TEST_F(FIXTURE, Derivation_ ## NAME ## _to_json) { \ TEST_F(FIXTURE, Derivation_ ## NAME ## _from_json) { \
using nlohmann::literals::operator "" _json; \ if (testAccept()) \
ASSERT_EQ( \ { \
STR ## _json, \ GTEST_SKIP() << cannotReadGoldenMaster; \
(VAL).toJSON(*store)); \ } \
} \ else \
\ { \
TEST_F(FIXTURE, Derivation_ ## NAME ## _from_json) { \ auto encoded = json::parse( \
using nlohmann::literals::operator "" _json; \ readFile(goldenMaster( #NAME ".json"))); \
ASSERT_EQ( \ Derivation expected { VAL }; \
(VAL), \ Derivation got = Derivation::fromJSON( \
Derivation::fromJSON( \ *store, \
*store, \ encoded, \
STR ## _json, \ mockXpSettings); \
mockXpSettings)); \ ASSERT_EQ(got, expected); \
} \
} \
\
TEST_F(FIXTURE, Derivation_ ## NAME ## _to_json) { \
auto file = goldenMaster( #NAME ".json"); \
\
json got = Derivation { VAL }.toJSON(*store); \
\
if (testAccept()) \
{ \
createDirs(dirOf(file)); \
writeFile(file, got.dump(2) + "\n"); \
GTEST_SKIP() << updatingGoldenMaster; \
} \
else \
{ \
auto expected = json::parse(readFile(file)); \
ASSERT_EQ(got, expected); \
} \
} }
#define TEST_ATERM(FIXTURE, NAME, STR, VAL, DRV_NAME) \ #define TEST_ATERM(FIXTURE, NAME, VAL, DRV_NAME) \
TEST_F(FIXTURE, Derivation_ ## NAME ## _to_aterm) { \ TEST_F(FIXTURE, Derivation_ ## NAME ## _from_aterm) { \
ASSERT_EQ( \ if (testAccept()) \
STR, \ { \
(VAL).unparse(*store, false)); \ GTEST_SKIP() << cannotReadGoldenMaster; \
} \ } \
\ else \
TEST_F(FIXTURE, Derivation_ ## NAME ## _from_aterm) { \ { \
auto parsed = parseDerivation( \ auto encoded = readFile(goldenMaster( #NAME ".drv")); \
*store, \ Derivation expected { VAL }; \
STR, \ auto got = parseDerivation( \
DRV_NAME, \ *store, \
mockXpSettings); \ std::move(encoded), \
ASSERT_EQ( \ DRV_NAME, \
(VAL).toJSON(*store), \ mockXpSettings); \
parsed.toJSON(*store)); \ ASSERT_EQ(got.toJSON(*store), expected.toJSON(*store)) ; \
ASSERT_EQ( \ ASSERT_EQ(got, expected); \
(VAL), \ } \
parsed); \ } \
\
TEST_F(FIXTURE, Derivation_ ## NAME ## _to_aterm) { \
auto file = goldenMaster( #NAME ".drv"); \
\
auto got = (VAL).unparse(*store, false); \
\
if (testAccept()) \
{ \
createDirs(dirOf(file)); \
writeFile(file, got); \
GTEST_SKIP() << updatingGoldenMaster; \
} \
else \
{ \
auto expected = readFile(file); \
ASSERT_EQ(got, expected); \
} \
} }
Derivation makeSimpleDrv(const Store & store) { Derivation makeSimpleDrv(const Store & store) {
@ -236,36 +274,9 @@ Derivation makeSimpleDrv(const Store & store) {
return drv; return drv;
} }
TEST_JSON(DerivationTest, simple, TEST_JSON(DerivationTest, simple, makeSimpleDrv(*store))
R"({
"name": "simple-derivation",
"inputSrcs": [
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
],
"inputDrvs": {
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"dynamicOutputs": {},
"outputs": [
"cat",
"dog"
]
}
},
"system": "wasm-sel4",
"builder": "foo",
"args": [
"bar",
"baz"
],
"env": {
"BIG_BAD": "WOLF"
},
"outputs": {}
})",
makeSimpleDrv(*store))
TEST_ATERM(DerivationTest, simple, TEST_ATERM(DerivationTest, simple,
R"(Derive([],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))",
makeSimpleDrv(*store), makeSimpleDrv(*store),
"simple-derivation") "simple-derivation")
@ -321,45 +332,9 @@ Derivation makeDynDepDerivation(const Store & store) {
return drv; return drv;
} }
TEST_JSON(DynDerivationTest, dynDerivationDeps, TEST_JSON(DynDerivationTest, dynDerivationDeps, makeDynDepDerivation(*store))
R"({
"name": "dyn-dep-derivation",
"inputSrcs": [
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
],
"inputDrvs": {
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"dynamicOutputs": {
"cat": {
"dynamicOutputs": {},
"outputs": ["kitten"]
},
"goose": {
"dynamicOutputs": {},
"outputs": ["gosling"]
}
},
"outputs": [
"cat",
"dog"
]
}
},
"system": "wasm-sel4",
"builder": "foo",
"args": [
"bar",
"baz"
],
"env": {
"BIG_BAD": "WOLF"
},
"outputs": {}
})",
makeDynDepDerivation(*store))
TEST_ATERM(DynDerivationTest, dynDerivationDeps, TEST_ATERM(DynDerivationTest, dynDerivationDeps,
R"(DrvWithVersion("xp-dyn-drv",[],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",(["cat","dog"],[("cat",["kitten"]),("goose",["gosling"])]))],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))",
makeDynDepDerivation(*store), makeDynDepDerivation(*store),
"dyn-dep-derivation") "dyn-dep-derivation")

View file

@ -29,7 +29,7 @@ public:
{ {
if (testAccept()) if (testAccept())
{ {
GTEST_SKIP() << "Cannot read golden master because another test is also updating it"; GTEST_SKIP() << cannotReadGoldenMaster;
} }
else else
{ {
@ -70,7 +70,7 @@ public:
{ {
createDirs(dirOf(file)); createDirs(dirOf(file));
writeFile(file, to.s); writeFile(file, to.s);
GTEST_SKIP() << "Updating golden master"; GTEST_SKIP() << updatingGoldenMaster;
} }
else else
{ {

View file

@ -0,0 +1 @@
Derive([],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",(["cat","dog"],[("cat",["kitten"]),("goose",["gosling"])]))],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")])

View file

@ -0,0 +1 @@
DrvWithVersion("invalid-version",[],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")])

View file

@ -0,0 +1 @@
DrvWithVersion("xp-dyn-drv",[],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",(["cat","dog"],[("cat",["kitten"]),("goose",["gosling"])]))],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")])

View file

@ -0,0 +1,38 @@
{
"args": [
"bar",
"baz"
],
"builder": "foo",
"env": {
"BIG_BAD": "WOLF"
},
"inputDrvs": {
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"dynamicOutputs": {
"cat": {
"dynamicOutputs": {},
"outputs": [
"kitten"
]
},
"goose": {
"dynamicOutputs": {},
"outputs": [
"gosling"
]
}
},
"outputs": [
"cat",
"dog"
]
}
},
"inputSrcs": [
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
],
"name": "dyn-dep-derivation",
"outputs": {},
"system": "wasm-sel4"
}

View file

@ -0,0 +1,5 @@
{
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"hashAlgo": "sha256",
"path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name"
}

View file

@ -0,0 +1,5 @@
{
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"hashAlgo": "r:sha256",
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
}

View file

@ -0,0 +1,5 @@
{
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"hashAlgo": "text:sha256",
"path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name"
}

View file

@ -0,0 +1,3 @@
{
"hashAlgo": "r:sha256"
}

View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1,4 @@
{
"hashAlgo": "r:sha256",
"impure": true
}

View file

@ -0,0 +1,3 @@
{
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
}

View file

@ -0,0 +1 @@
Derive([],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")])

View file

@ -0,0 +1,25 @@
{
"args": [
"bar",
"baz"
],
"builder": "foo",
"env": {
"BIG_BAD": "WOLF"
},
"inputDrvs": {
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"dynamicOutputs": {},
"outputs": [
"cat",
"dog"
]
}
},
"inputSrcs": [
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
],
"name": "simple-derivation",
"outputs": {},
"system": "wasm-sel4"
}