From 3c3527e16bf1d0bf57207dcc54975534f5252225 Mon Sep 17 00:00:00 2001 From: Kane York Date: Tue, 4 Aug 2020 16:44:20 -0700 Subject: [PATCH] feat(3p/nix): add MockBinaryCacheStore This adds an implementation of BinaryCacheStore to be used by tests exercising both the logic inherent to BinaryCacheStore and more general Store tests. A new library target, nixstoremock, is created to indicate that this file is intended only for use in tests and not in user-facing code. Change-Id: Ib68f777238843a4f3a2303db8a69735fbc22d161 Reviewed-on: https://cl.tvl.fyi/c/depot/+/1645 Tested-by: BuildkiteCI Reviewed-by: glittershark --- third_party/nix/src/libstore/CMakeLists.txt | 21 ++++- .../src/libstore/mock-binary-cache-store.cc | 91 +++++++++++++++++++ .../src/libstore/mock-binary-cache-store.hh | 59 ++++++++++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 third_party/nix/src/libstore/mock-binary-cache-store.cc create mode 100644 third_party/nix/src/libstore/mock-binary-cache-store.hh diff --git a/third_party/nix/src/libstore/CMakeLists.txt b/third_party/nix/src/libstore/CMakeLists.txt index 4bfbb165f..246377cc9 100644 --- a/third_party/nix/src/libstore/CMakeLists.txt +++ b/third_party/nix/src/libstore/CMakeLists.txt @@ -1,8 +1,11 @@ # -*- mode: cmake; -*- add_library(nixstore SHARED) +add_library(nixstoremock SHARED) set_property(TARGET nixstore PROPERTY CXX_STANDARD 17) +set_property(TARGET nixstoremock PROPERTY CXX_STANDARD 17) include_directories(${PROJECT_BINARY_DIR}) # for config.h target_include_directories(nixstore PUBLIC "${nix_SOURCE_DIR}/src") +target_include_directories(nixstoremock PUBLIC "${nix_SOURCE_DIR}/src") # The database schema is stored in schema.sql, but needs to be # available during the build as static data. @@ -101,8 +104,24 @@ target_link_libraries(nixstore sodium ) +target_sources(nixstoremock + PUBLIC + mock-binary-cache-store.hh + + PRIVATE + mock-binary-cache-store.cc +) + +target_link_libraries(nixstoremock + nixstore + + absl::btree + absl::flat_hash_map + glog +) + configure_file("nix-store.pc.in" "${PROJECT_BINARY_DIR}/nix-store.pc" @ONLY) INSTALL(FILES "${PROJECT_BINARY_DIR}/nix-store.pc" DESTINATION "${PKGCONFIG_INSTALL_DIR}") INSTALL(FILES ${HEADER_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/nix/libstore) -INSTALL(TARGETS nixstore DESTINATION ${CMAKE_INSTALL_LIBDIR}) +INSTALL(TARGETS nixstore nixstoremock DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/third_party/nix/src/libstore/mock-binary-cache-store.cc b/third_party/nix/src/libstore/mock-binary-cache-store.cc new file mode 100644 index 000000000..995d61521 --- /dev/null +++ b/third_party/nix/src/libstore/mock-binary-cache-store.cc @@ -0,0 +1,91 @@ +#include "libstore/mock-binary-cache-store.hh" + +#include + +namespace nix { + +MockBinaryCacheStore::MockBinaryCacheStore(const Params& params) + : BinaryCacheStore(params), contents_(), errorInjections_() {} + +std::string MockBinaryCacheStore::getUri() { return "mock://1"; } + +bool MockBinaryCacheStore::fileExists(const std::string& path) { + ThrowInjectedErrors(path); + + return contents_.find(path) != contents_.end(); +}; + +void MockBinaryCacheStore::upsertFile(const std::string& path, + const std::string& data, + const std::string& mimeType) { + ThrowInjectedErrors(path); + + contents_[path] = MemoryFile{data, mimeType}; +} + +void MockBinaryCacheStore::getFile( + const std::string& path, + Callback> callback) noexcept { + auto eit = errorInjections_.find(path); + if (eit != errorInjections_.end()) { + try { + eit->second(); + LOG(FATAL) << "thrower failed to throw"; + } catch (...) { + callback.rethrow(); + } + return; + } + + auto it = contents_.find(path); + if (it == contents_.end()) { + try { + throw NoSuchBinaryCacheFile(absl::StrCat( + "file '", path, "' was not added to the MockBinaryCache")); + } catch (...) { + callback.rethrow(); + } + return; + } + callback(std::make_shared(it->second.data)); +} + +PathSet MockBinaryCacheStore::queryAllValidPaths() { + PathSet paths; + + for (auto it : contents_) { + paths.insert(it.first); + } + + return paths; +} + +void MockBinaryCacheStore::DeleteFile(const std::string& path) { + contents_.erase(path); +} + +// Same as upsert, but bypasses injected errors. +void MockBinaryCacheStore::SetFileContentsForTest(const std::string& path, + const std::string& data, + const std::string& mimeType) { + contents_[path] = MemoryFile{data, mimeType}; +} + +void MockBinaryCacheStore::PrepareErrorInjection( + const std::string& path, std::function err_factory) { + errorInjections_[path] = err_factory; +} + +void MockBinaryCacheStore::CancelErrorInjection(const std::string& path) { + errorInjections_.erase(path); +} + +void MockBinaryCacheStore::ThrowInjectedErrors(const std::string& path) { + auto it = errorInjections_.find(path); + if (it != errorInjections_.end()) { + it->second(); + LOG(FATAL) << "thrower failed to throw"; + } +} + +} // namespace nix diff --git a/third_party/nix/src/libstore/mock-binary-cache-store.hh b/third_party/nix/src/libstore/mock-binary-cache-store.hh new file mode 100644 index 000000000..419077b6b --- /dev/null +++ b/third_party/nix/src/libstore/mock-binary-cache-store.hh @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include "libstore/binary-cache-store.hh" + +namespace nix { + +// MockBinaryCacheStore implements a memory-based BinaryCacheStore, for use in +// tests. +class MockBinaryCacheStore : public BinaryCacheStore { + public: + MockBinaryCacheStore(const Params& params); + + // Store API + + std::string getUri() override; + + bool fileExists(const std::string& path) override; + + void upsertFile(const std::string& path, const std::string& data, + const std::string& mimeType) override; + + void getFile( + const std::string& path, + Callback> callback) noexcept override; + + PathSet queryAllValidPaths() override; + + // Test API + + // Remove a file from the store. + void DeleteFile(const std::string& path); + + // Same as upsert, but bypasses injected errors. + void SetFileContentsForTest(const std::string& path, const std::string& data, + const std::string& mimeType); + + void PrepareErrorInjection(const std::string& path, + std::function throw_func); + + void CancelErrorInjection(const std::string& path); + + // Internals + + private: + void ThrowInjectedErrors(const std::string& path); + + struct MemoryFile { + std::string data; + std::string mimeType; + }; + + absl::btree_map contents_; + absl::flat_hash_map> errorInjections_; +}; + +} // namespace nix