summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/buildtool/execution_api/bazel/TARGETS15
-rw-r--r--test/buildtool/execution_api/bazel/bazel_api.test.cpp35
-rw-r--r--test/buildtool/execution_api/common/TARGETS12
-rw-r--r--test/buildtool/execution_api/common/api_test.hpp314
-rw-r--r--test/buildtool/execution_api/local/TARGETS4
-rw-r--r--test/buildtool/execution_api/local/local_api.test.cpp286
6 files changed, 389 insertions, 277 deletions
diff --git a/test/buildtool/execution_api/bazel/TARGETS b/test/buildtool/execution_api/bazel/TARGETS
index 74890977..5978f7be 100644
--- a/test/buildtool/execution_api/bazel/TARGETS
+++ b/test/buildtool/execution_api/bazel/TARGETS
@@ -72,6 +72,18 @@
]
, "stage": ["test", "buildtool", "execution_api", "bazel"]
}
+, "bazel_api":
+ { "type": ["@", "rules", "CC/test", "test"]
+ , "name": ["bazel_api"]
+ , "srcs": ["bazel_api.test.cpp"]
+ , "deps":
+ [ ["@", "catch2", "", "catch2"]
+ , ["test/utils", "catch-main-remote-execution"]
+ , ["src/buildtool/execution_api/remote", "bazel"]
+ , ["test/buildtool/execution_api/common", "api_test"]
+ ]
+ , "stage": ["test", "buildtool", "execution_api", "bazel"]
+ }
, "TESTS":
{ "type": "install"
, "tainted": ["test"]
@@ -82,6 +94,7 @@
, "execution_client"
, "msg_factory"
, "network"
+ , "bazel_api"
]
}
-} \ No newline at end of file
+}
diff --git a/test/buildtool/execution_api/bazel/bazel_api.test.cpp b/test/buildtool/execution_api/bazel/bazel_api.test.cpp
new file mode 100644
index 00000000..18d08f7c
--- /dev/null
+++ b/test/buildtool/execution_api/bazel/bazel_api.test.cpp
@@ -0,0 +1,35 @@
+#include <cstdlib>
+#include <string>
+
+#include "catch2/catch.hpp"
+#include "src/buildtool/execution_api/remote/bazel/bazel_api.hpp"
+#include "src/buildtool/execution_api/remote/config.hpp"
+#include "test/buildtool/execution_api/common/api_test.hpp"
+#include "test/utils/test_env.hpp"
+
+namespace {
+
+auto api_factory = []() {
+ static auto const& server = RemoteExecutionConfig::Instance();
+ return IExecutionApi::Ptr{
+ new BazelApi{"remote-execution", server.Host(), server.Port(), {}}};
+};
+
+} // namespace
+
+TEST_CASE("BazelAPI: No input, no output", "[execution_api]") {
+ TestNoInputNoOutput(api_factory, ReadPlatformPropertiesFromEnv());
+}
+
+TEST_CASE("BazelAPI: No input, create output", "[execution_api]") {
+ TestNoInputCreateOutput(api_factory, ReadPlatformPropertiesFromEnv());
+}
+
+TEST_CASE("BazelAPI: One input copied to output", "[execution_api]") {
+ TestOneInputCopiedToOutput(api_factory, ReadPlatformPropertiesFromEnv());
+}
+
+TEST_CASE("BazelAPI: Non-zero exit code, create output", "[execution_api]") {
+ TestNonZeroExitCodeCreateOutput(api_factory,
+ ReadPlatformPropertiesFromEnv());
+}
diff --git a/test/buildtool/execution_api/common/TARGETS b/test/buildtool/execution_api/common/TARGETS
new file mode 100644
index 00000000..21095882
--- /dev/null
+++ b/test/buildtool/execution_api/common/TARGETS
@@ -0,0 +1,12 @@
+{ "api_test":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["api_test"]
+ , "hdrs": ["api_test.hpp"]
+ , "deps":
+ [ ["@", "catch2", "", "catch2"]
+ , ["src/buildtool/common", "artifact_factory"]
+ , ["src/buildtool/execution_api/common", "common"]
+ ]
+ , "stage": ["test", "buildtool", "execution_api", "common"]
+ }
+}
diff --git a/test/buildtool/execution_api/common/api_test.hpp b/test/buildtool/execution_api/common/api_test.hpp
new file mode 100644
index 00000000..42026563
--- /dev/null
+++ b/test/buildtool/execution_api/common/api_test.hpp
@@ -0,0 +1,314 @@
+#include <cstdlib>
+#include <string>
+
+#include "catch2/catch.hpp"
+#include "src/buildtool/common/artifact_factory.hpp"
+#include "src/buildtool/execution_api/common/execution_action.hpp"
+#include "src/buildtool/execution_api/common/execution_api.hpp"
+#include "src/buildtool/execution_api/common/execution_response.hpp"
+
+using ApiFactory = std::function<IExecutionApi::Ptr()>;
+using ExecProps = std::map<std::string, std::string>;
+
+[[nodiscard]] static inline auto TestNoInputNoOutput(
+ ApiFactory const& api_factory,
+ ExecProps const& props,
+ bool is_hermetic = false) {
+ std::string test_content("test");
+
+ auto api = api_factory();
+
+ auto action = api->CreateAction(
+ *api->UploadTree({}), {"echo", "-n", test_content}, {}, {}, {}, props);
+
+ SECTION("Cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->HasStdOut());
+ CHECK(response->StdOut() == test_content);
+
+ if (is_hermetic) {
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify caching") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->HasStdOut());
+ CHECK(response->StdOut() == test_content);
+ CHECK(response->IsCached());
+ }
+ }
+ }
+
+ SECTION("Do not cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->HasStdOut());
+ CHECK(response->StdOut() == test_content);
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify caching") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->HasStdOut());
+ CHECK(response->StdOut() == test_content);
+ CHECK(not response->IsCached());
+ }
+ }
+}
+
+[[nodiscard]] static inline auto TestNoInputCreateOutput(
+ ApiFactory const& api_factory,
+ ExecProps const& props,
+ bool is_hermetic = false) {
+ std::string test_content("test");
+ auto test_digest = ArtifactDigest::Create(test_content);
+
+ std::string output_path{"output_file"};
+
+ auto api = api_factory();
+
+ auto action = api->CreateAction(
+ *api->UploadTree({}),
+ {"/bin/sh",
+ "-c",
+ "set -e\necho -n " + test_content + " > " + output_path},
+ {output_path},
+ {},
+ {},
+ props);
+
+ SECTION("Cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+
+ if (is_hermetic) {
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify caching") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(response->IsCached());
+ }
+ }
+ }
+
+ SECTION("Do not cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify caching") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(not response->IsCached());
+ }
+ }
+}
+
+[[nodiscard]] static inline auto TestOneInputCopiedToOutput(
+ ApiFactory const& api_factory,
+ ExecProps const& props,
+ bool is_hermetic = false) {
+ std::string test_content("test");
+ auto test_digest = ArtifactDigest::Create(test_content);
+
+ auto input_artifact_opt =
+ ArtifactFactory::FromDescription(ArtifactFactory::DescribeKnownArtifact(
+ test_digest.hash(), test_digest.size(), ObjectType::File));
+ CHECK(input_artifact_opt.has_value());
+ auto input_artifact =
+ DependencyGraph::ArtifactNode{std::move(*input_artifact_opt)};
+
+ std::string input_path{"dir/subdir/input"};
+ std::string output_path{"output_file"};
+
+ auto api = api_factory();
+ CHECK(api->Upload(BlobContainer{{BazelBlob{test_digest, test_content}}},
+ false));
+
+ auto action =
+ api->CreateAction(*api->UploadTree({{input_path, &input_artifact}}),
+ {"cp", input_path, output_path},
+ {output_path},
+ {},
+ {},
+ props);
+
+ SECTION("Cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+
+ if (is_hermetic) {
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify caching") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(response->IsCached());
+ }
+ }
+ }
+
+ SECTION("Do not cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify caching") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(not response->IsCached());
+ }
+ }
+}
+
+[[nodiscard]] static inline auto TestNonZeroExitCodeCreateOutput(
+ ApiFactory const& api_factory,
+ ExecProps const& props) {
+ std::string test_content("test");
+ auto test_digest = ArtifactDigest::Create(test_content);
+
+ std::string output_path{"output_file"};
+
+ auto api = api_factory();
+
+ auto action = api->CreateAction(*api->UploadTree({}),
+ {"/bin/sh",
+ "-c",
+ "set -e\necho -n " + test_content + " > " +
+ output_path + "\nexit 1\n"},
+ {output_path},
+ {},
+ {},
+ props);
+
+ SECTION("Cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->ExitCode() == 1);
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify that non-zero actions are rerun") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->ExitCode() == 1);
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(not response->IsCached());
+ }
+ }
+
+ SECTION("Do not cache execution result in action cache") {
+ action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
+
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->ExitCode() == 1);
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(not response->IsCached());
+
+ SECTION("Rerun execution to verify non-zero actions are not cached") {
+ // run execution
+ auto response = action->Execute();
+ REQUIRE(response);
+
+ // verify result
+ CHECK(response->ExitCode() == 1);
+ auto artifacts = response->Artifacts();
+ REQUIRE(artifacts.contains(output_path));
+ CHECK(artifacts.at(output_path).digest == test_digest);
+ CHECK(not response->IsCached());
+ }
+ }
+}
diff --git a/test/buildtool/execution_api/local/TARGETS b/test/buildtool/execution_api/local/TARGETS
index 1a86621f..92107bd8 100644
--- a/test/buildtool/execution_api/local/TARGETS
+++ b/test/buildtool/execution_api/local/TARGETS
@@ -45,8 +45,8 @@
, "deps":
[ ["@", "catch2", "", "catch2"]
, ["test", "catch-main"]
- , ["src/buildtool/common", "artifact_factory"]
, ["src/buildtool/execution_api/local", "local"]
+ , ["test/buildtool/execution_api/common", "api_test"]
, ["test/utils", "local_hermeticity"]
]
, "stage": ["test", "buildtool", "execution_api", "local"]
@@ -70,4 +70,4 @@
, "deps":
["local_ac", "local_api", "local_cas", "local_execution", "local_storage"]
}
-} \ No newline at end of file
+}
diff --git a/test/buildtool/execution_api/local/local_api.test.cpp b/test/buildtool/execution_api/local/local_api.test.cpp
index 39eaa6f0..e347c445 100644
--- a/test/buildtool/execution_api/local/local_api.test.cpp
+++ b/test/buildtool/execution_api/local/local_api.test.cpp
@@ -1,299 +1,37 @@
+#include <cstdlib>
#include <string>
#include "catch2/catch.hpp"
-#include "src/buildtool/common/artifact_factory.hpp"
-#include "src/buildtool/execution_api/common/execution_action.hpp"
-#include "src/buildtool/execution_api/common/execution_api.hpp"
-#include "src/buildtool/execution_api/common/execution_response.hpp"
#include "src/buildtool/execution_api/local/local_api.hpp"
+#include "test/buildtool/execution_api/common/api_test.hpp"
#include "test/utils/hermeticity/local.hpp"
-TEST_CASE_METHOD(HermeticLocalTestFixture,
- "LocalAPI: No input, no output",
- "[execution_api]") {
- std::string test_content("test");
-
- auto api = LocalApi();
-
- auto action = api.CreateAction(
- *api.UploadTree({}), {"echo", "-n", test_content}, {}, {}, {}, {});
-
- SECTION("Cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
+namespace {
- // verify result
- CHECK(response->HasStdOut());
- CHECK(response->StdOut() == test_content);
- CHECK(not response->IsCached());
+auto api_factory = []() { return IExecutionApi::Ptr{new LocalApi()}; };
- SECTION("Rerun execution to verify caching") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
+} // namespace
- // verify result
- CHECK(response->HasStdOut());
- CHECK(response->StdOut() == test_content);
- CHECK(response->IsCached());
- }
- }
-
- SECTION("Do not cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- CHECK(response->HasStdOut());
- CHECK(response->StdOut() == test_content);
- CHECK(not response->IsCached());
-
- SECTION("Rerun execution to verify caching") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- CHECK(response->HasStdOut());
- CHECK(response->StdOut() == test_content);
- CHECK(not response->IsCached());
- }
- }
+TEST_CASE_METHOD(HermeticLocalTestFixture,
+ "LocalAPI: No input, no output",
+ "[execution_api]") {
+ TestNoInputNoOutput(api_factory, {}, /*is_hermetic=*/true);
}
TEST_CASE_METHOD(HermeticLocalTestFixture,
"LocalAPI: No input, create output",
"[execution_api]") {
- std::string test_content("test");
- auto test_digest = ArtifactDigest::Create(test_content);
-
- std::string output_path{"output_file"};
-
- auto api = LocalApi();
-
- auto action = api.CreateAction(
- *api.UploadTree({}),
- {"/bin/sh",
- "-c",
- "set -e\necho -n " + test_content + " > " + output_path},
- {output_path},
- {},
- {},
- {});
-
- SECTION("Cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
-
- SECTION("Rerun execution to verify caching") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(response->IsCached());
- }
- }
-
- SECTION("Do not cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
-
- SECTION("Rerun execution to verify caching") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
- }
- }
+ TestNoInputCreateOutput(api_factory, {}, /*is_hermetic=*/true);
}
TEST_CASE_METHOD(HermeticLocalTestFixture,
"LocalAPI: One input copied to output",
"[execution_api]") {
- std::string test_content("test");
- auto test_digest = ArtifactDigest::Create(test_content);
-
- auto input_artifact_opt =
- ArtifactFactory::FromDescription(ArtifactFactory::DescribeKnownArtifact(
- test_digest.hash(), test_digest.size(), ObjectType::File));
- CHECK(input_artifact_opt.has_value());
- auto input_artifact =
- DependencyGraph::ArtifactNode{std::move(*input_artifact_opt)};
-
- std::string input_path{"dir/subdir/input"};
- std::string output_path{"output_file"};
-
- auto api = LocalApi();
- CHECK(api.Upload(BlobContainer{{BazelBlob{test_digest, test_content}}},
- false));
-
- auto action =
- api.CreateAction(*api.UploadTree({{input_path, &input_artifact}}),
- {"cp", input_path, output_path},
- {output_path},
- {},
- {},
- {});
-
- SECTION("Cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
-
- SECTION("Rerun execution to verify caching") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(response->IsCached());
- }
- }
-
- SECTION("Do not cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
-
- SECTION("Rerun execution to verify caching") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
- }
- }
+ TestOneInputCopiedToOutput(api_factory, {}, /*is_hermetic=*/true);
}
TEST_CASE_METHOD(HermeticLocalTestFixture,
"LocalAPI: Non-zero exit code, create output",
"[execution_api]") {
- std::string test_content("test");
- auto test_digest = ArtifactDigest::Create(test_content);
-
- std::string output_path{"output_file"};
-
- auto api = LocalApi();
-
- auto action = api.CreateAction(*api.UploadTree({}),
- {"/bin/sh",
- "-c",
- "set -e\necho -n " + test_content + " > " +
- output_path + "\nexit 1\n"},
- {output_path},
- {},
- {},
- {});
-
- SECTION("Cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::CacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- CHECK(response->ExitCode() == 1);
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
-
- SECTION("Rerun execution to verify that non-zero actions are rerun") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- CHECK(response->ExitCode() == 1);
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
- }
- }
-
- SECTION("Do not cache execution result in action cache") {
- action->SetCacheFlag(IExecutionAction::CacheFlag::DoNotCacheOutput);
-
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- CHECK(response->ExitCode() == 1);
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
-
- SECTION("Rerun execution to verify non-zero actions are not cached") {
- // run execution
- auto response = action->Execute();
- REQUIRE(response);
-
- // verify result
- CHECK(response->ExitCode() == 1);
- auto artifacts = response->Artifacts();
- REQUIRE(artifacts.contains(output_path));
- CHECK(artifacts.at(output_path).digest == test_digest);
- CHECK(not response->IsCached());
- }
- }
+ TestNonZeroExitCodeCreateOutput(api_factory, {});
}