From 42b452e72f536b63bac080880b8daa481099793c Mon Sep 17 00:00:00 2001 From: Oliver Reiche Date: Fri, 24 Feb 2023 15:49:14 +0100 Subject: Storage: Reworked storage and garbage collection The improved GC implementation uses refactored storage classes instead of directly accessing "unknown" file paths. The required storage class refactoring is quite substantial and outlined in the following paragraphs. The module `buildtool/file_system` was extended by: - `ObjectCAS`: a plain CAS implementation for reading/writing blobs and computing digests for a given `ObjectType`. Depending on that type, files written to the file system may have different properties (e.g., the x-bit set) or the digest may be computed differently (e.g., tree digests in non-compatible mode). A new module `buildtool/storage` was introduced containing: - `LocalCAS`: provides a common interface for the "logical CAS", which internally combines three `ObjectCAS`s, one for each `ObjectType` (file, executable, tree). - `LocalAC`: implements the action cache, which needs the `LocalCAS` for storing cache values. - `TargetCache`: implements the high-level target cache, which also needs the `LocalCAS` for storing cache values. - `LocalStorage`: combines the storage classes `LocalCAS`, `LocalAC`, and `TargetCache`. Those are initialized with settings from `StorageConfig`, such as the build root base path or number of generations for the garbage collector. `LocalStorage` is templated with a Boolean parameter `kDoGlobalUplink`, which indicates that, on every read/write access, the garbage collector should be used for uplinking across all generations (global). - `GarbageCollector`: responsible for garbage collection and the global uplinking across all generations. To do so, it employs instances of `LocalStorage` with `kDoGlobalUplink` set to false, in order to avoid endless recursion. The actual (local) uplinking within two single generations is performed by the corresponding storage class (e.g., `TargetCache` implements uplinking of target cache entries between two target cache generations etc.). Thereby, the actual knowledge how data should be uplinked is implemented by the instance that is responsible for creating the data in the first place. --- test/buildtool/TARGETS | 1 + test/buildtool/common/repository_config.test.cpp | 7 +- test/buildtool/execution_api/bazel/TARGETS | 2 +- .../execution_api/bazel/bazel_msg_factory.test.cpp | 2 +- test/buildtool/execution_api/data/executable_file | 1 - .../execution_api/data/non_executable_file | 1 - test/buildtool/execution_api/data/subdir1/file1 | 1 - .../execution_api/data/subdir1/subdir2/file2 | 1 - test/buildtool/execution_api/local/TARGETS | 45 +---- .../execution_api/local/local_ac.test.cpp | 141 --------------- .../execution_api/local/local_cas.test.cpp | 102 ----------- .../execution_api/local/local_storage.test.cpp | 194 --------------------- test/buildtool/file_system/TARGETS | 14 ++ test/buildtool/file_system/object_cas.test.cpp | 104 +++++++++++ test/buildtool/storage/TARGETS | 37 ++++ test/buildtool/storage/data/executable_file | 1 + test/buildtool/storage/data/non_executable_file | 1 + test/buildtool/storage/data/subdir1/file1 | 1 + test/buildtool/storage/data/subdir1/subdir2/file2 | 1 + test/buildtool/storage/local_ac.test.cpp | 141 +++++++++++++++ test/buildtool/storage/local_cas.test.cpp | 164 +++++++++++++++++ test/utils/hermeticity/local.hpp | 12 +- 22 files changed, 478 insertions(+), 496 deletions(-) delete mode 100755 test/buildtool/execution_api/data/executable_file delete mode 100755 test/buildtool/execution_api/data/non_executable_file delete mode 100644 test/buildtool/execution_api/data/subdir1/file1 delete mode 100644 test/buildtool/execution_api/data/subdir1/subdir2/file2 delete mode 100644 test/buildtool/execution_api/local/local_ac.test.cpp delete mode 100644 test/buildtool/execution_api/local/local_cas.test.cpp delete mode 100644 test/buildtool/execution_api/local/local_storage.test.cpp create mode 100644 test/buildtool/file_system/object_cas.test.cpp create mode 100644 test/buildtool/storage/TARGETS create mode 100755 test/buildtool/storage/data/executable_file create mode 100755 test/buildtool/storage/data/non_executable_file create mode 100644 test/buildtool/storage/data/subdir1/file1 create mode 100644 test/buildtool/storage/data/subdir1/subdir2/file2 create mode 100644 test/buildtool/storage/local_ac.test.cpp create mode 100644 test/buildtool/storage/local_cas.test.cpp (limited to 'test') diff --git a/test/buildtool/TARGETS b/test/buildtool/TARGETS index f7fb17ce..89d4cf15 100644 --- a/test/buildtool/TARGETS +++ b/test/buildtool/TARGETS @@ -12,6 +12,7 @@ , [["./", "logging", "TESTS"], "logging"] , [["./", "main", "TESTS"], "main"] , [["./", "multithreading", "TESTS"], "multithreading"] + , [["./", "storage", "TESTS"], "storage"] , [["./", "system", "TESTS"], "system"] ] } diff --git a/test/buildtool/common/repository_config.test.cpp b/test/buildtool/common/repository_config.test.cpp index 13d0bab9..406ca2fe 100644 --- a/test/buildtool/common/repository_config.test.cpp +++ b/test/buildtool/common/repository_config.test.cpp @@ -14,7 +14,7 @@ #include "catch2/catch.hpp" #include "src/buildtool/common/repository_config.hpp" -#include "src/buildtool/execution_api/local/local_cas.hpp" +#include "src/buildtool/storage/storage.hpp" #include "test/utils/hermeticity/local.hpp" namespace { @@ -73,9 +73,10 @@ template // Read graph from CAS [[nodiscard]] auto ReadGraph(std::string const& hash) -> nlohmann::json { - auto& cas = LocalCAS::Instance(); + auto const& cas = Storage::Instance().CAS(); auto blob = cas.BlobPath( - ArtifactDigest{hash, /*does not matter*/ 0, /*is_tree=*/false}); + ArtifactDigest{hash, /*does not matter*/ 0, /*is_tree=*/false}, + /*is_executable=*/false); REQUIRE(blob); auto content = FileSystemManager::ReadFile(*blob); REQUIRE(content); diff --git a/test/buildtool/execution_api/bazel/TARGETS b/test/buildtool/execution_api/bazel/TARGETS index 26026139..1b70c429 100644 --- a/test/buildtool/execution_api/bazel/TARGETS +++ b/test/buildtool/execution_api/bazel/TARGETS @@ -62,7 +62,7 @@ { "type": ["@", "rules", "CC/test", "test"] , "name": ["msg_factory"] , "srcs": ["bazel_msg_factory.test.cpp"] - , "data": [["test/buildtool/execution_api", "test_data"]] + , "data": [["test/buildtool/storage", "test_data"]] , "private-deps": [ ["@", "catch2", "", "catch2"] , ["test", "catch-main"] diff --git a/test/buildtool/execution_api/bazel/bazel_msg_factory.test.cpp b/test/buildtool/execution_api/bazel/bazel_msg_factory.test.cpp index e91d6d9e..67deb467 100644 --- a/test/buildtool/execution_api/bazel/bazel_msg_factory.test.cpp +++ b/test/buildtool/execution_api/bazel/bazel_msg_factory.test.cpp @@ -22,7 +22,7 @@ #include "src/buildtool/file_system/object_type.hpp" TEST_CASE("Bazel internals: MessageFactory", "[execution_api]") { - std::filesystem::path workspace{"test/buildtool/execution_api/data"}; + std::filesystem::path workspace{"test/buildtool/storage/data"}; std::filesystem::path subdir1 = workspace / "subdir1"; std::filesystem::path subdir2 = subdir1 / "subdir2"; diff --git a/test/buildtool/execution_api/data/executable_file b/test/buildtool/execution_api/data/executable_file deleted file mode 100755 index 30d74d25..00000000 --- a/test/buildtool/execution_api/data/executable_file +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/test/buildtool/execution_api/data/non_executable_file b/test/buildtool/execution_api/data/non_executable_file deleted file mode 100755 index 30d74d25..00000000 --- a/test/buildtool/execution_api/data/non_executable_file +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/test/buildtool/execution_api/data/subdir1/file1 b/test/buildtool/execution_api/data/subdir1/file1 deleted file mode 100644 index 30d74d25..00000000 --- a/test/buildtool/execution_api/data/subdir1/file1 +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/test/buildtool/execution_api/data/subdir1/subdir2/file2 b/test/buildtool/execution_api/data/subdir1/subdir2/file2 deleted file mode 100644 index 30d74d25..00000000 --- a/test/buildtool/execution_api/data/subdir1/subdir2/file2 +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/test/buildtool/execution_api/local/TARGETS b/test/buildtool/execution_api/local/TARGETS index 22c459ce..c0131568 100644 --- a/test/buildtool/execution_api/local/TARGETS +++ b/test/buildtool/execution_api/local/TARGETS @@ -1,31 +1,4 @@ -{ "local_cas": - { "type": ["@", "rules", "CC/test", "test"] - , "name": ["local_cas"] - , "srcs": ["local_cas.test.cpp"] - , "private-deps": - [ ["@", "catch2", "", "catch2"] - , ["test", "catch-main"] - , ["src/buildtool/crypto", "hash_function"] - , ["src/buildtool/execution_api/local", "local"] - , ["src/buildtool/file_system", "file_system_manager"] - , ["test/utils", "local_hermeticity"] - ] - , "stage": ["test", "buildtool", "execution_api", "local"] - } -, "local_ac": - { "type": ["@", "rules", "CC/test", "test"] - , "name": ["local_ac"] - , "srcs": ["local_ac.test.cpp"] - , "private-deps": - [ ["@", "catch2", "", "catch2"] - , ["test", "catch-main"] - , ["src/buildtool/execution_api/local", "local"] - , ["src/buildtool/file_system", "file_system_manager"] - , ["test/utils", "local_hermeticity"] - ] - , "stage": ["test", "buildtool", "execution_api", "local"] - } -, "local_execution": +{ "local_execution": { "type": ["@", "rules", "CC/test", "test"] , "name": ["local_execution"] , "srcs": ["local_execution.test.cpp"] @@ -51,23 +24,9 @@ ] , "stage": ["test", "buildtool", "execution_api", "local"] } -, "local_storage": - { "type": ["@", "rules", "CC/test", "test"] - , "name": ["local_storage"] - , "srcs": ["local_storage.test.cpp"] - , "data": [["test/buildtool/execution_api", "test_data"]] - , "private-deps": - [ ["@", "catch2", "", "catch2"] - , ["test", "catch-main"] - , ["src/buildtool/execution_api/local", "local"] - , ["test/utils", "local_hermeticity"] - ] - , "stage": ["test", "buildtool", "execution_api", "local"] - } , "TESTS": { "type": "install" , "tainted": ["test"] - , "deps": - ["local_ac", "local_api", "local_cas", "local_execution", "local_storage"] + , "deps": ["local_api", "local_execution"] } } diff --git a/test/buildtool/execution_api/local/local_ac.test.cpp b/test/buildtool/execution_api/local/local_ac.test.cpp deleted file mode 100644 index b37bced9..00000000 --- a/test/buildtool/execution_api/local/local_ac.test.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "catch2/catch.hpp" -#include "gsl-lite/gsl-lite.hpp" -#include "src/buildtool/execution_api/local/local_ac.hpp" -#include "src/buildtool/file_system/file_system_manager.hpp" -#include "test/utils/hermeticity/local.hpp" - -[[nodiscard]] static auto RunDummyExecution( - gsl::not_null const& ac, - gsl::not_null*> cas_, - bazel_re::Digest const& action_id, - std::string const& seed) -> bool; - -TEST_CASE_METHOD(HermeticLocalTestFixture, - "LocalAC: Single action, single result", - "[execution_api]") { - LocalCAS cas{}; - LocalAC ac{&cas}; - - auto action_id = ArtifactDigest::Create("action"); - CHECK(not ac.CachedResult(action_id)); - CHECK(RunDummyExecution(&ac, &cas, action_id, "result")); - auto ac_result = ac.CachedResult(action_id); - CHECK(ac_result); -} - -TEST_CASE_METHOD(HermeticLocalTestFixture, - "LocalAC: Two different actions, two different results", - "[execution_api]") { - LocalCAS cas{}; - LocalAC ac{&cas}; - - auto action_id1 = ArtifactDigest::Create("action1"); - auto action_id2 = ArtifactDigest::Create("action2"); - CHECK(not ac.CachedResult(action_id1)); - CHECK(not ac.CachedResult(action_id2)); - - std::string result_content1{}; - std::string result_content2{}; - - CHECK(RunDummyExecution(&ac, &cas, action_id1, "result1")); - auto ac_result1 = ac.CachedResult(action_id1); - REQUIRE(ac_result1); - CHECK(ac_result1->SerializeToString(&result_content1)); - - CHECK(RunDummyExecution(&ac, &cas, action_id2, "result2")); - auto ac_result2 = ac.CachedResult(action_id2); - REQUIRE(ac_result2); - CHECK(ac_result2->SerializeToString(&result_content2)); - - // check different actions, different result - CHECK(action_id1.hash() != action_id2.hash()); - CHECK(result_content1 != result_content2); -} - -TEST_CASE_METHOD(HermeticLocalTestFixture, - "LocalAC: Two different actions, same two results", - "[execution_api]") { - LocalCAS cas{}; - LocalAC ac{&cas}; - - auto action_id1 = ArtifactDigest::Create("action1"); - auto action_id2 = ArtifactDigest::Create("action2"); - CHECK(not ac.CachedResult(action_id1)); - CHECK(not ac.CachedResult(action_id2)); - - std::string result_content1{}; - std::string result_content2{}; - - CHECK(RunDummyExecution(&ac, &cas, action_id1, "same result")); - auto ac_result1 = ac.CachedResult(action_id1); - REQUIRE(ac_result1); - CHECK(ac_result1->SerializeToString(&result_content1)); - - CHECK(RunDummyExecution(&ac, &cas, action_id2, "same result")); - auto ac_result2 = ac.CachedResult(action_id2); - REQUIRE(ac_result2); - CHECK(ac_result2->SerializeToString(&result_content2)); - - // check different actions, but same result - CHECK(action_id1.hash() != action_id2.hash()); - CHECK(result_content1 == result_content2); -} - -TEST_CASE_METHOD(HermeticLocalTestFixture, - "LocalAC: Same two actions, two differnet results", - "[execution_api]") { - LocalCAS cas{}; - LocalAC ac{&cas}; - - auto action_id = ArtifactDigest::Create("same action"); - CHECK(not ac.CachedResult(action_id)); - - std::string result_content1{}; - std::string result_content2{}; - - CHECK(RunDummyExecution(&ac, &cas, action_id, "result1")); - auto ac_result1 = ac.CachedResult(action_id); - REQUIRE(ac_result1); - CHECK(ac_result1->SerializeToString(&result_content1)); - - CHECK(RunDummyExecution(&ac, &cas, action_id, "result2")); // updated - auto ac_result2 = ac.CachedResult(action_id); - REQUIRE(ac_result2); - CHECK(ac_result2->SerializeToString(&result_content2)); - - // check same actions, different cached result - CHECK(result_content1 != result_content2); -} - -auto RunDummyExecution(gsl::not_null const& ac, - gsl::not_null*> cas_, - bazel_re::Digest const& action_id, - std::string const& seed) -> bool { - bazel_re::ActionResult result{}; - *result.add_output_files() = [&]() { - bazel_re::OutputFile out{}; - out.set_path(seed); - auto digest = cas_->StoreBlobFromBytes(""); - out.set_allocated_digest( - gsl::owner{new bazel_re::Digest{*digest}}); - out.set_is_executable(false); - return out; - }(); - return ac->StoreResult(action_id, result); -} diff --git a/test/buildtool/execution_api/local/local_cas.test.cpp b/test/buildtool/execution_api/local/local_cas.test.cpp deleted file mode 100644 index 14a86628..00000000 --- a/test/buildtool/execution_api/local/local_cas.test.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "catch2/catch.hpp" -#include "src/buildtool/crypto/hash_function.hpp" -#include "src/buildtool/execution_api/local/local_cas.hpp" -#include "src/buildtool/file_system/file_system_manager.hpp" -#include "test/utils/hermeticity/local.hpp" - -TEST_CASE_METHOD(HermeticLocalTestFixture, "LocalCAS", "[execution_api]") { - std::string test_content{"test"}; - auto test_digest = ArtifactDigest::Create(test_content); - - SECTION("CAS for files") { - LocalCAS cas{}; - CHECK(not cas.BlobPath(test_digest)); - - SECTION("Add blob from bytes and verify") { - // add blob - auto cas_digest = cas.StoreBlobFromBytes(test_content); - CHECK(cas_digest); - CHECK(std::equal_to{}(*cas_digest, test_digest)); - - // verify blob - auto blob_path = cas.BlobPath(*cas_digest); - REQUIRE(blob_path); - auto const cas_content = FileSystemManager::ReadFile(*blob_path); - CHECK(cas_content.has_value()); - CHECK(cas_content == test_content); - CHECK(not FileSystemManager::IsExecutable(*blob_path)); - } - - SECTION("Add blob from file") { - CHECK(FileSystemManager::CreateDirectory("tmp")); - CHECK(FileSystemManager::WriteFile(test_content, "tmp/test")); - - // add blob - auto cas_digest = cas.StoreBlobFromFile("tmp/test"); - CHECK(cas_digest); - CHECK(std::equal_to{}(*cas_digest, test_digest)); - - // verify blob - auto blob_path = cas.BlobPath(*cas_digest); - REQUIRE(blob_path); - auto const cas_content = FileSystemManager::ReadFile(*blob_path); - CHECK(cas_content.has_value()); - CHECK(cas_content == test_content); - CHECK(not FileSystemManager::IsExecutable(*blob_path)); - } - } - - SECTION("CAS for executables") { - LocalCAS cas{}; - CHECK(not cas.BlobPath(test_digest)); - - SECTION("Add blob from bytes and verify") { - // add blob - auto cas_digest = cas.StoreBlobFromBytes(test_content); - CHECK(cas_digest); - CHECK(std::equal_to{}(*cas_digest, test_digest)); - - // verify blob - auto blob_path = cas.BlobPath(*cas_digest); - REQUIRE(blob_path); - auto const cas_content = FileSystemManager::ReadFile(*blob_path); - CHECK(cas_content.has_value()); - CHECK(cas_content == test_content); - CHECK(FileSystemManager::IsExecutable(*blob_path)); - } - - SECTION("Add blob from file") { - CHECK(FileSystemManager::CreateDirectory("tmp")); - CHECK(FileSystemManager::WriteFile(test_content, "tmp/test")); - - // add blob - auto cas_digest = cas.StoreBlobFromFile("tmp/test"); - CHECK(cas_digest); - CHECK(std::equal_to{}(*cas_digest, test_digest)); - - // verify blob - auto blob_path = cas.BlobPath(*cas_digest); - REQUIRE(blob_path); - auto const cas_content = FileSystemManager::ReadFile(*blob_path); - CHECK(cas_content.has_value()); - CHECK(cas_content == test_content); - CHECK(FileSystemManager::IsExecutable(*blob_path)); - } - } -} diff --git a/test/buildtool/execution_api/local/local_storage.test.cpp b/test/buildtool/execution_api/local/local_storage.test.cpp deleted file mode 100644 index ff2493ae..00000000 --- a/test/buildtool/execution_api/local/local_storage.test.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "catch2/catch.hpp" -#include "src/buildtool/execution_api/local/local_storage.hpp" -#include "test/utils/hermeticity/local.hpp" - -TEST_CASE_METHOD(HermeticLocalTestFixture, - "LocalStorage: Add blob to storage from bytes", - "[execution_api]") { - std::string test_bytes("test"); - - LocalStorage storage{}; - auto test_digest = ArtifactDigest::Create(test_bytes); - - // check blob not in storage - CHECK(not storage.BlobPath(test_digest, true)); - CHECK(not storage.BlobPath(test_digest, false)); - - // ensure previous calls did not accidentially create the blob - CHECK(not storage.BlobPath(test_digest, true)); - CHECK(not storage.BlobPath(test_digest, false)); - - SECTION("Add non-executable blob to storage") { - CHECK(storage.StoreBlob(test_bytes, false)); - - auto file_path = storage.BlobPath(test_digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } - - SECTION("Add executable blob to storage") { - CHECK(storage.StoreBlob(test_bytes, true)); - - auto file_path = storage.BlobPath(test_digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } -} - -TEST_CASE_METHOD(HermeticLocalTestFixture, - "LocalStorage: Add blob to storage from non-executable file", - "[execution_api]") { - std::filesystem::path non_exec_file{ - "test/buildtool/execution_api/data/non_executable_file"}; - - LocalStorage storage{}; - auto test_blob = CreateBlobFromFile(non_exec_file); - REQUIRE(test_blob); - - // check blob not in storage - CHECK(not storage.BlobPath(test_blob->digest, true)); - CHECK(not storage.BlobPath(test_blob->digest, false)); - - // ensure previous calls did not accidentially create the blob - CHECK(not storage.BlobPath(test_blob->digest, true)); - CHECK(not storage.BlobPath(test_blob->digest, false)); - - SECTION("Add blob to storage without specifying x-bit") { - CHECK(storage.StoreBlob(non_exec_file)); - - auto file_path = storage.BlobPath(test_blob->digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_blob->digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } - - SECTION("Add non-executable blob to storage") { - CHECK(storage.StoreBlob(non_exec_file, false)); - - auto file_path = storage.BlobPath(test_blob->digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_blob->digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } - - SECTION("Add executable blob to storage") { - CHECK(storage.StoreBlob(non_exec_file, true)); - - auto file_path = storage.BlobPath(test_blob->digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_blob->digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } -} - -TEST_CASE_METHOD(HermeticLocalTestFixture, - "LocalStorage: Add blob to storage from executable file", - "[execution_api]") { - std::filesystem::path exec_file{ - "test/buildtool/execution_api/data/executable_file"}; - - LocalStorage storage{}; - auto test_blob = CreateBlobFromFile(exec_file); - REQUIRE(test_blob); - - // check blob not in storage - CHECK(not storage.BlobPath(test_blob->digest, true)); - CHECK(not storage.BlobPath(test_blob->digest, false)); - - // ensure previous calls did not accidentially create the blob - CHECK(not storage.BlobPath(test_blob->digest, true)); - CHECK(not storage.BlobPath(test_blob->digest, false)); - - SECTION("Add blob to storage without specifying x-bit") { - CHECK(storage.StoreBlob(exec_file)); - - auto file_path = storage.BlobPath(test_blob->digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_blob->digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } - - SECTION("Add non-executable blob to storage") { - CHECK(storage.StoreBlob(exec_file, false)); - - auto file_path = storage.BlobPath(test_blob->digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_blob->digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } - - SECTION("Add executable blob to storage") { - CHECK(storage.StoreBlob(exec_file, true)); - - auto file_path = storage.BlobPath(test_blob->digest, false); - REQUIRE(file_path); - CHECK(FileSystemManager::IsFile(*file_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - - auto exe_path = storage.BlobPath(test_blob->digest, true); - REQUIRE(exe_path); - CHECK(FileSystemManager::IsFile(*exe_path)); - CHECK(FileSystemManager::IsExecutable(*exe_path)); - CHECK(not FileSystemManager::IsExecutable(*file_path)); - } -} diff --git a/test/buildtool/file_system/TARGETS b/test/buildtool/file_system/TARGETS index 285cafac..93477387 100644 --- a/test/buildtool/file_system/TARGETS +++ b/test/buildtool/file_system/TARGETS @@ -10,6 +10,19 @@ ] , "stage": ["test", "buildtool", "file_system"] } +, "object_cas": + { "type": ["@", "rules", "CC/test", "test"] + , "name": ["object_cas"] + , "srcs": ["object_cas.test.cpp"] + , "private-deps": + [ ["@", "catch2", "", "catch2"] + , ["test", "catch-main"] + , ["src/buildtool/crypto", "hash_function"] + , ["src/buildtool/file_system", "file_system_manager"] + , ["test/utils", "local_hermeticity"] + ] + , "stage": ["test", "buildtool", "file_system"] + } , "git_tree": { "type": ["@", "rules", "CC/test", "test"] , "name": ["git_tree"] @@ -93,6 +106,7 @@ , "deps": [ "file_root" , "file_system_manager" + , "object_cas" , "git_tree" , "directory_entries" , "git_repo" diff --git a/test/buildtool/file_system/object_cas.test.cpp b/test/buildtool/file_system/object_cas.test.cpp new file mode 100644 index 00000000..bf20a287 --- /dev/null +++ b/test/buildtool/file_system/object_cas.test.cpp @@ -0,0 +1,104 @@ +// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "catch2/catch.hpp" +#include "src/buildtool/crypto/hash_function.hpp" +#include "src/buildtool/file_system/file_system_manager.hpp" +#include "src/buildtool/file_system/object_cas.hpp" +#include "test/utils/hermeticity/local.hpp" + +TEST_CASE_METHOD(HermeticLocalTestFixture, "ObjectCAS", "[file_system]") { + std::string test_content{"test"}; + auto test_digest = ArtifactDigest::Create(test_content); + + SECTION("CAS for files") { + ObjectCAS cas{StorageConfig::GenerationCacheDir(0) / + "casf"}; + CHECK(not cas.BlobPath(test_digest)); + + SECTION("Add blob from bytes and verify") { + // add blob + auto cas_digest = cas.StoreBlobFromBytes(test_content); + CHECK(cas_digest); + CHECK(std::equal_to{}(*cas_digest, test_digest)); + + // verify blob + auto blob_path = cas.BlobPath(*cas_digest); + REQUIRE(blob_path); + auto const cas_content = FileSystemManager::ReadFile(*blob_path); + CHECK(cas_content.has_value()); + CHECK(cas_content == test_content); + CHECK(not FileSystemManager::IsExecutable(*blob_path)); + } + + SECTION("Add blob from file") { + CHECK(FileSystemManager::CreateDirectory("tmp")); + CHECK(FileSystemManager::WriteFile(test_content, "tmp/test")); + + // add blob + auto cas_digest = cas.StoreBlobFromFile("tmp/test"); + CHECK(cas_digest); + CHECK(std::equal_to{}(*cas_digest, test_digest)); + + // verify blob + auto blob_path = cas.BlobPath(*cas_digest); + REQUIRE(blob_path); + auto const cas_content = FileSystemManager::ReadFile(*blob_path); + CHECK(cas_content.has_value()); + CHECK(cas_content == test_content); + CHECK(not FileSystemManager::IsExecutable(*blob_path)); + } + } + + SECTION("CAS for executables") { + ObjectCAS cas{ + StorageConfig::GenerationCacheDir(0) / "casx"}; + CHECK(not cas.BlobPath(test_digest)); + + SECTION("Add blob from bytes and verify") { + // add blob + auto cas_digest = cas.StoreBlobFromBytes(test_content); + CHECK(cas_digest); + CHECK(std::equal_to{}(*cas_digest, test_digest)); + + // verify blob + auto blob_path = cas.BlobPath(*cas_digest); + REQUIRE(blob_path); + auto const cas_content = FileSystemManager::ReadFile(*blob_path); + CHECK(cas_content.has_value()); + CHECK(cas_content == test_content); + CHECK(FileSystemManager::IsExecutable(*blob_path)); + } + + SECTION("Add blob from file") { + CHECK(FileSystemManager::CreateDirectory("tmp")); + CHECK(FileSystemManager::WriteFile(test_content, "tmp/test")); + + // add blob + auto cas_digest = cas.StoreBlobFromFile("tmp/test"); + CHECK(cas_digest); + CHECK(std::equal_to{}(*cas_digest, test_digest)); + + // verify blob + auto blob_path = cas.BlobPath(*cas_digest); + REQUIRE(blob_path); + auto const cas_content = FileSystemManager::ReadFile(*blob_path); + CHECK(cas_content.has_value()); + CHECK(cas_content == test_content); + CHECK(FileSystemManager::IsExecutable(*blob_path)); + } + } +} diff --git a/test/buildtool/storage/TARGETS b/test/buildtool/storage/TARGETS new file mode 100644 index 00000000..abfab7b7 --- /dev/null +++ b/test/buildtool/storage/TARGETS @@ -0,0 +1,37 @@ +{ "test_data": + { "type": ["@", "rules", "data", "staged"] + , "srcs": + [ "data/executable_file" + , "data/non_executable_file" + , "data/subdir1/file1" + , "data/subdir1/subdir2/file2" + ] + , "stage": ["test", "buildtool", "storage"] + } +, "local_cas": + { "type": ["@", "rules", "CC/test", "test"] + , "name": ["local_cas"] + , "srcs": ["local_cas.test.cpp"] + , "data": [["test/buildtool/storage", "test_data"]] + , "private-deps": + [ ["@", "catch2", "", "catch2"] + , ["test", "catch-main"] + , ["test/utils", "local_hermeticity"] + ] + , "stage": ["test", "buildtool", "storage"] + } +, "local_ac": + { "type": ["@", "rules", "CC/test", "test"] + , "name": ["local_ac"] + , "srcs": ["local_ac.test.cpp"] + , "private-deps": + [ ["@", "catch2", "", "catch2"] + , ["test", "catch-main"] + , ["src/buildtool/file_system", "file_system_manager"] + , ["test/utils", "local_hermeticity"] + ] + , "stage": ["test", "buildtool", "storage"] + } +, "TESTS": + {"type": "install", "tainted": ["test"], "deps": ["local_cas", "local_ac"]} +} diff --git a/test/buildtool/storage/data/executable_file b/test/buildtool/storage/data/executable_file new file mode 100755 index 00000000..30d74d25 --- /dev/null +++ b/test/buildtool/storage/data/executable_file @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/test/buildtool/storage/data/non_executable_file b/test/buildtool/storage/data/non_executable_file new file mode 100755 index 00000000..30d74d25 --- /dev/null +++ b/test/buildtool/storage/data/non_executable_file @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/test/buildtool/storage/data/subdir1/file1 b/test/buildtool/storage/data/subdir1/file1 new file mode 100644 index 00000000..30d74d25 --- /dev/null +++ b/test/buildtool/storage/data/subdir1/file1 @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/test/buildtool/storage/data/subdir1/subdir2/file2 b/test/buildtool/storage/data/subdir1/subdir2/file2 new file mode 100644 index 00000000..30d74d25 --- /dev/null +++ b/test/buildtool/storage/data/subdir1/subdir2/file2 @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/test/buildtool/storage/local_ac.test.cpp b/test/buildtool/storage/local_ac.test.cpp new file mode 100644 index 00000000..19da0e59 --- /dev/null +++ b/test/buildtool/storage/local_ac.test.cpp @@ -0,0 +1,141 @@ +// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "catch2/catch.hpp" +#include "gsl-lite/gsl-lite.hpp" +#include "src/buildtool/file_system/file_system_manager.hpp" +#include "src/buildtool/storage/storage.hpp" +#include "test/utils/hermeticity/local.hpp" + +[[nodiscard]] static auto RunDummyExecution( + gsl::not_null const*> const& ac, + gsl::not_null const*> const& cas_, + bazel_re::Digest const& action_id, + std::string const& seed) -> bool; + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalAC: Single action, single result", + "[storage]") { + auto const& ac = Storage::Instance().ActionCache(); + auto const& cas = Storage::Instance().CAS(); + + auto action_id = ArtifactDigest::Create("action"); + CHECK(not ac.CachedResult(action_id)); + CHECK(RunDummyExecution(&ac, &cas, action_id, "result")); + auto ac_result = ac.CachedResult(action_id); + CHECK(ac_result); +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalAC: Two different actions, two different results", + "[storage]") { + auto const& ac = Storage::Instance().ActionCache(); + auto const& cas = Storage::Instance().CAS(); + + auto action_id1 = ArtifactDigest::Create("action1"); + auto action_id2 = ArtifactDigest::Create("action2"); + CHECK(not ac.CachedResult(action_id1)); + CHECK(not ac.CachedResult(action_id2)); + + std::string result_content1{}; + std::string result_content2{}; + + CHECK(RunDummyExecution(&ac, &cas, action_id1, "result1")); + auto ac_result1 = ac.CachedResult(action_id1); + REQUIRE(ac_result1); + CHECK(ac_result1->SerializeToString(&result_content1)); + + CHECK(RunDummyExecution(&ac, &cas, action_id2, "result2")); + auto ac_result2 = ac.CachedResult(action_id2); + REQUIRE(ac_result2); + CHECK(ac_result2->SerializeToString(&result_content2)); + + // check different actions, different result + CHECK(action_id1.hash() != action_id2.hash()); + CHECK(result_content1 != result_content2); +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalAC: Two different actions, same two results", + "[storage]") { + auto const& ac = Storage::Instance().ActionCache(); + auto const& cas = Storage::Instance().CAS(); + + auto action_id1 = ArtifactDigest::Create("action1"); + auto action_id2 = ArtifactDigest::Create("action2"); + CHECK(not ac.CachedResult(action_id1)); + CHECK(not ac.CachedResult(action_id2)); + + std::string result_content1{}; + std::string result_content2{}; + + CHECK(RunDummyExecution(&ac, &cas, action_id1, "same result")); + auto ac_result1 = ac.CachedResult(action_id1); + REQUIRE(ac_result1); + CHECK(ac_result1->SerializeToString(&result_content1)); + + CHECK(RunDummyExecution(&ac, &cas, action_id2, "same result")); + auto ac_result2 = ac.CachedResult(action_id2); + REQUIRE(ac_result2); + CHECK(ac_result2->SerializeToString(&result_content2)); + + // check different actions, but same result + CHECK(action_id1.hash() != action_id2.hash()); + CHECK(result_content1 == result_content2); +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalAC: Same two actions, two different results", + "[storage]") { + auto const& ac = Storage::Instance().ActionCache(); + auto const& cas = Storage::Instance().CAS(); + + auto action_id = ArtifactDigest::Create("same action"); + CHECK(not ac.CachedResult(action_id)); + + std::string result_content1{}; + std::string result_content2{}; + + CHECK(RunDummyExecution(&ac, &cas, action_id, "result1")); + auto ac_result1 = ac.CachedResult(action_id); + REQUIRE(ac_result1); + CHECK(ac_result1->SerializeToString(&result_content1)); + + CHECK(RunDummyExecution(&ac, &cas, action_id, "result2")); // updated + auto ac_result2 = ac.CachedResult(action_id); + REQUIRE(ac_result2); + CHECK(ac_result2->SerializeToString(&result_content2)); + + // check same actions, different cached result + CHECK(result_content1 != result_content2); +} + +auto RunDummyExecution(gsl::not_null const*> const& ac, + gsl::not_null const*> const& cas_, + bazel_re::Digest const& action_id, + std::string const& seed) -> bool { + bazel_re::ActionResult result{}; + *result.add_output_files() = [&]() { + bazel_re::OutputFile out{}; + out.set_path(seed); + auto digest = cas_->StoreBlob(""); + out.set_allocated_digest( + gsl::owner{new bazel_re::Digest{*digest}}); + out.set_is_executable(false); + return out; + }(); + return ac->StoreResult(action_id, result); +} diff --git a/test/buildtool/storage/local_cas.test.cpp b/test/buildtool/storage/local_cas.test.cpp new file mode 100644 index 00000000..95d119bf --- /dev/null +++ b/test/buildtool/storage/local_cas.test.cpp @@ -0,0 +1,164 @@ +// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "catch2/catch.hpp" +#include "src/buildtool/storage/storage.hpp" +#include "test/utils/hermeticity/local.hpp" + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalCAS: Add blob to storage from bytes", + "[storage]") { + std::string test_bytes("test"); + + auto const& cas = Storage::Instance().CAS(); + auto test_digest = ArtifactDigest::Create(test_bytes); + + // check blob not in storage + CHECK(not cas.BlobPath(test_digest, true)); + CHECK(not cas.BlobPath(test_digest, false)); + + // ensure previous calls did not accidentially create the blob + CHECK(not cas.BlobPath(test_digest, true)); + CHECK(not cas.BlobPath(test_digest, false)); + + SECTION("Add non-executable blob to storage") { + CHECK(cas.StoreBlob(test_bytes, false)); + + auto file_path = cas.BlobPath(test_digest, false); + REQUIRE(file_path); + CHECK(FileSystemManager::IsFile(*file_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + + auto exe_path = cas.BlobPath(test_digest, true); + REQUIRE(exe_path); + CHECK(FileSystemManager::IsFile(*exe_path)); + CHECK(FileSystemManager::IsExecutable(*exe_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + } + + SECTION("Add executable blob to storage") { + CHECK(cas.StoreBlob(test_bytes, true)); + + auto file_path = cas.BlobPath(test_digest, false); + REQUIRE(file_path); + CHECK(FileSystemManager::IsFile(*file_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + + auto exe_path = cas.BlobPath(test_digest, true); + REQUIRE(exe_path); + CHECK(FileSystemManager::IsFile(*exe_path)); + CHECK(FileSystemManager::IsExecutable(*exe_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + } +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalCAS: Add blob to storage from non-executable file", + "[storage]") { + std::filesystem::path non_exec_file{ + "test/buildtool/storage/data/non_executable_file"}; + + auto const& cas = Storage::Instance().CAS(); + auto test_blob = CreateBlobFromFile(non_exec_file); + REQUIRE(test_blob); + + // check blob not in storage + CHECK(not cas.BlobPath(test_blob->digest, true)); + CHECK(not cas.BlobPath(test_blob->digest, false)); + + // ensure previous calls did not accidentially create the blob + CHECK(not cas.BlobPath(test_blob->digest, true)); + CHECK(not cas.BlobPath(test_blob->digest, false)); + + SECTION("Add non-executable blob to storage") { + CHECK(cas.StoreBlob(non_exec_file, false)); + + auto file_path = cas.BlobPath(test_blob->digest, false); + REQUIRE(file_path); + CHECK(FileSystemManager::IsFile(*file_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + + auto exe_path = cas.BlobPath(test_blob->digest, true); + REQUIRE(exe_path); + CHECK(FileSystemManager::IsFile(*exe_path)); + CHECK(FileSystemManager::IsExecutable(*exe_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + } + + SECTION("Add executable blob to storage") { + CHECK(cas.StoreBlob(non_exec_file, true)); + + auto file_path = cas.BlobPath(test_blob->digest, false); + REQUIRE(file_path); + CHECK(FileSystemManager::IsFile(*file_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + + auto exe_path = cas.BlobPath(test_blob->digest, true); + REQUIRE(exe_path); + CHECK(FileSystemManager::IsFile(*exe_path)); + CHECK(FileSystemManager::IsExecutable(*exe_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + } +} + +TEST_CASE_METHOD(HermeticLocalTestFixture, + "LocalCAS: Add blob to storage from executable file", + "[storage]") { + std::filesystem::path exec_file{ + "test/buildtool/storage/data/executable_file"}; + + auto const& cas = Storage::Instance().CAS(); + auto test_blob = CreateBlobFromFile(exec_file); + REQUIRE(test_blob); + + // check blob not in storage + CHECK(not cas.BlobPath(test_blob->digest, true)); + CHECK(not cas.BlobPath(test_blob->digest, false)); + + // ensure previous calls did not accidentially create the blob + CHECK(not cas.BlobPath(test_blob->digest, true)); + CHECK(not cas.BlobPath(test_blob->digest, false)); + + SECTION("Add non-executable blob to storage") { + CHECK(cas.StoreBlob(exec_file, false)); + + auto file_path = cas.BlobPath(test_blob->digest, false); + REQUIRE(file_path); + CHECK(FileSystemManager::IsFile(*file_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + + auto exe_path = cas.BlobPath(test_blob->digest, true); + REQUIRE(exe_path); + CHECK(FileSystemManager::IsFile(*exe_path)); + CHECK(FileSystemManager::IsExecutable(*exe_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + } + + SECTION("Add executable blob to storage") { + CHECK(cas.StoreBlob(exec_file, true)); + + auto file_path = cas.BlobPath(test_blob->digest, false); + REQUIRE(file_path); + CHECK(FileSystemManager::IsFile(*file_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + + auto exe_path = cas.BlobPath(test_blob->digest, true); + REQUIRE(exe_path); + CHECK(FileSystemManager::IsFile(*exe_path)); + CHECK(FileSystemManager::IsExecutable(*exe_path)); + CHECK(not FileSystemManager::IsExecutable(*file_path)); + } +} diff --git a/test/utils/hermeticity/local.hpp b/test/utils/hermeticity/local.hpp index 0b55723a..2b67cf10 100644 --- a/test/utils/hermeticity/local.hpp +++ b/test/utils/hermeticity/local.hpp @@ -16,10 +16,10 @@ #define INCLUDED_SRC_TEST_UTILS_HERMETICITY_LOCAL_HPP #include "src/buildtool/common/statistics.hpp" -#include "src/buildtool/execution_api/local/config.hpp" -#include "src/buildtool/execution_api/local/local_cas.hpp" #include "src/buildtool/file_system/file_system_manager.hpp" #include "src/buildtool/logging/logger.hpp" +#include "src/buildtool/storage/config.hpp" +#include "src/buildtool/storage/storage.hpp" class HermeticLocalTestFixture { public: @@ -36,12 +36,10 @@ class HermeticLocalTestFixture { if (FileSystemManager::RemoveDirectory(case_dir, true) and FileSystemManager::CreateDirectoryExclusive(case_dir) and - LocalExecutionConfig::SetBuildRoot(case_dir)) { + StorageConfig::SetBuildRoot(case_dir)) { // After the build root has been changed, the file roots of the - // static CAS instances needs to be updated. - LocalCAS::Instance().Reset(); - LocalCAS::Instance().Reset(); - LocalCAS::Instance().Reset(); + // static storage instances need to be updated. + Storage::Reinitialize(); Logger::Log(LogLevel::Debug, "created test-local cache dir {}", case_dir.string()); -- cgit v1.2.3