mirror of
https://github.com/NixOS/nix.git
synced 2025-11-14 22:42:41 +01:00
Merge remote-tracking branch 'upstream/master' into upstream-RossComputerGuy/feat/expose-computefsclosure
This commit is contained in:
commit
a9d9b50b72
467 changed files with 9259 additions and 5039 deletions
10
src/libstore-tests/data/derived-path/multi_built_built.json
Normal file
10
src/libstore-tests/data/derived-path/multi_built_built.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"drvPath": {
|
||||
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"output": "bar"
|
||||
},
|
||||
"outputs": [
|
||||
"baz",
|
||||
"quux"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"drvPath": {
|
||||
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"output": "bar"
|
||||
},
|
||||
"outputs": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
1
src/libstore-tests/data/derived-path/multi_opaque.json
Normal file
1
src/libstore-tests/data/derived-path/multi_opaque.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"
|
||||
7
src/libstore-tests/data/derived-path/mutli_built.json
Normal file
7
src/libstore-tests/data/derived-path/mutli_built.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"outputs": [
|
||||
"bar",
|
||||
"baz"
|
||||
]
|
||||
}
|
||||
4
src/libstore-tests/data/derived-path/single_built.json
Normal file
4
src/libstore-tests/data/derived-path/single_built.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"output": "bar"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"drvPath": {
|
||||
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"output": "bar"
|
||||
},
|
||||
"output": "baz"
|
||||
}
|
||||
1
src/libstore-tests/data/derived-path/single_opaque.json
Normal file
1
src/libstore-tests/data/derived-path/single_opaque.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"
|
||||
3
src/libstore-tests/data/outputs-spec/all.json
Normal file
3
src/libstore-tests/data/outputs-spec/all.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
"*"
|
||||
]
|
||||
3
src/libstore-tests/data/outputs-spec/extended/all.json
Normal file
3
src/libstore-tests/data/outputs-spec/extended/all.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
"*"
|
||||
]
|
||||
1
src/libstore-tests/data/outputs-spec/extended/def.json
Normal file
1
src/libstore-tests/data/outputs-spec/extended/def.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
null
|
||||
3
src/libstore-tests/data/outputs-spec/extended/name.json
Normal file
3
src/libstore-tests/data/outputs-spec/extended/name.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
"a"
|
||||
]
|
||||
4
src/libstore-tests/data/outputs-spec/extended/names.json
Normal file
4
src/libstore-tests/data/outputs-spec/extended/names.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[
|
||||
"a",
|
||||
"b"
|
||||
]
|
||||
3
src/libstore-tests/data/outputs-spec/name.json
Normal file
3
src/libstore-tests/data/outputs-spec/name.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
"a"
|
||||
]
|
||||
4
src/libstore-tests/data/outputs-spec/names.json
Normal file
4
src/libstore-tests/data/outputs-spec/names.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[
|
||||
"a",
|
||||
"b"
|
||||
]
|
||||
6
src/libstore-tests/data/realisation/simple.json
Normal file
6
src/libstore-tests/data/realisation/simple.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dependentRealisations": {},
|
||||
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
|
||||
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"signatures": []
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"dependentRealisations": {
|
||||
"sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"
|
||||
},
|
||||
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
|
||||
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"signatures": []
|
||||
}
|
||||
8
src/libstore-tests/data/realisation/with-signature.json
Normal file
8
src/libstore-tests/data/realisation/with-signature.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"dependentRealisations": {},
|
||||
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
|
||||
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
|
||||
"signatures": [
|
||||
"asdfasdfasdf"
|
||||
]
|
||||
}
|
||||
|
|
@ -5,13 +5,13 @@
|
|||
#include "nix/store/derivations.hh"
|
||||
|
||||
#include "nix/store/tests/libstore.hh"
|
||||
#include "nix/util/tests/characterization.hh"
|
||||
#include "nix/util/tests/json-characterization.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
class DerivationTest : public CharacterizationTest, public LibStoreTest
|
||||
class DerivationTest : public virtual CharacterizationTest, public LibStoreTest
|
||||
{
|
||||
std::filesystem::path unitTestData = getUnitTestData() / "derivation";
|
||||
|
||||
|
|
@ -66,146 +66,183 @@ TEST_F(DynDerivationTest, BadATerm_oldVersionDynDeps)
|
|||
FormatError);
|
||||
}
|
||||
|
||||
#define TEST_JSON(FIXTURE, NAME, VAL, DRV_NAME, OUTPUT_NAME) \
|
||||
TEST_F(FIXTURE, DerivationOutput_##NAME##_from_json) \
|
||||
{ \
|
||||
readTest("output-" #NAME ".json", [&](const auto & encoded_) { \
|
||||
auto encoded = json::parse(encoded_); \
|
||||
DerivationOutput got = DerivationOutput::fromJSON(DRV_NAME, OUTPUT_NAME, encoded, mockXpSettings); \
|
||||
DerivationOutput expected{VAL}; \
|
||||
ASSERT_EQ(got, expected); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_F(FIXTURE, DerivationOutput_##NAME##_to_json) \
|
||||
{ \
|
||||
writeTest( \
|
||||
"output-" #NAME ".json", \
|
||||
[&]() -> json { return DerivationOutput{(VAL)}.toJSON((DRV_NAME), (OUTPUT_NAME)); }, \
|
||||
[](const auto & file) { return json::parse(readFile(file)); }, \
|
||||
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
||||
#define MAKE_OUTPUT_JSON_TEST_P(FIXTURE) \
|
||||
TEST_P(FIXTURE, from_json) \
|
||||
{ \
|
||||
const auto & [name, expected] = GetParam(); \
|
||||
/* Don't use readJsonTest because we want to check experimental \
|
||||
features. */ \
|
||||
readTest(Path{"output-"} + name + ".json", [&](const auto & encoded_) { \
|
||||
json j = json::parse(encoded_); \
|
||||
DerivationOutput got = DerivationOutput::fromJSON(j, mockXpSettings); \
|
||||
ASSERT_EQ(got, expected); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_P(FIXTURE, to_json) \
|
||||
{ \
|
||||
const auto & [name, value] = GetParam(); \
|
||||
writeJsonTest("output-" + name, value); \
|
||||
}
|
||||
|
||||
TEST_JSON(
|
||||
DerivationTest,
|
||||
inputAddressed,
|
||||
(DerivationOutput::InputAddressed{
|
||||
.path = store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"),
|
||||
}),
|
||||
"drv-name",
|
||||
"output-name")
|
||||
struct DerivationOutputJsonTest : DerivationTest,
|
||||
JsonCharacterizationTest<DerivationOutput>,
|
||||
::testing::WithParamInterface<std::pair<std::string_view, DerivationOutput>>
|
||||
{};
|
||||
|
||||
TEST_JSON(
|
||||
DerivationTest,
|
||||
caFixedFlat,
|
||||
(DerivationOutput::CAFixed{
|
||||
.ca =
|
||||
{
|
||||
.method = ContentAddressMethod::Raw::Flat,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
}),
|
||||
"drv-name",
|
||||
"output-name")
|
||||
MAKE_OUTPUT_JSON_TEST_P(DerivationOutputJsonTest)
|
||||
|
||||
TEST_JSON(
|
||||
DerivationTest,
|
||||
caFixedNAR,
|
||||
(DerivationOutput::CAFixed{
|
||||
.ca =
|
||||
{
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DerivationOutputJSON,
|
||||
DerivationOutputJsonTest,
|
||||
::testing::Values(
|
||||
std::pair{
|
||||
"inputAddressed",
|
||||
DerivationOutput{DerivationOutput::InputAddressed{
|
||||
.path = StorePath{"c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"},
|
||||
}},
|
||||
},
|
||||
std::pair{
|
||||
"caFixedFlat",
|
||||
DerivationOutput{DerivationOutput::CAFixed{
|
||||
.ca =
|
||||
{
|
||||
.method = ContentAddressMethod::Raw::Flat,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
}},
|
||||
},
|
||||
std::pair{
|
||||
"caFixedNAR",
|
||||
DerivationOutput{DerivationOutput::CAFixed{
|
||||
.ca =
|
||||
{
|
||||
.method = ContentAddressMethod::Raw::NixArchive,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
}},
|
||||
},
|
||||
std::pair{
|
||||
"deferred",
|
||||
DerivationOutput{DerivationOutput::Deferred{}},
|
||||
}));
|
||||
|
||||
struct DynDerivationOutputJsonTest : DynDerivationTest,
|
||||
JsonCharacterizationTest<DerivationOutput>,
|
||||
::testing::WithParamInterface<std::pair<std::string_view, DerivationOutput>>
|
||||
{};
|
||||
|
||||
MAKE_OUTPUT_JSON_TEST_P(DynDerivationOutputJsonTest);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DynDerivationOutputJSON,
|
||||
DynDerivationOutputJsonTest,
|
||||
::testing::Values(
|
||||
std::pair{
|
||||
"caFixedText",
|
||||
DerivationOutput{DerivationOutput::CAFixed{
|
||||
.ca =
|
||||
{
|
||||
.method = ContentAddressMethod::Raw::Text,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
}},
|
||||
}));
|
||||
|
||||
struct CaDerivationOutputJsonTest : CaDerivationTest,
|
||||
JsonCharacterizationTest<DerivationOutput>,
|
||||
::testing::WithParamInterface<std::pair<std::string_view, DerivationOutput>>
|
||||
{};
|
||||
|
||||
MAKE_OUTPUT_JSON_TEST_P(CaDerivationOutputJsonTest);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
CaDerivationOutputJSON,
|
||||
CaDerivationOutputJsonTest,
|
||||
::testing::Values(
|
||||
std::pair{
|
||||
"caFloating",
|
||||
DerivationOutput{DerivationOutput::CAFloating{
|
||||
.method = ContentAddressMethod::Raw::NixArchive,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
}),
|
||||
"drv-name",
|
||||
"output-name")
|
||||
.hashAlgo = HashAlgorithm::SHA256,
|
||||
}},
|
||||
}));
|
||||
|
||||
TEST_JSON(
|
||||
DynDerivationTest,
|
||||
caFixedText,
|
||||
(DerivationOutput::CAFixed{
|
||||
.ca =
|
||||
{
|
||||
.method = ContentAddressMethod::Raw::Text,
|
||||
.hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="),
|
||||
},
|
||||
}),
|
||||
"drv-name",
|
||||
"output-name")
|
||||
struct ImpureDerivationOutputJsonTest : ImpureDerivationTest,
|
||||
JsonCharacterizationTest<DerivationOutput>,
|
||||
::testing::WithParamInterface<std::pair<std::string_view, DerivationOutput>>
|
||||
{};
|
||||
|
||||
TEST_JSON(
|
||||
CaDerivationTest,
|
||||
caFloating,
|
||||
(DerivationOutput::CAFloating{
|
||||
.method = ContentAddressMethod::Raw::NixArchive,
|
||||
.hashAlgo = HashAlgorithm::SHA256,
|
||||
}),
|
||||
"drv-name",
|
||||
"output-name")
|
||||
MAKE_OUTPUT_JSON_TEST_P(ImpureDerivationOutputJsonTest);
|
||||
|
||||
TEST_JSON(DerivationTest, deferred, DerivationOutput::Deferred{}, "drv-name", "output-name")
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ImpureDerivationOutputJSON,
|
||||
ImpureDerivationOutputJsonTest,
|
||||
::testing::Values(
|
||||
std::pair{
|
||||
"impure",
|
||||
DerivationOutput{DerivationOutput::Impure{
|
||||
.method = ContentAddressMethod::Raw::NixArchive,
|
||||
.hashAlgo = HashAlgorithm::SHA256,
|
||||
}},
|
||||
}));
|
||||
|
||||
TEST_JSON(
|
||||
ImpureDerivationTest,
|
||||
impure,
|
||||
(DerivationOutput::Impure{
|
||||
.method = ContentAddressMethod::Raw::NixArchive,
|
||||
.hashAlgo = HashAlgorithm::SHA256,
|
||||
}),
|
||||
"drv-name",
|
||||
"output-name")
|
||||
#undef MAKE_OUTPUT_JSON_TEST_P
|
||||
|
||||
#undef TEST_JSON
|
||||
|
||||
#define TEST_JSON(FIXTURE, NAME, VAL) \
|
||||
TEST_F(FIXTURE, Derivation_##NAME##_from_json) \
|
||||
{ \
|
||||
readTest(#NAME ".json", [&](const auto & encoded_) { \
|
||||
auto encoded = json::parse(encoded_); \
|
||||
Derivation expected{VAL}; \
|
||||
Derivation got = Derivation::fromJSON(encoded, mockXpSettings); \
|
||||
ASSERT_EQ(got, expected); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_F(FIXTURE, Derivation_##NAME##_to_json) \
|
||||
{ \
|
||||
writeTest( \
|
||||
#NAME ".json", \
|
||||
[&]() -> json { return Derivation{VAL}.toJSON(); }, \
|
||||
[](const auto & file) { return json::parse(readFile(file)); }, \
|
||||
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
||||
#define MAKE_TEST_P(FIXTURE) \
|
||||
TEST_P(FIXTURE, from_json) \
|
||||
{ \
|
||||
const auto & drv = GetParam(); \
|
||||
/* Don't use readJsonTest because we want to check experimental \
|
||||
features. */ \
|
||||
readTest(drv.name + ".json", [&](const auto & encoded_) { \
|
||||
auto encoded = json::parse(encoded_); \
|
||||
Derivation got = Derivation::fromJSON(encoded, mockXpSettings); \
|
||||
ASSERT_EQ(got, drv); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_P(FIXTURE, to_json) \
|
||||
{ \
|
||||
const auto & drv = GetParam(); \
|
||||
writeJsonTest(drv.name, drv); \
|
||||
} \
|
||||
\
|
||||
TEST_P(FIXTURE, from_aterm) \
|
||||
{ \
|
||||
const auto & drv = GetParam(); \
|
||||
readTest(drv.name + ".drv", [&](auto encoded) { \
|
||||
auto got = parseDerivation(*store, std::move(encoded), drv.name, mockXpSettings); \
|
||||
ASSERT_EQ(got.toJSON(), drv.toJSON()); \
|
||||
ASSERT_EQ(got, drv); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_P(FIXTURE, to_aterm) \
|
||||
{ \
|
||||
const auto & drv = GetParam(); \
|
||||
writeTest(drv.name + ".drv", [&]() -> std::string { return drv.unparse(*store, false); }); \
|
||||
}
|
||||
|
||||
#define TEST_ATERM(FIXTURE, NAME, VAL, DRV_NAME) \
|
||||
TEST_F(FIXTURE, Derivation_##NAME##_from_aterm) \
|
||||
{ \
|
||||
readTest(#NAME ".drv", [&](auto encoded) { \
|
||||
Derivation expected{VAL}; \
|
||||
auto got = parseDerivation(*store, std::move(encoded), DRV_NAME, mockXpSettings); \
|
||||
ASSERT_EQ(got.toJSON(), expected.toJSON()); \
|
||||
ASSERT_EQ(got, expected); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_F(FIXTURE, Derivation_##NAME##_to_aterm) \
|
||||
{ \
|
||||
writeTest(#NAME ".drv", [&]() -> std::string { return (VAL).unparse(*store, false); }); \
|
||||
}
|
||||
struct DerivationJsonAtermTest : DerivationTest,
|
||||
JsonCharacterizationTest<Derivation>,
|
||||
::testing::WithParamInterface<Derivation>
|
||||
{};
|
||||
|
||||
Derivation makeSimpleDrv(const Store & store)
|
||||
MAKE_TEST_P(DerivationJsonAtermTest);
|
||||
|
||||
Derivation makeSimpleDrv()
|
||||
{
|
||||
Derivation drv;
|
||||
drv.name = "simple-derivation";
|
||||
drv.inputSrcs = {
|
||||
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"),
|
||||
StorePath("c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"),
|
||||
};
|
||||
drv.inputDrvs = {
|
||||
.map =
|
||||
{
|
||||
{
|
||||
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"),
|
||||
StorePath("c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"),
|
||||
{
|
||||
.value =
|
||||
{
|
||||
|
|
@ -231,22 +268,27 @@ Derivation makeSimpleDrv(const Store & store)
|
|||
return drv;
|
||||
}
|
||||
|
||||
TEST_JSON(DerivationTest, simple, makeSimpleDrv(*store))
|
||||
INSTANTIATE_TEST_SUITE_P(DerivationJSONATerm, DerivationJsonAtermTest, ::testing::Values(makeSimpleDrv()));
|
||||
|
||||
TEST_ATERM(DerivationTest, simple, makeSimpleDrv(*store), "simple-derivation")
|
||||
struct DynDerivationJsonAtermTest : DynDerivationTest,
|
||||
JsonCharacterizationTest<Derivation>,
|
||||
::testing::WithParamInterface<Derivation>
|
||||
{};
|
||||
|
||||
Derivation makeDynDepDerivation(const Store & store)
|
||||
MAKE_TEST_P(DynDerivationJsonAtermTest);
|
||||
|
||||
Derivation makeDynDepDerivation()
|
||||
{
|
||||
Derivation drv;
|
||||
drv.name = "dyn-dep-derivation";
|
||||
drv.inputSrcs = {
|
||||
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"),
|
||||
StorePath{"c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"},
|
||||
};
|
||||
drv.inputDrvs = {
|
||||
.map =
|
||||
{
|
||||
{
|
||||
store.parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"),
|
||||
StorePath{"c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"},
|
||||
DerivedPathMap<StringSet>::ChildNode{
|
||||
.value =
|
||||
{
|
||||
|
|
@ -293,11 +335,8 @@ Derivation makeDynDepDerivation(const Store & store)
|
|||
return drv;
|
||||
}
|
||||
|
||||
TEST_JSON(DynDerivationTest, dynDerivationDeps, makeDynDepDerivation(*store))
|
||||
INSTANTIATE_TEST_SUITE_P(DynDerivationJSONATerm, DynDerivationJsonAtermTest, ::testing::Values(makeDynDepDerivation()));
|
||||
|
||||
TEST_ATERM(DynDerivationTest, dynDerivationDeps, makeDynDepDerivation(*store), "dyn-dep-derivation")
|
||||
|
||||
#undef TEST_JSON
|
||||
#undef TEST_ATERM
|
||||
#undef MAKE_TEST_P
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -3,13 +3,23 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <rapidcheck/gtest.h>
|
||||
|
||||
#include "nix/util/tests/characterization.hh"
|
||||
#include "nix/store/tests/derived-path.hh"
|
||||
#include "nix/store/tests/libstore.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
class DerivedPathTest : public LibStoreTest
|
||||
{};
|
||||
class DerivedPathTest : public CharacterizationTest, public LibStoreTest
|
||||
{
|
||||
std::filesystem::path unitTestData = getUnitTestData() / "derived-path";
|
||||
|
||||
public:
|
||||
|
||||
std::filesystem::path goldenMaster(std::string_view testStem) const override
|
||||
{
|
||||
return unitTestData / testStem;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Round trip (string <-> data structure) test for
|
||||
|
|
@ -107,4 +117,90 @@ RC_GTEST_FIXTURE_PROP(DerivedPathTest, prop_round_rip, (const DerivedPath & o))
|
|||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* JSON
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
#define TEST_JSON(TYPE, NAME, VAL) \
|
||||
static const TYPE NAME = VAL; \
|
||||
\
|
||||
TEST_F(DerivedPathTest, NAME##_from_json) \
|
||||
{ \
|
||||
readTest(#NAME ".json", [&](const auto & encoded_) { \
|
||||
auto encoded = json::parse(encoded_); \
|
||||
TYPE got = static_cast<TYPE>(encoded); \
|
||||
ASSERT_EQ(got, NAME); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_F(DerivedPathTest, NAME##_to_json) \
|
||||
{ \
|
||||
writeTest( \
|
||||
#NAME ".json", \
|
||||
[&]() -> json { return static_cast<json>(NAME); }, \
|
||||
[](const auto & file) { return json::parse(readFile(file)); }, \
|
||||
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
||||
}
|
||||
|
||||
TEST_JSON(
|
||||
SingleDerivedPath, single_opaque, SingleDerivedPath::Opaque{StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"}});
|
||||
|
||||
TEST_JSON(
|
||||
SingleDerivedPath,
|
||||
single_built,
|
||||
(SingleDerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Opaque{
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"}}),
|
||||
.output = "bar",
|
||||
}));
|
||||
|
||||
TEST_JSON(
|
||||
SingleDerivedPath,
|
||||
single_built_built,
|
||||
(SingleDerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Opaque{
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"}}),
|
||||
.output = "bar",
|
||||
}),
|
||||
.output = "baz",
|
||||
}));
|
||||
|
||||
TEST_JSON(DerivedPath, multi_opaque, DerivedPath::Opaque{StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"}});
|
||||
|
||||
TEST_JSON(
|
||||
DerivedPath,
|
||||
mutli_built,
|
||||
(DerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Opaque{
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"}}),
|
||||
.outputs = OutputsSpec::Names{"bar", "baz"},
|
||||
}));
|
||||
|
||||
TEST_JSON(
|
||||
DerivedPath,
|
||||
multi_built_built,
|
||||
(DerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Opaque{
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"}}),
|
||||
.output = "bar",
|
||||
}),
|
||||
.outputs = OutputsSpec::Names{"baz", "quux"},
|
||||
}));
|
||||
|
||||
TEST_JSON(
|
||||
DerivedPath,
|
||||
multi_built_built_wildcard,
|
||||
(DerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Built{
|
||||
.drvPath = make_ref<const SingleDerivedPath>(SingleDerivedPath::Opaque{
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"}}),
|
||||
.output = "bar",
|
||||
}),
|
||||
.outputs = OutputsSpec::All{},
|
||||
}));
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
27
src/libstore-tests/dummy-store.cc
Normal file
27
src/libstore-tests/dummy-store.cc
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/dummy-store.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/realisation.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(DummyStore, realisation_read)
|
||||
{
|
||||
initLibStore(/*loadConfig=*/false);
|
||||
|
||||
auto store = [] {
|
||||
auto cfg = make_ref<DummyStoreConfig>(StoreReference::Params{});
|
||||
cfg->readOnly = false;
|
||||
return cfg->openStore();
|
||||
}();
|
||||
|
||||
auto drvHash = Hash::parseExplicitFormatUnprefixed(
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", HashAlgorithm::SHA256, HashFormat::Base16);
|
||||
|
||||
auto outputName = "foo";
|
||||
|
||||
EXPECT_EQ(store->queryRealisation({drvHash, outputName}), nullptr);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
@ -18,4 +18,20 @@ TEST(HttpBinaryCacheStore, constructConfigNoTrailingSlash)
|
|||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b");
|
||||
}
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfigWithParams)
|
||||
{
|
||||
StoreConfig::Params params{{"compression", "xz"}};
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b/", params};
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b");
|
||||
EXPECT_EQ(config.getReference().params, params);
|
||||
}
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfigWithParamsAndUrlWithParams)
|
||||
{
|
||||
StoreConfig::Params params{{"compression", "xz"}};
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b?some-param=some-value", params};
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b?some-param=some-value");
|
||||
EXPECT_EQ(config.getReference().params, params);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ gtest = dependency('gmock')
|
|||
deps_private += gtest
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'common-protocol.cc',
|
||||
|
|
@ -61,6 +60,7 @@ sources = files(
|
|||
'derivation.cc',
|
||||
'derived-path.cc',
|
||||
'downstream-placeholder.cc',
|
||||
'dummy-store.cc',
|
||||
'http-binary-cache-store.cc',
|
||||
'legacy-ssh-store.cc',
|
||||
'local-binary-cache-store.cc',
|
||||
|
|
@ -74,14 +74,16 @@ sources = files(
|
|||
'outputs-spec.cc',
|
||||
'path-info.cc',
|
||||
'path.cc',
|
||||
'realisation.cc',
|
||||
'references.cc',
|
||||
's3-binary-cache-store.cc',
|
||||
's3.cc',
|
||||
's3-url.cc',
|
||||
'serve-protocol.cc',
|
||||
'ssh-store.cc',
|
||||
'store-reference.cc',
|
||||
'uds-remote-store.cc',
|
||||
'worker-protocol.cc',
|
||||
'write-derivation.cc',
|
||||
)
|
||||
|
||||
include_dirs = [ include_directories('.') ]
|
||||
|
|
@ -103,7 +105,7 @@ this_exe = executable(
|
|||
test(
|
||||
meson.project_name(),
|
||||
this_exe,
|
||||
env : asan_test_options_env + {
|
||||
env : {
|
||||
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
|
||||
'HOME' : meson.current_build_dir() / 'test-home',
|
||||
'NIX_REMOTE' : meson.current_build_dir() / 'test-home' / 'store',
|
||||
|
|
@ -137,7 +139,7 @@ if get_option('benchmarks')
|
|||
benchmark(
|
||||
'nix-store-benchmarks',
|
||||
benchmark_exe,
|
||||
env : asan_test_options_env + {
|
||||
env : {
|
||||
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,43 @@
|
|||
#include "nix/store/tests/outputs-spec.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <rapidcheck/gtest.h>
|
||||
|
||||
#include "nix/store/tests/outputs-spec.hh"
|
||||
#include "nix/util/tests/json-characterization.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(OutputsSpec, no_empty_names)
|
||||
class OutputsSpecTest : public virtual CharacterizationTest
|
||||
{
|
||||
std::filesystem::path unitTestData = getUnitTestData() / "outputs-spec";
|
||||
|
||||
public:
|
||||
|
||||
std::filesystem::path goldenMaster(std::string_view testStem) const override
|
||||
{
|
||||
return unitTestData / testStem;
|
||||
}
|
||||
};
|
||||
|
||||
class ExtendedOutputsSpecTest : public virtual CharacterizationTest
|
||||
{
|
||||
std::filesystem::path unitTestData = getUnitTestData() / "outputs-spec" / "extended";
|
||||
|
||||
public:
|
||||
|
||||
std::filesystem::path goldenMaster(std::string_view testStem) const override
|
||||
{
|
||||
return unitTestData / testStem;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(OutputsSpecTest, no_empty_names)
|
||||
{
|
||||
ASSERT_DEATH(OutputsSpec::Names{StringSet{}}, "");
|
||||
}
|
||||
|
||||
#define TEST_DONT_PARSE(NAME, STR) \
|
||||
TEST(OutputsSpec, bad_##NAME) \
|
||||
TEST_F(OutputsSpecTest, bad_##NAME) \
|
||||
{ \
|
||||
std::optional OutputsSpecOpt = OutputsSpec::parseOpt(STR); \
|
||||
ASSERT_FALSE(OutputsSpecOpt); \
|
||||
|
|
@ -26,7 +51,7 @@ TEST_DONT_PARSE(star_second, "foo,*")
|
|||
|
||||
#undef TEST_DONT_PARSE
|
||||
|
||||
TEST(OutputsSpec, all)
|
||||
TEST_F(OutputsSpecTest, all)
|
||||
{
|
||||
std::string_view str = "*";
|
||||
OutputsSpec expected = OutputsSpec::All{};
|
||||
|
|
@ -34,7 +59,7 @@ TEST(OutputsSpec, all)
|
|||
ASSERT_EQ(expected.to_string(), str);
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, names_out)
|
||||
TEST_F(OutputsSpecTest, names_out)
|
||||
{
|
||||
std::string_view str = "out";
|
||||
OutputsSpec expected = OutputsSpec::Names{"out"};
|
||||
|
|
@ -42,7 +67,7 @@ TEST(OutputsSpec, names_out)
|
|||
ASSERT_EQ(expected.to_string(), str);
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, names_underscore)
|
||||
TEST_F(OutputsSpecTest, names_underscore)
|
||||
{
|
||||
std::string_view str = "a_b";
|
||||
OutputsSpec expected = OutputsSpec::Names{"a_b"};
|
||||
|
|
@ -50,7 +75,7 @@ TEST(OutputsSpec, names_underscore)
|
|||
ASSERT_EQ(expected.to_string(), str);
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, names_numeric)
|
||||
TEST_F(OutputsSpecTest, names_numeric)
|
||||
{
|
||||
std::string_view str = "01";
|
||||
OutputsSpec expected = OutputsSpec::Names{"01"};
|
||||
|
|
@ -58,7 +83,7 @@ TEST(OutputsSpec, names_numeric)
|
|||
ASSERT_EQ(expected.to_string(), str);
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, names_out_bin)
|
||||
TEST_F(OutputsSpecTest, names_out_bin)
|
||||
{
|
||||
OutputsSpec expected = OutputsSpec::Names{"out", "bin"};
|
||||
ASSERT_EQ(OutputsSpec::parse("out,bin"), expected);
|
||||
|
|
@ -68,32 +93,32 @@ TEST(OutputsSpec, names_out_bin)
|
|||
|
||||
#define TEST_SUBSET(X, THIS, THAT) X((OutputsSpec{THIS}).isSubsetOf(THAT));
|
||||
|
||||
TEST(OutputsSpec, subsets_all_all)
|
||||
TEST_F(OutputsSpecTest, subsets_all_all)
|
||||
{
|
||||
TEST_SUBSET(ASSERT_TRUE, OutputsSpec::All{}, OutputsSpec::All{});
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, subsets_names_all)
|
||||
TEST_F(OutputsSpecTest, subsets_names_all)
|
||||
{
|
||||
TEST_SUBSET(ASSERT_TRUE, OutputsSpec::Names{"a"}, OutputsSpec::All{});
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, subsets_names_names_eq)
|
||||
TEST_F(OutputsSpecTest, subsets_names_names_eq)
|
||||
{
|
||||
TEST_SUBSET(ASSERT_TRUE, OutputsSpec::Names{"a"}, OutputsSpec::Names{"a"});
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, subsets_names_names_noneq)
|
||||
TEST_F(OutputsSpecTest, subsets_names_names_noneq)
|
||||
{
|
||||
TEST_SUBSET(ASSERT_TRUE, OutputsSpec::Names{"a"}, (OutputsSpec::Names{"a", "b"}));
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, not_subsets_all_names)
|
||||
TEST_F(OutputsSpecTest, not_subsets_all_names)
|
||||
{
|
||||
TEST_SUBSET(ASSERT_FALSE, OutputsSpec::All{}, OutputsSpec::Names{"a"});
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, not_subsets_names_names)
|
||||
TEST_F(OutputsSpecTest, not_subsets_names_names)
|
||||
{
|
||||
TEST_SUBSET(ASSERT_FALSE, (OutputsSpec::Names{"a", "b"}), (OutputsSpec::Names{"a"}));
|
||||
}
|
||||
|
|
@ -102,22 +127,22 @@ TEST(OutputsSpec, not_subsets_names_names)
|
|||
|
||||
#define TEST_UNION(RES, THIS, THAT) ASSERT_EQ(OutputsSpec{RES}, (OutputsSpec{THIS}).union_(THAT));
|
||||
|
||||
TEST(OutputsSpec, union_all_all)
|
||||
TEST_F(OutputsSpecTest, union_all_all)
|
||||
{
|
||||
TEST_UNION(OutputsSpec::All{}, OutputsSpec::All{}, OutputsSpec::All{});
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, union_all_names)
|
||||
TEST_F(OutputsSpecTest, union_all_names)
|
||||
{
|
||||
TEST_UNION(OutputsSpec::All{}, OutputsSpec::All{}, OutputsSpec::Names{"a"});
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, union_names_all)
|
||||
TEST_F(OutputsSpecTest, union_names_all)
|
||||
{
|
||||
TEST_UNION(OutputsSpec::All{}, OutputsSpec::Names{"a"}, OutputsSpec::All{});
|
||||
}
|
||||
|
||||
TEST(OutputsSpec, union_names_names)
|
||||
TEST_F(OutputsSpecTest, union_names_names)
|
||||
{
|
||||
TEST_UNION((OutputsSpec::Names{"a", "b"}), OutputsSpec::Names{"a"}, OutputsSpec::Names{"b"});
|
||||
}
|
||||
|
|
@ -125,7 +150,7 @@ TEST(OutputsSpec, union_names_names)
|
|||
#undef TEST_UNION
|
||||
|
||||
#define TEST_DONT_PARSE(NAME, STR) \
|
||||
TEST(ExtendedOutputsSpec, bad_##NAME) \
|
||||
TEST_F(ExtendedOutputsSpecTest, bad_##NAME) \
|
||||
{ \
|
||||
std::optional extendedOutputsSpecOpt = ExtendedOutputsSpec::parseOpt(STR); \
|
||||
ASSERT_FALSE(extendedOutputsSpecOpt); \
|
||||
|
|
@ -140,7 +165,7 @@ TEST_DONT_PARSE(star_second, "^foo,*")
|
|||
|
||||
#undef TEST_DONT_PARSE
|
||||
|
||||
TEST(ExtendedOutputsSpec, default)
|
||||
TEST_F(ExtendedOutputsSpecTest, default)
|
||||
{
|
||||
std::string_view str = "foo";
|
||||
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(str);
|
||||
|
|
@ -150,7 +175,7 @@ TEST(ExtendedOutputsSpec, default)
|
|||
ASSERT_EQ(std::string{prefix} + expected.to_string(), str);
|
||||
}
|
||||
|
||||
TEST(ExtendedOutputsSpec, all)
|
||||
TEST_F(ExtendedOutputsSpecTest, all)
|
||||
{
|
||||
std::string_view str = "foo^*";
|
||||
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(str);
|
||||
|
|
@ -160,7 +185,7 @@ TEST(ExtendedOutputsSpec, all)
|
|||
ASSERT_EQ(std::string{prefix} + expected.to_string(), str);
|
||||
}
|
||||
|
||||
TEST(ExtendedOutputsSpec, out)
|
||||
TEST_F(ExtendedOutputsSpecTest, out)
|
||||
{
|
||||
std::string_view str = "foo^out";
|
||||
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(str);
|
||||
|
|
@ -170,7 +195,7 @@ TEST(ExtendedOutputsSpec, out)
|
|||
ASSERT_EQ(std::string{prefix} + expected.to_string(), str);
|
||||
}
|
||||
|
||||
TEST(ExtendedOutputsSpec, out_bin)
|
||||
TEST_F(ExtendedOutputsSpecTest, out_bin)
|
||||
{
|
||||
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse("foo^out,bin");
|
||||
ASSERT_EQ(prefix, "foo");
|
||||
|
|
@ -179,7 +204,7 @@ TEST(ExtendedOutputsSpec, out_bin)
|
|||
ASSERT_EQ(std::string{prefix} + expected.to_string(), "foo^bin,out");
|
||||
}
|
||||
|
||||
TEST(ExtendedOutputsSpec, many_carrot)
|
||||
TEST_F(ExtendedOutputsSpecTest, many_carrot)
|
||||
{
|
||||
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse("foo^bar^out,bin");
|
||||
ASSERT_EQ(prefix, "foo^bar");
|
||||
|
|
@ -188,28 +213,49 @@ TEST(ExtendedOutputsSpec, many_carrot)
|
|||
ASSERT_EQ(std::string{prefix} + expected.to_string(), "foo^bar^bin,out");
|
||||
}
|
||||
|
||||
#define TEST_JSON(TYPE, NAME, STR, VAL) \
|
||||
\
|
||||
TEST(TYPE, NAME##_to_json) \
|
||||
{ \
|
||||
using nlohmann::literals::operator"" _json; \
|
||||
ASSERT_EQ(STR##_json, ((nlohmann::json) TYPE{VAL})); \
|
||||
} \
|
||||
\
|
||||
TEST(TYPE, NAME##_from_json) \
|
||||
{ \
|
||||
using nlohmann::literals::operator"" _json; \
|
||||
ASSERT_EQ(TYPE{VAL}, (STR##_json).get<TYPE>()); \
|
||||
#define MAKE_TEST_P(FIXTURE, TYPE) \
|
||||
TEST_P(FIXTURE, from_json) \
|
||||
{ \
|
||||
const auto & [name, value] = GetParam(); \
|
||||
readJsonTest(name, value); \
|
||||
} \
|
||||
\
|
||||
TEST_P(FIXTURE, to_json) \
|
||||
{ \
|
||||
const auto & [name, value] = GetParam(); \
|
||||
writeJsonTest(name, value); \
|
||||
}
|
||||
|
||||
TEST_JSON(OutputsSpec, all, R"(["*"])", OutputsSpec::All{})
|
||||
TEST_JSON(OutputsSpec, name, R"(["a"])", OutputsSpec::Names{"a"})
|
||||
TEST_JSON(OutputsSpec, names, R"(["a","b"])", (OutputsSpec::Names{"a", "b"}))
|
||||
struct OutputsSpecJsonTest : OutputsSpecTest,
|
||||
JsonCharacterizationTest<OutputsSpec>,
|
||||
::testing::WithParamInterface<std::pair<std::string_view, OutputsSpec>>
|
||||
{};
|
||||
|
||||
TEST_JSON(ExtendedOutputsSpec, def, R"(null)", ExtendedOutputsSpec::Default{})
|
||||
TEST_JSON(ExtendedOutputsSpec, all, R"(["*"])", ExtendedOutputsSpec::Explicit{OutputsSpec::All{}})
|
||||
TEST_JSON(ExtendedOutputsSpec, name, R"(["a"])", ExtendedOutputsSpec::Explicit{OutputsSpec::Names{"a"}})
|
||||
TEST_JSON(ExtendedOutputsSpec, names, R"(["a","b"])", (ExtendedOutputsSpec::Explicit{OutputsSpec::Names{"a", "b"}}))
|
||||
MAKE_TEST_P(OutputsSpecJsonTest, OutputsSpec);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OutputsSpecJSON,
|
||||
OutputsSpecJsonTest,
|
||||
::testing::Values(
|
||||
std::pair{"all", OutputsSpec{OutputsSpec::All{}}},
|
||||
std::pair{"name", OutputsSpec{OutputsSpec::Names{"a"}}},
|
||||
std::pair{"names", OutputsSpec{OutputsSpec::Names{"a", "b"}}}));
|
||||
|
||||
struct ExtendedOutputsSpecJsonTest : ExtendedOutputsSpecTest,
|
||||
JsonCharacterizationTest<ExtendedOutputsSpec>,
|
||||
::testing::WithParamInterface<std::pair<std::string_view, ExtendedOutputsSpec>>
|
||||
{};
|
||||
|
||||
MAKE_TEST_P(ExtendedOutputsSpecJsonTest, ExtendedOutputsSpec);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExtendedOutputsSpecJSON,
|
||||
ExtendedOutputsSpecJsonTest,
|
||||
::testing::Values(
|
||||
std::pair{"def", ExtendedOutputsSpec{ExtendedOutputsSpec::Default{}}},
|
||||
std::pair{"all", ExtendedOutputsSpec{ExtendedOutputsSpec::Explicit{OutputsSpec::All{}}}},
|
||||
std::pair{"name", ExtendedOutputsSpec{ExtendedOutputsSpec::Explicit{OutputsSpec::Names{"a"}}}},
|
||||
std::pair{"names", ExtendedOutputsSpec{ExtendedOutputsSpec::Explicit{OutputsSpec::Names{"a", "b"}}}}));
|
||||
|
||||
#undef TEST_JSON
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ mkMesonExecutable (finalAttrs: {
|
|||
}
|
||||
(
|
||||
''
|
||||
export ASAN_OPTIONS=abort_on_error=1:print_summary=1:detect_leaks=0
|
||||
export _NIX_TEST_UNIT_DATA=${data + "/src/libstore-tests/data"}
|
||||
export NIX_REMOTE=$HOME/store
|
||||
${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include "nix/store/path-regex.hh"
|
||||
#include "nix/store/store-api.hh"
|
||||
|
||||
#include "nix/util/tests/characterization.hh"
|
||||
#include "nix/util/tests/json-characterization.hh"
|
||||
#include "nix/store/tests/libstore.hh"
|
||||
#include "nix/store/tests/path.hh"
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ namespace nix {
|
|||
#define STORE_DIR "/nix/store/"
|
||||
#define HASH_PART "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q"
|
||||
|
||||
class StorePathTest : public CharacterizationTest, public LibStoreTest
|
||||
class StorePathTest : public virtual CharacterizationTest, public LibStoreTest
|
||||
{
|
||||
std::filesystem::path unitTestData = getUnitTestData() / "store-path";
|
||||
|
||||
|
|
@ -149,27 +149,30 @@ RC_GTEST_FIXTURE_PROP(StorePathTest, prop_check_regex_eq_parse, ())
|
|||
|
||||
using nlohmann::json;
|
||||
|
||||
#define TEST_JSON(FIXTURE, NAME, VAL) \
|
||||
static const StorePath NAME = VAL; \
|
||||
\
|
||||
TEST_F(FIXTURE, NAME##_from_json) \
|
||||
{ \
|
||||
readTest(#NAME ".json", [&](const auto & encoded_) { \
|
||||
auto encoded = json::parse(encoded_); \
|
||||
StorePath got = static_cast<StorePath>(encoded); \
|
||||
ASSERT_EQ(got, NAME); \
|
||||
}); \
|
||||
} \
|
||||
\
|
||||
TEST_F(FIXTURE, NAME##_to_json) \
|
||||
{ \
|
||||
writeTest( \
|
||||
#NAME ".json", \
|
||||
[&]() -> json { return static_cast<json>(NAME); }, \
|
||||
[](const auto & file) { return json::parse(readFile(file)); }, \
|
||||
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
||||
}
|
||||
struct StorePathJsonTest : StorePathTest,
|
||||
JsonCharacterizationTest<StorePath>,
|
||||
::testing::WithParamInterface<std::pair<std::string_view, StorePath>>
|
||||
{};
|
||||
|
||||
TEST_JSON(StorePathTest, simple, StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"});
|
||||
TEST_P(StorePathJsonTest, from_json)
|
||||
{
|
||||
auto & [name, expected] = GetParam();
|
||||
readJsonTest(name, expected);
|
||||
}
|
||||
|
||||
TEST_P(StorePathJsonTest, to_json)
|
||||
{
|
||||
auto & [name, value] = GetParam();
|
||||
writeJsonTest(name, value);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
StorePathJSON,
|
||||
StorePathJsonTest,
|
||||
::testing::Values(
|
||||
std::pair{
|
||||
"simple",
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
|
||||
}));
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
97
src/libstore-tests/realisation.cc
Normal file
97
src/libstore-tests/realisation.cc
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#include <regex>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <rapidcheck/gtest.h>
|
||||
|
||||
#include "nix/store/store-api.hh"
|
||||
|
||||
#include "nix/util/tests/json-characterization.hh"
|
||||
#include "nix/store/tests/libstore.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
class RealisationTest : public JsonCharacterizationTest<Realisation>, public LibStoreTest
|
||||
{
|
||||
std::filesystem::path unitTestData = getUnitTestData() / "realisation";
|
||||
|
||||
public:
|
||||
|
||||
std::filesystem::path goldenMaster(std::string_view testStem) const override
|
||||
{
|
||||
return unitTestData / testStem;
|
||||
}
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* JSON
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
struct RealisationJsonTest : RealisationTest, ::testing::WithParamInterface<std::pair<std::string_view, Realisation>>
|
||||
{};
|
||||
|
||||
TEST_P(RealisationJsonTest, from_json)
|
||||
{
|
||||
const auto & [name, expected] = GetParam();
|
||||
readJsonTest(name, expected);
|
||||
}
|
||||
|
||||
TEST_P(RealisationJsonTest, to_json)
|
||||
{
|
||||
const auto & [name, value] = GetParam();
|
||||
writeJsonTest(name, value);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
RealisationJSON,
|
||||
RealisationJsonTest,
|
||||
([] {
|
||||
Realisation simple{
|
||||
|
||||
.id =
|
||||
{
|
||||
.drvHash = Hash::parseExplicitFormatUnprefixed(
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
||||
HashAlgorithm::SHA256,
|
||||
HashFormat::Base16),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
|
||||
};
|
||||
return ::testing::Values(
|
||||
std::pair{
|
||||
"simple",
|
||||
simple,
|
||||
},
|
||||
std::pair{
|
||||
"with-signature",
|
||||
[&] {
|
||||
auto r = simple;
|
||||
// FIXME actually sign properly
|
||||
r.signatures = {"asdfasdfasdf"};
|
||||
return r;
|
||||
}()},
|
||||
std::pair{
|
||||
"with-dependent-realisations",
|
||||
[&] {
|
||||
auto r = simple;
|
||||
r.dependentRealisations = {{
|
||||
{
|
||||
.drvHash = Hash::parseExplicitFormatUnprefixed(
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
||||
HashAlgorithm::SHA256,
|
||||
HashFormat::Base16),
|
||||
.outputName = "foo",
|
||||
},
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
|
||||
}};
|
||||
return r;
|
||||
}(),
|
||||
});
|
||||
}
|
||||
|
||||
()));
|
||||
|
||||
} // namespace nix
|
||||
|
|
@ -15,4 +15,131 @@ TEST(S3BinaryCacheStore, constructConfig)
|
|||
|
||||
} // namespace nix
|
||||
|
||||
#elif NIX_WITH_CURL_S3
|
||||
|
||||
# include "nix/store/http-binary-cache-store.hh"
|
||||
# include "nix/store/filetransfer.hh"
|
||||
# include "nix/store/s3-url.hh"
|
||||
|
||||
# include <gtest/gtest.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(S3BinaryCacheStore, constructConfig)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "foobar", {}};
|
||||
|
||||
// The bucket name is stored as the host part of the authority in cacheUri
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
(ParsedURL{
|
||||
.scheme = "s3",
|
||||
.authority = ParsedURL::Authority{.host = "foobar"},
|
||||
}));
|
||||
}
|
||||
|
||||
TEST(S3BinaryCacheStore, constructConfigWithRegion)
|
||||
{
|
||||
Store::Config::Params params{{"region", "eu-west-1"}};
|
||||
S3BinaryCacheStoreConfig config{"s3", "my-bucket", params};
|
||||
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
(ParsedURL{
|
||||
.scheme = "s3",
|
||||
.authority = ParsedURL::Authority{.host = "my-bucket"},
|
||||
.query = (StringMap) {{"region", "eu-west-1"}},
|
||||
}));
|
||||
EXPECT_EQ(config.region.get(), "eu-west-1");
|
||||
}
|
||||
|
||||
TEST(S3BinaryCacheStore, defaultSettings)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "test-bucket", {}};
|
||||
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
(ParsedURL{
|
||||
.scheme = "s3",
|
||||
.authority = ParsedURL::Authority{.host = "test-bucket"},
|
||||
}));
|
||||
|
||||
// Check default values
|
||||
EXPECT_EQ(config.region.get(), "us-east-1");
|
||||
EXPECT_EQ(config.profile.get(), "default");
|
||||
EXPECT_EQ(config.scheme.get(), "https");
|
||||
EXPECT_EQ(config.endpoint.get(), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that S3BinaryCacheStore properly preserves S3-specific parameters
|
||||
*/
|
||||
TEST(S3BinaryCacheStore, s3StoreConfigPreservesParameters)
|
||||
{
|
||||
StringMap params;
|
||||
params["region"] = "eu-west-1";
|
||||
params["endpoint"] = "custom.s3.com";
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
|
||||
// The config should preserve S3-specific parameters
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
(ParsedURL{
|
||||
.scheme = "s3",
|
||||
.authority = ParsedURL::Authority{.host = "test-bucket"},
|
||||
.query = (StringMap) {{"region", "eu-west-1"}, {"endpoint", "custom.s3.com"}},
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that S3 store scheme is properly registered
|
||||
*/
|
||||
TEST(S3BinaryCacheStore, s3SchemeRegistration)
|
||||
{
|
||||
auto schemes = S3BinaryCacheStoreConfig::uriSchemes();
|
||||
EXPECT_TRUE(schemes.count("s3") > 0) << "S3 scheme should be supported";
|
||||
|
||||
// Verify HttpBinaryCacheStoreConfig doesn't directly list S3
|
||||
auto httpSchemes = HttpBinaryCacheStoreConfig::uriSchemes();
|
||||
EXPECT_FALSE(httpSchemes.count("s3") > 0) << "HTTP store shouldn't directly list S3 scheme";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that only S3-specific parameters are preserved in cacheUri,
|
||||
* while non-S3 store parameters are not propagated to the URL
|
||||
*/
|
||||
TEST(S3BinaryCacheStore, parameterFiltering)
|
||||
{
|
||||
StringMap params;
|
||||
params["region"] = "eu-west-1";
|
||||
params["endpoint"] = "minio.local";
|
||||
params["want-mass-query"] = "true"; // Non-S3 store parameter
|
||||
params["priority"] = "10"; // Non-S3 store parameter
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
|
||||
// Only S3-specific params should be in cacheUri.query
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
(ParsedURL{
|
||||
.scheme = "s3",
|
||||
.authority = ParsedURL::Authority{.host = "test-bucket"},
|
||||
.query = (StringMap) {{"region", "eu-west-1"}, {"endpoint", "minio.local"}},
|
||||
}));
|
||||
|
||||
// But the non-S3 params should still be set on the config
|
||||
EXPECT_EQ(config.wantMassQuery.get(), true);
|
||||
EXPECT_EQ(config.priority.get(), 10);
|
||||
|
||||
// And all params (S3 and non-S3) should be returned by getReference()
|
||||
auto ref = config.getReference();
|
||||
EXPECT_EQ(ref.params["region"], "eu-west-1");
|
||||
EXPECT_EQ(ref.params["endpoint"], "minio.local");
|
||||
EXPECT_EQ(ref.params["want-mass-query"], "true");
|
||||
EXPECT_EQ(ref.params["priority"], "10");
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
#include "nix/store/s3.hh"
|
||||
#include "nix/store/s3-url.hh"
|
||||
#include "nix/util/tests/gmock-matchers.hh"
|
||||
|
||||
#if NIX_WITH_S3_SUPPORT
|
||||
#if NIX_WITH_S3_SUPPORT || NIX_WITH_CURL_S3
|
||||
|
||||
# include <gtest/gtest.h>
|
||||
# include <gmock/gmock.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
// =============================================================================
|
||||
// ParsedS3URL Tests
|
||||
// =============================================================================
|
||||
|
||||
struct ParsedS3URLTestCase
|
||||
{
|
||||
std::string url;
|
||||
|
|
@ -86,18 +90,41 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
}),
|
||||
[](const ::testing::TestParamInfo<ParsedS3URLTestCase> & info) { return info.param.description; });
|
||||
|
||||
TEST(InvalidParsedS3URLTest, parseS3URLErrors)
|
||||
// Parameterized test for invalid S3 URLs
|
||||
struct InvalidS3URLTestCase
|
||||
{
|
||||
auto invalidBucketMatcher = ::testing::ThrowsMessage<BadURL>(
|
||||
testing::HasSubstrIgnoreANSIMatcher("error: URI has a missing or invalid bucket name"));
|
||||
std::string url;
|
||||
std::string expectedErrorSubstring;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
/* Empty bucket (authority) */
|
||||
ASSERT_THAT([]() { ParsedS3URL::parse(parseURL("s3:///key")); }, invalidBucketMatcher);
|
||||
/* Invalid bucket name */
|
||||
ASSERT_THAT([]() { ParsedS3URL::parse(parseURL("s3://127.0.0.1")); }, invalidBucketMatcher);
|
||||
class InvalidParsedS3URLTest : public ::testing::WithParamInterface<InvalidS3URLTestCase>, public ::testing::Test
|
||||
{};
|
||||
|
||||
TEST_P(InvalidParsedS3URLTest, parseS3URLErrors)
|
||||
{
|
||||
const auto & testCase = GetParam();
|
||||
|
||||
ASSERT_THAT(
|
||||
[&testCase]() { ParsedS3URL::parse(parseURL(testCase.url)); },
|
||||
::testing::ThrowsMessage<BadURL>(testing::HasSubstrIgnoreANSIMatcher(testCase.expectedErrorSubstring)));
|
||||
}
|
||||
|
||||
// Parameterized test for s3ToHttpsUrl conversion
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
InvalidUrls,
|
||||
InvalidParsedS3URLTest,
|
||||
::testing::Values(
|
||||
InvalidS3URLTestCase{"s3:///key", "error: URI has a missing or invalid bucket name", "empty_bucket"},
|
||||
InvalidS3URLTestCase{"s3://127.0.0.1", "error: URI has a missing or invalid bucket name", "ip_address_bucket"},
|
||||
InvalidS3URLTestCase{"s3://bucket with spaces/key", "is not a valid URL", "bucket_with_spaces"},
|
||||
InvalidS3URLTestCase{"s3://", "error: URI has a missing or invalid bucket name", "completely_empty"},
|
||||
InvalidS3URLTestCase{"s3://bucket", "error: URI has a missing or invalid key", "missing_key"}),
|
||||
[](const ::testing::TestParamInfo<InvalidS3URLTestCase> & info) { return info.param.description; });
|
||||
|
||||
// =============================================================================
|
||||
// S3 URL to HTTPS Conversion Tests
|
||||
// =============================================================================
|
||||
|
||||
struct S3ToHttpsConversionTestCase
|
||||
{
|
||||
ParsedS3URL input;
|
||||
|
|
@ -127,17 +127,17 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
VERSIONED_CHARACTERIZATION_TEST(ServeProtoTest, buildResult_2_2, "build-result-2.2", 2 << 8 | 2, ({
|
||||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<BuildResult, BuildResult, BuildResult> t{
|
||||
BuildResult{
|
||||
.status = BuildResult::OutputRejected,
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::NotDeterministic,
|
||||
}}},
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::Built,
|
||||
},
|
||||
}}},
|
||||
BuildResult{.inner{BuildResult::Success{
|
||||
.status = BuildResult::Success::Built,
|
||||
}}},
|
||||
};
|
||||
t;
|
||||
}))
|
||||
|
|
@ -145,20 +145,24 @@ VERSIONED_CHARACTERIZATION_TEST(ServeProtoTest, buildResult_2_2, "build-result-2
|
|||
VERSIONED_CHARACTERIZATION_TEST(ServeProtoTest, buildResult_2_3, "build-result-2.3", 2 << 8 | 3, ({
|
||||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<BuildResult, BuildResult, BuildResult> t{
|
||||
BuildResult{
|
||||
.status = BuildResult::OutputRejected,
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
}}},
|
||||
BuildResult{
|
||||
.status = BuildResult::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.isNonDeterministic = true,
|
||||
}},
|
||||
.timesBuilt = 3,
|
||||
.isNonDeterministic = true,
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::Built,
|
||||
.inner{BuildResult::Success{
|
||||
.status = BuildResult::Success::Built,
|
||||
}},
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
},
|
||||
|
|
@ -170,48 +174,52 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
ServeProtoTest, buildResult_2_6, "build-result-2.6", 2 << 8 | 6, ({
|
||||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<BuildResult, BuildResult, BuildResult> t{
|
||||
BuildResult{
|
||||
.status = BuildResult::OutputRejected,
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
}}},
|
||||
BuildResult{
|
||||
.status = BuildResult::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.isNonDeterministic = true,
|
||||
}},
|
||||
.timesBuilt = 3,
|
||||
.isNonDeterministic = true,
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::Built,
|
||||
.inner{BuildResult::Success{
|
||||
.status = BuildResult::Success::Built,
|
||||
.builtOutputs =
|
||||
{
|
||||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
.timesBuilt = 1,
|
||||
.builtOutputs =
|
||||
{
|
||||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
#if 0
|
||||
|
|
|
|||
|
|
@ -22,4 +22,24 @@ TEST(UDSRemoteStore, constructConfig_to_string)
|
|||
EXPECT_EQ(config.getReference().to_string(), "daemon");
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfigWithParams)
|
||||
{
|
||||
StoreConfig::Params params{{"max-connections", "1"}};
|
||||
UDSRemoteStoreConfig config{"unix", "/tmp/socket", params};
|
||||
auto storeReference = config.getReference();
|
||||
EXPECT_EQ(storeReference.to_string(), "unix:///tmp/socket?max-connections=1");
|
||||
EXPECT_EQ(storeReference.render(/*withParams=*/false), "unix:///tmp/socket");
|
||||
EXPECT_EQ(storeReference.params, params);
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfigWithParamsNoPath)
|
||||
{
|
||||
StoreConfig::Params params{{"max-connections", "1"}};
|
||||
UDSRemoteStoreConfig config{"unix", "", params};
|
||||
auto storeReference = config.getReference();
|
||||
EXPECT_EQ(storeReference.to_string(), "daemon?max-connections=1");
|
||||
EXPECT_EQ(storeReference.render(/*withParams=*/false), "daemon");
|
||||
EXPECT_EQ(storeReference.params, params);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -180,17 +180,17 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
VERSIONED_CHARACTERIZATION_TEST(WorkerProtoTest, buildResult_1_27, "build-result-1.27", 1 << 8 | 27, ({
|
||||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<BuildResult, BuildResult, BuildResult> t{
|
||||
BuildResult{
|
||||
.status = BuildResult::OutputRejected,
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::NotDeterministic,
|
||||
}}},
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::Built,
|
||||
},
|
||||
}}},
|
||||
BuildResult{.inner{BuildResult::Success{
|
||||
.status = BuildResult::Success::Built,
|
||||
}}},
|
||||
};
|
||||
t;
|
||||
}))
|
||||
|
|
@ -199,16 +199,16 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
WorkerProtoTest, buildResult_1_28, "build-result-1.28", 1 << 8 | 28, ({
|
||||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<BuildResult, BuildResult, BuildResult> t{
|
||||
BuildResult{
|
||||
.status = BuildResult::OutputRejected,
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::NotDeterministic,
|
||||
}}},
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::Built,
|
||||
}}},
|
||||
BuildResult{.inner{BuildResult::Success{
|
||||
.status = BuildResult::Success::Built,
|
||||
.builtOutputs =
|
||||
{
|
||||
{
|
||||
|
|
@ -236,7 +236,7 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
};
|
||||
t;
|
||||
}))
|
||||
|
|
@ -245,48 +245,52 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
WorkerProtoTest, buildResult_1_29, "build-result-1.29", 1 << 8 | 29, ({
|
||||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<BuildResult, BuildResult, BuildResult> t{
|
||||
BuildResult{
|
||||
.status = BuildResult::OutputRejected,
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
}}},
|
||||
BuildResult{
|
||||
.status = BuildResult::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.isNonDeterministic = true,
|
||||
}},
|
||||
.timesBuilt = 3,
|
||||
.isNonDeterministic = true,
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::Built,
|
||||
.inner{BuildResult::Success{
|
||||
.status = BuildResult::Success::Built,
|
||||
.builtOutputs =
|
||||
{
|
||||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
.timesBuilt = 1,
|
||||
.builtOutputs =
|
||||
{
|
||||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
},
|
||||
|
|
@ -298,48 +302,52 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
WorkerProtoTest, buildResult_1_37, "build-result-1.37", 1 << 8 | 37, ({
|
||||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<BuildResult, BuildResult, BuildResult> t{
|
||||
BuildResult{
|
||||
.status = BuildResult::OutputRejected,
|
||||
BuildResult{.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
}}},
|
||||
BuildResult{
|
||||
.status = BuildResult::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.inner{BuildResult::Failure{
|
||||
.status = BuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.isNonDeterministic = true,
|
||||
}},
|
||||
.timesBuilt = 3,
|
||||
.isNonDeterministic = true,
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
},
|
||||
BuildResult{
|
||||
.status = BuildResult::Built,
|
||||
.inner{BuildResult::Success{
|
||||
.status = BuildResult::Success::Built,
|
||||
.builtOutputs =
|
||||
{
|
||||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
.timesBuilt = 1,
|
||||
.builtOutputs =
|
||||
{
|
||||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
.cpuUser = std::chrono::microseconds(500s),
|
||||
|
|
@ -353,10 +361,10 @@ VERSIONED_CHARACTERIZATION_TEST(WorkerProtoTest, keyedBuildResult_1_29, "keyed-b
|
|||
using namespace std::literals::chrono_literals;
|
||||
std::tuple<KeyedBuildResult, KeyedBuildResult /*, KeyedBuildResult*/> t{
|
||||
KeyedBuildResult{
|
||||
{
|
||||
.status = KeyedBuildResult::OutputRejected,
|
||||
{.inner{BuildResult::Failure{
|
||||
.status = KeyedBuildResult::Failure::OutputRejected,
|
||||
.errorMsg = "no idea why",
|
||||
},
|
||||
}}},
|
||||
/* .path = */
|
||||
DerivedPath::Opaque{
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-xxx"},
|
||||
|
|
@ -364,10 +372,12 @@ VERSIONED_CHARACTERIZATION_TEST(WorkerProtoTest, keyedBuildResult_1_29, "keyed-b
|
|||
},
|
||||
KeyedBuildResult{
|
||||
{
|
||||
.status = KeyedBuildResult::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.inner{BuildResult::Failure{
|
||||
.status = KeyedBuildResult::Failure::NotDeterministic,
|
||||
.errorMsg = "no idea why",
|
||||
.isNonDeterministic = true,
|
||||
}},
|
||||
.timesBuilt = 3,
|
||||
.isNonDeterministic = true,
|
||||
.startTime = 30,
|
||||
.stopTime = 50,
|
||||
},
|
||||
|
|
|
|||
57
src/libstore-tests/write-derivation.cc
Normal file
57
src/libstore-tests/write-derivation.cc
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "nix/util/tests/gmock-matchers.hh"
|
||||
#include "nix/store/derivations.hh"
|
||||
#include "nix/store/dummy-store-impl.hh"
|
||||
#include "nix/store/tests/libstore.hh"
|
||||
|
||||
namespace nix {
|
||||
namespace {
|
||||
|
||||
class WriteDerivationTest : public LibStoreTest
|
||||
{
|
||||
protected:
|
||||
WriteDerivationTest(ref<DummyStoreConfig> config_)
|
||||
: LibStoreTest(config_->openDummyStore())
|
||||
, config(std::move(config_))
|
||||
{
|
||||
config->readOnly = false;
|
||||
}
|
||||
|
||||
WriteDerivationTest()
|
||||
: WriteDerivationTest(make_ref<DummyStoreConfig>(DummyStoreConfig::Params{}))
|
||||
{
|
||||
}
|
||||
|
||||
ref<DummyStoreConfig> config;
|
||||
};
|
||||
|
||||
static Derivation makeSimpleDrv()
|
||||
{
|
||||
Derivation drv;
|
||||
drv.name = "simple-derivation";
|
||||
drv.platform = "system";
|
||||
drv.builder = "foo";
|
||||
drv.args = {"bar", "baz"};
|
||||
drv.env = StringPairs{{"BIG_BAD", "WOLF"}};
|
||||
return drv;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(WriteDerivationTest, addToStoreFromDumpCalledOnce)
|
||||
{
|
||||
auto drv = makeSimpleDrv();
|
||||
|
||||
auto path1 = writeDerivation(*store, drv, NoRepair);
|
||||
config->readOnly = true;
|
||||
auto path2 = writeDerivation(*store, drv, NoRepair);
|
||||
EXPECT_EQ(path1, path2);
|
||||
EXPECT_THAT(
|
||||
[&] { writeDerivation(*store, drv, Repair); },
|
||||
::testing::ThrowsMessage<Error>(testing::HasSubstrIgnoreANSIMatcher(
|
||||
"operation 'addToStoreFromDump' is not supported by store 'dummy://'")));
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
Loading…
Add table
Add a link
Reference in a new issue