![John Ericson](/assets/img/avatar_default.png)
We use the same nested map representation we used for goals, again in order to save space. We might someday want to combine with `inputDrvs`, by doing `V = bool` instead of `V = std::set<OutputName>`, but we are not doing that yet for sake of a smaller diff. The ATerm format for Derivations also needs to be extended, in addition to the in-memory format. To accomodate this, we added a new basic versioning scheme, so old versions of Nix will get nice errors. (And going forward, if the ATerm format changes again the errors will be even better.) `parsedStrings`, an internal function used as part of parsing derivations in A-Term format, used to consume the final `]` but expect the initial `[` to already be consumed. This made for what looked like unbalanced brackets at callsites, which was confusing. Now it consumes both which is hopefully less confusing. As part of testing, we also created a unit test for the A-Term format for regular non-experimental derivations too. Co-authored-by: Robert Hensing <roberth@users.noreply.github.com> Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io> Apply suggestions from code review Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
370 lines
12 KiB
C++
370 lines
12 KiB
C++
#include <nlohmann/json.hpp>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "experimental-features.hh"
|
|
#include "derivations.hh"
|
|
|
|
#include "tests/libstore.hh"
|
|
|
|
namespace nix {
|
|
|
|
class DerivationTest : public LibStoreTest
|
|
{
|
|
public:
|
|
/**
|
|
* We set these in tests rather than the regular globals so we don't have
|
|
* to worry about race conditions if the tests run concurrently.
|
|
*/
|
|
ExperimentalFeatureSettings mockXpSettings;
|
|
};
|
|
|
|
class CaDerivationTest : public DerivationTest
|
|
{
|
|
void SetUp() override
|
|
{
|
|
mockXpSettings.set("experimental-features", "ca-derivations");
|
|
}
|
|
};
|
|
|
|
class DynDerivationTest : public DerivationTest
|
|
{
|
|
void SetUp() override
|
|
{
|
|
mockXpSettings.set("experimental-features", "dynamic-derivations ca-derivations");
|
|
}
|
|
};
|
|
|
|
class ImpureDerivationTest : public DerivationTest
|
|
{
|
|
void SetUp() override
|
|
{
|
|
mockXpSettings.set("experimental-features", "impure-derivations");
|
|
}
|
|
};
|
|
|
|
TEST_F(DerivationTest, BadATerm_version) {
|
|
ASSERT_THROW(
|
|
parseDerivation(
|
|
*store,
|
|
R"(DrvWithVersion("invalid-version",[],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))",
|
|
"whatever",
|
|
mockXpSettings),
|
|
FormatError);
|
|
}
|
|
|
|
TEST_F(DynDerivationTest, BadATerm_oldVersionDynDeps) {
|
|
ASSERT_THROW(
|
|
parseDerivation(
|
|
*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")]))",
|
|
"dyn-dep-derivation",
|
|
mockXpSettings),
|
|
FormatError);
|
|
}
|
|
|
|
#define TEST_JSON(FIXTURE, NAME, STR, VAL, DRV_NAME, OUTPUT_NAME) \
|
|
TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _to_json) { \
|
|
using nlohmann::literals::operator "" _json; \
|
|
ASSERT_EQ( \
|
|
STR ## _json, \
|
|
(DerivationOutput { VAL }).toJSON( \
|
|
*store, \
|
|
DRV_NAME, \
|
|
OUTPUT_NAME)); \
|
|
} \
|
|
\
|
|
TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _from_json) { \
|
|
using nlohmann::literals::operator "" _json; \
|
|
ASSERT_EQ( \
|
|
DerivationOutput { VAL }, \
|
|
DerivationOutput::fromJSON( \
|
|
*store, \
|
|
DRV_NAME, \
|
|
OUTPUT_NAME, \
|
|
STR ## _json, \
|
|
mockXpSettings)); \
|
|
}
|
|
|
|
TEST_JSON(DerivationTest, inputAddressed,
|
|
R"({
|
|
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
|
|
})",
|
|
(DerivationOutput::InputAddressed {
|
|
.path = store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"),
|
|
}),
|
|
"drv-name", "output-name")
|
|
|
|
TEST_JSON(DerivationTest, caFixedFlat,
|
|
R"({
|
|
"hashAlgo": "sha256",
|
|
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
|
|
"path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name"
|
|
})",
|
|
(DerivationOutput::CAFixed {
|
|
.ca = {
|
|
.method = FileIngestionMethod::Flat,
|
|
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
|
},
|
|
}),
|
|
"drv-name", "output-name")
|
|
|
|
TEST_JSON(DerivationTest, caFixedNAR,
|
|
R"({
|
|
"hashAlgo": "r:sha256",
|
|
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
|
|
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
|
|
})",
|
|
(DerivationOutput::CAFixed {
|
|
.ca = {
|
|
.method = FileIngestionMethod::Recursive,
|
|
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
|
},
|
|
}),
|
|
"drv-name", "output-name")
|
|
|
|
TEST_JSON(DynDerivationTest, caFixedText,
|
|
R"({
|
|
"hashAlgo": "text:sha256",
|
|
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
|
|
"path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name"
|
|
})",
|
|
(DerivationOutput::CAFixed {
|
|
.ca = {
|
|
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
|
},
|
|
}),
|
|
"drv-name", "output-name")
|
|
|
|
TEST_JSON(CaDerivationTest, caFloating,
|
|
R"({
|
|
"hashAlgo": "r:sha256"
|
|
})",
|
|
(DerivationOutput::CAFloating {
|
|
.method = FileIngestionMethod::Recursive,
|
|
.hashType = htSHA256,
|
|
}),
|
|
"drv-name", "output-name")
|
|
|
|
TEST_JSON(DerivationTest, deferred,
|
|
R"({ })",
|
|
DerivationOutput::Deferred { },
|
|
"drv-name", "output-name")
|
|
|
|
TEST_JSON(ImpureDerivationTest, impure,
|
|
R"({
|
|
"hashAlgo": "r:sha256",
|
|
"impure": true
|
|
})",
|
|
(DerivationOutput::Impure {
|
|
.method = FileIngestionMethod::Recursive,
|
|
.hashType = htSHA256,
|
|
}),
|
|
"drv-name", "output-name")
|
|
|
|
#undef TEST_JSON
|
|
|
|
#define TEST_JSON(FIXTURE, NAME, STR, VAL) \
|
|
TEST_F(FIXTURE, Derivation_ ## NAME ## _to_json) { \
|
|
using nlohmann::literals::operator "" _json; \
|
|
ASSERT_EQ( \
|
|
STR ## _json, \
|
|
(VAL).toJSON(*store)); \
|
|
} \
|
|
\
|
|
TEST_F(FIXTURE, Derivation_ ## NAME ## _from_json) { \
|
|
using nlohmann::literals::operator "" _json; \
|
|
ASSERT_EQ( \
|
|
(VAL), \
|
|
Derivation::fromJSON( \
|
|
*store, \
|
|
STR ## _json, \
|
|
mockXpSettings)); \
|
|
}
|
|
|
|
#define TEST_ATERM(FIXTURE, NAME, STR, VAL, DRV_NAME) \
|
|
TEST_F(FIXTURE, Derivation_ ## NAME ## _to_aterm) { \
|
|
ASSERT_EQ( \
|
|
STR, \
|
|
(VAL).unparse(*store, false)); \
|
|
} \
|
|
\
|
|
TEST_F(FIXTURE, Derivation_ ## NAME ## _from_aterm) { \
|
|
auto parsed = parseDerivation( \
|
|
*store, \
|
|
STR, \
|
|
DRV_NAME, \
|
|
mockXpSettings); \
|
|
ASSERT_EQ( \
|
|
(VAL).toJSON(*store), \
|
|
parsed.toJSON(*store)); \
|
|
ASSERT_EQ( \
|
|
(VAL), \
|
|
parsed); \
|
|
}
|
|
|
|
Derivation makeSimpleDrv(const Store & store) {
|
|
Derivation drv;
|
|
drv.name = "simple-derivation";
|
|
drv.inputSrcs = {
|
|
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"),
|
|
};
|
|
drv.inputDrvs = {
|
|
.map = {
|
|
{
|
|
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"),
|
|
{
|
|
.value = {
|
|
"cat",
|
|
"dog",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
drv.platform = "wasm-sel4";
|
|
drv.builder = "foo";
|
|
drv.args = {
|
|
"bar",
|
|
"baz",
|
|
};
|
|
drv.env = {
|
|
{
|
|
"BIG_BAD",
|
|
"WOLF",
|
|
},
|
|
};
|
|
return drv;
|
|
}
|
|
|
|
TEST_JSON(DerivationTest, simple,
|
|
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,
|
|
R"(Derive([],[("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv",["cat","dog"])],["/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"],"wasm-sel4","foo",["bar","baz"],[("BIG_BAD","WOLF")]))",
|
|
makeSimpleDrv(*store),
|
|
"simple-derivation")
|
|
|
|
Derivation makeDynDepDerivation(const Store & store) {
|
|
Derivation drv;
|
|
drv.name = "dyn-dep-derivation";
|
|
drv.inputSrcs = {
|
|
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"),
|
|
};
|
|
drv.inputDrvs = {
|
|
.map = {
|
|
{
|
|
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"),
|
|
DerivedPathMap<StringSet>::ChildNode {
|
|
.value = {
|
|
"cat",
|
|
"dog",
|
|
},
|
|
.childMap = {
|
|
{
|
|
"cat",
|
|
DerivedPathMap<StringSet>::ChildNode {
|
|
.value = {
|
|
"kitten",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"goose",
|
|
DerivedPathMap<StringSet>::ChildNode {
|
|
.value = {
|
|
"gosling",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
drv.platform = "wasm-sel4";
|
|
drv.builder = "foo";
|
|
drv.args = {
|
|
"bar",
|
|
"baz",
|
|
};
|
|
drv.env = {
|
|
{
|
|
"BIG_BAD",
|
|
"WOLF",
|
|
},
|
|
};
|
|
return drv;
|
|
}
|
|
|
|
TEST_JSON(DynDerivationTest, dynDerivationDeps,
|
|
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,
|
|
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),
|
|
"dyn-dep-derivation")
|
|
|
|
#undef TEST_JSON
|
|
#undef TEST_ATERM
|
|
|
|
}
|