From cc82d6e3605d428a93cdd7063edc30034816df6f Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Sun, 2 Aug 2020 13:28:28 -0400 Subject: test(3p/nix): Add test for derivation parse/serialize Add a rapidcheck test covering roundtrip parse and serialize for Nix derivations. This covers a bug we discovered in ef54f5d which broke this roundtrip. Change-Id: I72d140334b5f24f79e82e34f98609c695dbfbf93 Reviewed-on: https://cl.tvl.fyi/c/depot/+/1582 Tested-by: BuildkiteCI Reviewed-by: kanepyork --- third_party/nix/src/libstore/derivations.cc | 2 +- third_party/nix/src/libstore/derivations.hh | 4 +- third_party/nix/src/tests/CMakeLists.txt | 11 +++ third_party/nix/src/tests/derivations_test.cc | 106 ++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 third_party/nix/src/tests/derivations_test.cc (limited to 'third_party') diff --git a/third_party/nix/src/libstore/derivations.cc b/third_party/nix/src/libstore/derivations.cc index 29f929270e..8a50f3c85b 100644 --- a/third_party/nix/src/libstore/derivations.cc +++ b/third_party/nix/src/libstore/derivations.cc @@ -144,7 +144,7 @@ static StringSet parseStrings(std::istream& str, bool arePaths) { return res; } -static Derivation parseDerivation(const std::string& s) { +Derivation parseDerivation(const std::string& s) { Derivation drv; istringstream_nocopy str(s); expect(str, "Derive(["); diff --git a/third_party/nix/src/libstore/derivations.hh b/third_party/nix/src/libstore/derivations.hh index 21ef71372e..38877780e0 100644 --- a/third_party/nix/src/libstore/derivations.hh +++ b/third_party/nix/src/libstore/derivations.hh @@ -16,10 +16,10 @@ const std::string drvExtension = ".drv"; struct DerivationOutput { Path path; + // TODO(grfn): make these two fields a Hash std::string hashAlgo; /* hash used for expected hash computation */ std::string hash; /* expected hash, may be null */ DerivationOutput() {} - // TODO(grfn): Make explicit DerivationOutput(Path path, std::string hashAlgo, std::string hash) { this->path = path; this->hashAlgo = hashAlgo; @@ -92,6 +92,8 @@ Path writeDerivation(const ref& store, const Derivation& drv, /* Read a derivation from a file. */ Derivation readDerivation(const Path& drvPath); +Derivation parseDerivation(const std::string& s); + /* Check whether a file name ends with the extension for derivations. */ bool isDerivation(const std::string& fileName); diff --git a/third_party/nix/src/tests/CMakeLists.txt b/third_party/nix/src/tests/CMakeLists.txt index 724a7a95b5..33f4f774a6 100644 --- a/third_party/nix/src/tests/CMakeLists.txt +++ b/third_party/nix/src/tests/CMakeLists.txt @@ -11,6 +11,17 @@ target_link_libraries(attr-set gtest_discover_tests(attr-set) +add_executable(derivations_test derivations_test.cc) +target_link_libraries(derivations_test + nixexpr + nixstore + rapidcheck + rapidcheck_gtest + GTest::gtest_main +) + +gtest_discover_tests(derivations_test) + add_executable(hash_test hash_test.cc) target_link_libraries(hash_test nixutil diff --git a/third_party/nix/src/tests/derivations_test.cc b/third_party/nix/src/tests/derivations_test.cc new file mode 100644 index 0000000000..e026fbe3b1 --- /dev/null +++ b/third_party/nix/src/tests/derivations_test.cc @@ -0,0 +1,106 @@ +#include "libstore/derivations.hh" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libexpr/eval.hh" +#include "libutil/hash.hh" +#include "libutil/types.hh" + +namespace rc { + +using nix::Derivation; +using nix::DerivationOutput; + +template <> +struct Arbitrary { + static Gen arbitrary() { + return gen::element(nix::Base16, nix::Base32, nix::Base64); + } +}; + +template <> +struct Arbitrary { + static Gen arbitrary() { + return gen::apply( + [](std::string content, std::string path, std::string hash_algo, + bool recursive, bool include_algo_in_hash, nix::Base base) { + auto hash_type = nix::parseHashType(hash_algo); + auto hash = nix::hashString(hash_type, content); + return DerivationOutput( + path, recursive ? absl::StrCat("r:", hash_algo) : hash_algo, + hash.to_string(base, include_algo_in_hash)); + }, + gen::arbitrary(), + gen::map(gen::arbitrary(), + [](std::string s) { return absl::StrCat("/", s); }), + gen::element("md5", "sha1", "sha256", "sha512"), + gen::arbitrary(), gen::arbitrary(), + gen::arbitrary()); + } +}; + +template <> +struct Arbitrary { + static Gen arbitrary() { + auto gen_path = gen::map(gen::arbitrary(), [](std::string s) { + return absl::StrCat("/", s); + }); + + return gen::build( + gen::set(&nix::BasicDerivation::outputs), + gen::set(&nix::BasicDerivation::inputSrcs, + gen::container(gen_path)), + gen::set(&nix::BasicDerivation::platform), + gen::set(&nix::BasicDerivation::builder, gen_path), + gen::set(&nix::BasicDerivation::args), + gen::set(&nix::BasicDerivation::env), + gen::set(&Derivation::inputDrvs, + gen::container( + gen_path, gen::arbitrary()))); + } +}; + +} // namespace rc + +namespace nix { + +void AssertDerivationsEqual(const Derivation& lhs, const Derivation& rhs) { + RC_ASSERT(lhs.outputs.size() == rhs.outputs.size()); + for (const auto& [k, lhs_v] : lhs.outputs) { + auto rhs_v = rhs.outputs.find(k); + RC_ASSERT(rhs_v != rhs.outputs.end()); + RC_ASSERT(lhs_v.path == rhs_v->second.path); + RC_ASSERT(lhs_v.hashAlgo == rhs_v->second.hashAlgo); + RC_ASSERT(lhs_v.hash == rhs_v->second.hash); + } + + RC_ASSERT(lhs.inputSrcs == rhs.inputSrcs); + RC_ASSERT(lhs.platform == rhs.platform); + RC_ASSERT(lhs.builder == rhs.builder); + RC_ASSERT(lhs.args == rhs.args); + RC_ASSERT(lhs.env == rhs.env); + RC_ASSERT(lhs.inputDrvs == rhs.inputDrvs); +} + +class DerivationsTest : public ::testing::Test {}; + +// NOLINTNEXTLINE +RC_GTEST_FIXTURE_PROP(DerivationsTest, UnparseParseRoundTrip, + (Derivation && drv)) { + auto unparsed = drv.unparse(); + auto parsed = parseDerivation(unparsed); + AssertDerivationsEqual(drv, parsed); +} + +} // namespace nix -- cgit 1.4.1