This repository has been archived by the owner on Mar 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use 'exec*()' to perform client and server death tests
Before this commit we tried to perform the death part of the client or server death tests in the forked child process created from 'ASSERT_DEATH()'. This has "worked" but investigating ongoing flaky tests suggests this approach is insufficient. This commit does less in the forked child by immediately doing an 'exec*()'.
- Loading branch information
Showing
7 changed files
with
294 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include "eventuals/grpc/client.h" | ||
#include "eventuals/terminal.h" | ||
#include "eventuals/then.h" | ||
#include "examples/protos/helloworld.grpc.pb.h" | ||
|
||
using helloworld::Greeter; | ||
using helloworld::HelloReply; | ||
using helloworld::HelloRequest; | ||
|
||
using stout::Borrowable; | ||
|
||
using eventuals::Eventual; | ||
using eventuals::Terminate; | ||
using eventuals::Then; | ||
|
||
using eventuals::grpc::Client; | ||
using eventuals::grpc::CompletionPool; | ||
|
||
int main(int argc, char** argv) { | ||
CHECK(argc == 3) | ||
<< "expecting 'pipe_fork' and 'pipe_port' to be passed as arguments"; | ||
|
||
int pipe_fork = atoi(argv[1]); | ||
int pipe_port = atoi(argv[2]); | ||
|
||
auto NotifyForked = [&]() { | ||
int one = 1; | ||
CHECK_GT(write(pipe_fork, &one, sizeof(int)), 0); | ||
}; | ||
|
||
auto WaitForPort = [&]() { | ||
int port; | ||
CHECK_GT(read(pipe_port, &port, sizeof(int)), 0); | ||
return port; | ||
}; | ||
|
||
NotifyForked(); | ||
|
||
int port = WaitForPort(); | ||
|
||
Borrowable<CompletionPool> pool; | ||
|
||
Client client( | ||
"0.0.0.0:" + std::to_string(port), | ||
grpc::InsecureChannelCredentials(), | ||
pool.Borrow()); | ||
|
||
auto call = [&]() { | ||
return client.Call<Greeter, HelloRequest, HelloReply>("SayHello") | ||
| Then([](auto&& call) { | ||
// NOTE: to avoid false positives with, for example, one | ||
// of the 'CHECK()'s failing above, the 'ClientDeathTest' | ||
// expects the string 'connected' to be written to stderr. | ||
std::cerr << "connected" << std::endl; | ||
exit(1); | ||
}); | ||
}; | ||
|
||
*call(); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#include "eventuals/grpc/server.h" | ||
#include "eventuals/head.h" | ||
#include "eventuals/terminal.h" | ||
#include "eventuals/then.h" | ||
#include "examples/protos/helloworld.grpc.pb.h" | ||
|
||
using helloworld::Greeter; | ||
using helloworld::HelloReply; | ||
using helloworld::HelloRequest; | ||
|
||
using eventuals::Head; | ||
using eventuals::Terminate; | ||
using eventuals::Then; | ||
|
||
using eventuals::grpc::Server; | ||
using eventuals::grpc::ServerBuilder; | ||
|
||
int main(int argc, char** argv) { | ||
CHECK(argc == 2) << "expecting 'pipe' to be passed as an argument"; | ||
|
||
int pipe = atoi(argv[1]); | ||
|
||
auto SendPort = [&](int port) { | ||
CHECK_GT(write(pipe, &port, sizeof(port)), 0); | ||
}; | ||
|
||
ServerBuilder builder; | ||
|
||
int port = 0; | ||
|
||
builder.AddListeningPort( | ||
"0.0.0.0:0", | ||
grpc::InsecureServerCredentials(), | ||
&port); | ||
|
||
auto build = builder.BuildAndStart(); | ||
|
||
CHECK(build.status.ok()); | ||
|
||
auto server = std::move(build.server); | ||
|
||
CHECK(server); | ||
|
||
auto serve = [&]() { | ||
return server->Accept<Greeter, HelloRequest, HelloReply>("SayHello") | ||
| Head() | ||
| Then([](auto&& call) { | ||
// NOTE: to avoid false positives with, for example, one | ||
// of the 'CHECK()'s failing above, the 'ServerDeathTest' | ||
// expects the string 'accepted' to be written to stderr. | ||
std::cerr << "accepted" << std::endl; | ||
exit(1); | ||
}); | ||
}; | ||
|
||
auto [future, k] = Terminate(serve()); | ||
|
||
k.Start(); | ||
|
||
// NOTE: sending this _after_ we start the eventual so that we're | ||
// ready to accept clients! | ||
SendPort(port); | ||
|
||
future.get(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include "gtest/gtest.h" | ||
#include "test/test.h" | ||
#include "tools/cpp/runfiles/runfiles.h" | ||
|
||
//////////////////////////////////////////////////////////////////////// | ||
|
||
// NOTE: using a raw pointer here as per Google C++ Style Guide | ||
// because 'bazel::tools::cpp::runfiles::Runfiles' is not trivially | ||
// destructible. | ||
static bazel::tools::cpp::runfiles::Runfiles* runfiles = nullptr; | ||
|
||
//////////////////////////////////////////////////////////////////////// | ||
|
||
// Declared in test.h. | ||
std::filesystem::path GetRunfilePathFor(const std::filesystem::path& runfile) { | ||
std::string path = CHECK_NOTNULL(runfiles)->Rlocation(runfile); | ||
|
||
CHECK(!path.empty()) << "runfile " << runfile << " does not exist"; | ||
|
||
return path; | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////// | ||
|
||
int main(int argc, char** argv) { | ||
std::string error; | ||
|
||
// NOTE: using 'Create()' instead of 'CreateForTest()' so that we | ||
// can support both running the test via 'bazel test' or explicitly | ||
// (i.e., ./path/to/test --gtest_...). | ||
runfiles = bazel::tools::cpp::runfiles::Runfiles::Create( | ||
argv[0], | ||
std::string(), | ||
std::filesystem::absolute(argv[0]).parent_path().string(), | ||
&error); | ||
|
||
if (runfiles == nullptr) { | ||
std::cerr | ||
<< "Failed to construct 'Runfiles' necessary for getting " | ||
<< "paths to assets needed in order to run tests: " | ||
<< error << std::endl; | ||
return -1; | ||
} | ||
|
||
::testing::InitGoogleTest(&argc, argv); | ||
|
||
return RUN_ALL_TESTS(); | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////// |
Oops, something went wrong.