Make Env::AppBundle constructor exception safe

When the Env::AppBundle constructor throws an exception
it still needs to run ~AppBundle(), otherwise the JobQueue
isn't properly shut down.  Specifically the  JobQueue
can destruct without waiting on outstanding jobs in the
queue.

This change ensures that if Env::AppBundle constructor
throws, Env::AppBundle::~AppBundle() runs.

This fixes the unit test crash exposed by PR #3047.
This commit is contained in:
Howard Hinnant
2019-10-17 20:21:24 -04:00
committed by Manoj doshi
parent 41b2c80dde
commit 726dd69ab9
3 changed files with 28 additions and 5 deletions

View File

@@ -124,12 +124,13 @@ public:
private:
struct AppBundle
{
Application* app;
Application* app = nullptr;
std::unique_ptr<Application> owned;
ManualTimeKeeper* timeKeeper;
ManualTimeKeeper* timeKeeper = nullptr;
std::thread thread;
std::unique_ptr<AbstractClient> client;
AppBundle() = default;
AppBundle (beast::unit_test::suite& suite,
std::unique_ptr<Config> config,
std::unique_ptr<Logs> logs);

View File

@@ -749,6 +749,22 @@ public:
}
}
void testExceptionalShutdown()
{
except(
[this]
{
jtx::Env env {*this,
jtx::envconfig([](std::unique_ptr<Config> cfg)
{
(*cfg).deprecatedClearSection("port_rpc");
return cfg;
})};
}
);
pass();
}
void
run() override
{
@@ -771,6 +787,7 @@ public:
testResignSigned();
testSignAndSubmit();
testFeatures();
testExceptionalShutdown();
}
};

View File

@@ -59,6 +59,7 @@ namespace jtx {
Env::AppBundle::AppBundle(beast::unit_test::suite& suite,
std::unique_ptr<Config> config,
std::unique_ptr<Logs> logs)
: AppBundle()
{
using namespace beast::severities;
// Use kFatal threshold to reduce noise from STObject.
@@ -89,9 +90,13 @@ Env::AppBundle::~AppBundle()
client.reset();
// Make sure all jobs finish, otherwise tests
// might not get the coverage they expect.
app->getJobQueue().rendezvous();
app->signalStop();
thread.join();
if (app)
{
app->getJobQueue().rendezvous();
app->signalStop();
}
if (thread.joinable())
thread.join();
// Remove the debugLogSink before the suite goes out of scope.
setDebugLogSink (nullptr);