diff --git a/xplat/Flipper/FlipperClient.cpp b/xplat/Flipper/FlipperClient.cpp index 0c3e39a5a..fc52f9b3e 100644 --- a/xplat/Flipper/FlipperClient.cpp +++ b/xplat/Flipper/FlipperClient.cpp @@ -1,23 +1,22 @@ /* - * Copyright (c) 2018-present, Facebook, Inc. + * Copyright (c) Facebook, Inc. * * This source code is licensed under the MIT license found in the LICENSE * file in the root directory of this source tree. * */ - #include "FlipperClient.h" +#include +#include +#include +#include +#include "ConnectionContextStore.h" #include "FlipperConnectionImpl.h" +#include "FlipperConnectionManagerImpl.h" #include "FlipperResponderImpl.h" #include "FlipperState.h" #include "FlipperStep.h" -#include "FlipperConnectionManagerImpl.h" -#include "ConnectionContextStore.h" #include "Log.h" -#include -#include -#include -#include #if FB_SONARKIT_ENABLED @@ -31,8 +30,10 @@ using folly::dynamic; void FlipperClient::init(FlipperInitConfig config) { auto state = std::make_shared(); auto context = std::make_shared(config.deviceData); - kInstance = - new FlipperClient(std::make_unique(std::move(config), state, context), state); + kInstance = new FlipperClient( + std::make_unique( + std::move(config), state, context), + state); } FlipperClient* FlipperClient::instance() { @@ -41,16 +42,18 @@ FlipperClient* FlipperClient::instance() { void FlipperClient::setStateListener( std::shared_ptr stateListener) { - log("Setting state listener"); - flipperState_->setUpdateListener(stateListener); + performAndReportError([this, &stateListener]() { + log("Setting state listener"); + flipperState_->setUpdateListener(stateListener); + }); } void FlipperClient::addPlugin(std::shared_ptr plugin) { - log("FlipperClient::addPlugin " + plugin->identifier()); - auto step = flipperState_->start("Add plugin " + plugin->identifier()); + performAndReportError([this, plugin]() { + log("FlipperClient::addPlugin " + plugin->identifier()); + auto step = flipperState_->start("Add plugin " + plugin->identifier()); - std::lock_guard lock(mutex_); - performAndReportError([this, plugin, step]() { + std::lock_guard lock(mutex_); if (plugins_.find(plugin->identifier()) != plugins_.end()) { throw std::out_of_range( "plugin " + plugin->identifier() + " already added."); @@ -64,10 +67,10 @@ void FlipperClient::addPlugin(std::shared_ptr plugin) { } void FlipperClient::removePlugin(std::shared_ptr plugin) { - log("FlipperClient::removePlugin " + plugin->identifier()); - - std::lock_guard lock(mutex_); performAndReportError([this, plugin]() { + log("FlipperClient::removePlugin " + plugin->identifier()); + + std::lock_guard lock(mutex_); if (plugins_.find(plugin->identifier()) == plugins_.end()) { throw std::out_of_range("plugin " + plugin->identifier() + " not added."); } @@ -79,18 +82,20 @@ void FlipperClient::removePlugin(std::shared_ptr plugin) { }); } - void FlipperClient::startBackgroundPlugins() { - std::cout << "Activating Background Plugins..." << std::endl; - for (std::map>::iterator it=plugins_.begin(); it!=plugins_.end(); ++it) { - std::cout << it->first << std::endl; - if (it->second.get()->runInBackground()) { - auto& conn = connections_[it->first]; - conn = std::make_shared(socket_.get(),it->first); - it->second.get()->didConnect(conn); - } - +void FlipperClient::startBackgroundPlugins() { + std::cout << "Activating Background Plugins..." << std::endl; + for (std::map>::iterator it = + plugins_.begin(); + it != plugins_.end(); + ++it) { + std::cout << it->first << std::endl; + if (it->second.get()->runInBackground()) { + auto& conn = connections_[it->first]; + conn = std::make_shared(socket_.get(), it->first); + it->second.get()->didConnect(conn); } } +} std::shared_ptr FlipperClient::getPlugin( const std::string& identifier) { @@ -115,26 +120,28 @@ void FlipperClient::disconnect(std::shared_ptr plugin) { } void FlipperClient::refreshPlugins() { - performAndReportError([this]() { - dynamic message = dynamic::object("method", "refreshPlugins"); - socket_->sendMessage(message); - }); + performAndReportError([this]() { + dynamic message = dynamic::object("method", "refreshPlugins"); + socket_->sendMessage(message); + }); } void FlipperClient::onConnected() { - log("FlipperClient::onConnected"); + performAndReportError([this]() { + log("FlipperClient::onConnected"); - std::lock_guard lock(mutex_); - connected_ = true; - startBackgroundPlugins(); + std::lock_guard lock(mutex_); + connected_ = true; + startBackgroundPlugins(); + }); } void FlipperClient::onDisconnected() { - log("FlipperClient::onDisconnected"); - auto step = flipperState_->start("Trigger onDisconnected callbacks"); - std::lock_guard lock(mutex_); - connected_ = false; - performAndReportError([this, step]() { + performAndReportError([this]() { + log("FlipperClient::onDisconnected"); + auto step = flipperState_->start("Trigger onDisconnected callbacks"); + std::lock_guard lock(mutex_); + connected_ = false; for (const auto& iter : plugins_) { disconnect(iter.second); } @@ -143,8 +150,8 @@ void FlipperClient::onDisconnected() { } void FlipperClient::onMessageReceived(const dynamic& message) { - std::lock_guard lock(mutex_); performAndReportError([this, &message]() { + std::lock_guard lock(mutex_); const auto& method = message["method"]; const auto& params = message.getDefault("params"); @@ -174,7 +181,8 @@ void FlipperClient::onMessageReceived(const dynamic& message) { const auto plugin = plugins_.at(identifier); if (!plugin.get()->runInBackground()) { auto& conn = connections_[plugin->identifier()]; - conn = std::make_shared(socket_.get(), plugin->identifier()); + conn = std::make_shared( + socket_.get(), plugin->identifier()); plugin->didConnect(conn); } return; @@ -214,20 +222,28 @@ void FlipperClient::onMessageReceived(const dynamic& message) { responder->error(response); }); } - void FlipperClient::performAndReportError(const std::function& func) { +#if FLIPPER_ENABLE_CRASH + // To debug the stack trace and an exception turn on the compiler flag + // FLIPPER_ENABLE_CRASH + func(); +#else try { func(); } catch (std::exception& e) { - dynamic message = dynamic::object( - "error", - dynamic::object("message", e.what())("stacktrace", "")); + dynamic message = dynamic::object( + "error", dynamic::object("message", e.what())("stacktrace", "")); if (connected_) { socket_->sendMessage(message); } else { - log("Error: " + std::string(e.what())); + log("Error: " + std::string(e.what())); } + } catch (...) { + // Generic catch block for the exception of type not belonging to + // std::exception + log("Unknown error suppressed in FlipperClient"); } +#endif } std::string FlipperClient::getState() { diff --git a/xplat/Flipper/FlipperClient.h b/xplat/Flipper/FlipperClient.h index 49c518328..4e4c7dbb4 100644 --- a/xplat/Flipper/FlipperClient.h +++ b/xplat/Flipper/FlipperClient.h @@ -1,22 +1,21 @@ /* - * Copyright (c) 2018-present, Facebook, Inc. + * Copyright (c) Facebook, Inc. * * This source code is licensed under the MIT license found in the LICENSE * file in the root directory of this source tree. * */ - #pragma once +#include +#include +#include #include "FlipperConnectionImpl.h" +#include "FlipperConnectionManager.h" #include "FlipperInitConfig.h" #include "FlipperPlugin.h" #include "FlipperState.h" -#include "FlipperConnectionManager.h" -#include -#include #include "FlipperStep.h" -#include namespace facebook { namespace flipper { @@ -24,23 +23,26 @@ namespace flipper { class FlipperClient : public FlipperConnectionManager::Callbacks { public: /** - Call before accessing instance with FlipperClient::instance(). This will set up - all the state needed to establish a Flipper connection. + Call before accessing instance with FlipperClient::instance(). This will set + up all the state needed to establish a Flipper connection. */ static void init(FlipperInitConfig config); /** Standard accessor for the shared FlipperClient instance. This returns a - singleton instance to a shared FlipperClient. First call to this function will - create the shared FlipperClient. Must call FlipperClient::initDeviceData() before - first call to FlipperClient::instance(). + singleton instance to a shared FlipperClient. First call to this function + will create the shared FlipperClient. Must call + FlipperClient::initDeviceData() before first call to + FlipperClient::instance(). */ static FlipperClient* instance(); /** Only public for testing */ - FlipperClient(std::unique_ptr socket, std::shared_ptr state) + FlipperClient( + std::unique_ptr socket, + std::shared_ptr state) : socket_(std::move(socket)), flipperState_(state) { auto step = flipperState_->start("Create client"); socket_->setCallbacks(this); @@ -48,15 +50,19 @@ class FlipperClient : public FlipperConnectionManager::Callbacks { } void start() { - auto step = flipperState_->start("Start client"); - socket_->start(); - step->complete(); + performAndReportError([this]() { + auto step = flipperState_->start("Start client"); + socket_->start(); + step->complete(); + }); } void stop() { - auto step = flipperState_->start("Stop client"); - socket_->stop(); - step->complete(); + performAndReportError([this]() { + auto step = flipperState_->start("Stop client"); + socket_->stop(); + step->complete(); + }); } void onConnected() override; @@ -86,6 +92,7 @@ class FlipperClient : public FlipperConnectionManager::Callbacks { } bool hasPlugin(const std::string& identifier); + void performAndReportError(const std::function& func); private: static FlipperClient* instance_; @@ -96,7 +103,6 @@ class FlipperClient : public FlipperConnectionManager::Callbacks { std::mutex mutex_; std::shared_ptr flipperState_; - void performAndReportError(const std::function& func); void disconnect(std::shared_ptr plugin); void startBackgroundPlugins(); }; diff --git a/xplat/Flipper/FlipperConnectionManagerImpl.cpp b/xplat/Flipper/FlipperConnectionManagerImpl.cpp index 30be9a64d..8fc7af78c 100644 --- a/xplat/Flipper/FlipperConnectionManagerImpl.cpp +++ b/xplat/Flipper/FlipperConnectionManagerImpl.cpp @@ -1,25 +1,24 @@ /* - * Copyright (c) 2018-present, Facebook, Inc. + * Copyright (c) Facebook, Inc. * * This source code is licensed under the MIT license found in the LICENSE * file in the root directory of this source tree. * */ - #include "FlipperConnectionManagerImpl.h" -#include "FlipperStep.h" -#include "ConnectionContextStore.h" -#include "Log.h" #include #include +#include #include #include #include #include #include -#include -#include #include +#include +#include "ConnectionContextStore.h" +#include "FlipperStep.h" +#include "Log.h" #define WRONG_THREAD_EXIT_MSG \ "ERROR: Aborting flipper initialization because it's not running in the flipper thread." @@ -39,7 +38,8 @@ class ConnectionEvents : public rsocket::RSocketConnectionEvents { FlipperConnectionManagerImpl* websocket_; public: - ConnectionEvents(FlipperConnectionManagerImpl* websocket) : websocket_(websocket) {} + ConnectionEvents(FlipperConnectionManagerImpl* websocket) + : websocket_(websocket) {} void onConnected() { websocket_->isOpen_ = true; @@ -79,11 +79,18 @@ class Responder : public rsocket::RSocketResponder { } }; -FlipperConnectionManagerImpl::FlipperConnectionManagerImpl(FlipperInitConfig config, std::shared_ptr state, std::shared_ptr contextStore) - : deviceData_(config.deviceData), flipperState_(state), flipperEventBase_(config.callbackWorker), connectionEventBase_(config.connectionWorker), contextStore_(contextStore) { - CHECK_THROW(config.callbackWorker, std::invalid_argument); - CHECK_THROW(config.connectionWorker, std::invalid_argument); - } +FlipperConnectionManagerImpl::FlipperConnectionManagerImpl( + FlipperInitConfig config, + std::shared_ptr state, + std::shared_ptr contextStore) + : deviceData_(config.deviceData), + flipperState_(state), + flipperEventBase_(config.callbackWorker), + connectionEventBase_(config.connectionWorker), + contextStore_(contextStore) { + CHECK_THROW(config.callbackWorker, std::invalid_argument); + CHECK_THROW(config.connectionWorker, std::invalid_argument); +} FlipperConnectionManagerImpl::~FlipperConnectionManagerImpl() { stop(); @@ -91,10 +98,14 @@ FlipperConnectionManagerImpl::~FlipperConnectionManagerImpl() { void FlipperConnectionManagerImpl::start() { auto step = flipperState_->start("Start connection thread"); + folly::makeFuture() .via(flipperEventBase_->getEventBase()) .delayed(std::chrono::milliseconds(0)) - .thenValue([this, step](auto&&){ step->complete(); startSync();}); + .thenValue([this, step](auto&&) { + step->complete(); + startSync(); + }); } void FlipperConnectionManagerImpl::startSync() { @@ -135,7 +146,6 @@ void FlipperConnectionManagerImpl::startSync() { } void FlipperConnectionManagerImpl::doCertificateExchange() { - rsocket::SetupParameters parameters; folly::SocketAddress address; @@ -175,7 +185,8 @@ void FlipperConnectionManagerImpl::connectSecurely() { "device_id", deviceId)("app", deviceData_.app))); address.setFromHostPort(deviceData_.host, securePort); - std::shared_ptr sslContext = contextStore_->getSSLContext(); + std::shared_ptr sslContext = + contextStore_->getSSLContext(); auto connectingSecurely = flipperState_->start("Connect securely"); connectionIsTrusted_ = true; client_ = @@ -198,7 +209,7 @@ void FlipperConnectionManagerImpl::reconnect() { folly::makeFuture() .via(flipperEventBase_->getEventBase()) .delayed(std::chrono::seconds(reconnectIntervalSeconds)) - .thenValue([this](auto&&){ startSync(); }); + .thenValue([this](auto&&) { startSync(); }); } void FlipperConnectionManagerImpl::stop() { @@ -240,7 +251,6 @@ void FlipperConnectionManagerImpl::sendMessage(const folly::dynamic& message) { } bool FlipperConnectionManagerImpl::isCertificateExchangeNeeded() { - if (failedConnectionAttempts_ >= 2) { return true; } @@ -258,59 +268,66 @@ void FlipperConnectionManagerImpl::requestSignedCertFromFlipper() { std::string csr = contextStore_->createCertificateSigningRequest(); generatingCSR->complete(); - folly::dynamic message = folly::dynamic::object("method", "signCertificate")( - "csr", csr.c_str())("destination", contextStore_->getCertificateDirectoryPath().c_str()); + folly::dynamic message = + folly::dynamic::object("method", "signCertificate")("csr", csr.c_str())( + "destination", contextStore_->getCertificateDirectoryPath().c_str()); auto gettingCert = flipperState_->start("Getting cert from desktop"); flipperEventBase_->add([this, message, gettingCert]() { client_->getRequester() ->requestResponse(rsocket::Payload(folly::toJson(message))) - ->subscribe([this, gettingCert](rsocket::Payload p) { - auto response = p.moveDataToString(); - if (!response.empty()) { - folly::dynamic config = folly::parseJson(response); - contextStore_->storeConnectionConfig(config); - } - gettingCert->complete(); - log("Certificate exchange complete."); - // Disconnect after message sending is complete. - // This will trigger a reconnect which should use the secure channel. - // TODO: Connect immediately, without waiting for reconnect - client_ = nullptr; - }, - [this, message](folly::exception_wrapper e) { - e.handle( - [&](rsocket::ErrorWithPayload& errorWithPayload) { - std::string errorMessage = errorWithPayload.payload.moveDataToString(); - - if (errorMessage.compare("not implemented")) { - log("Desktop failed to provide certificates. Error from flipper desktop:\n" + errorMessage); - client_ = nullptr; - } else { - sendLegacyCertificateRequest(message); - } + ->subscribe( + [this, gettingCert](rsocket::Payload p) { + auto response = p.moveDataToString(); + if (!response.empty()) { + folly::dynamic config = folly::parseJson(response); + contextStore_->storeConnectionConfig(config); + } + gettingCert->complete(); + log("Certificate exchange complete."); + // Disconnect after message sending is complete. + // This will trigger a reconnect which should use the secure + // channel. + // TODO: Connect immediately, without waiting for reconnect + client_ = nullptr; }, - [e](...) { - log(("Error during certificate exchange:" + e.what()).c_str()); - } - ); - }); + [this, message](folly::exception_wrapper e) { + e.handle( + [&](rsocket::ErrorWithPayload& errorWithPayload) { + std::string errorMessage = + errorWithPayload.payload.moveDataToString(); + + if (errorMessage.compare("not implemented")) { + log("Desktop failed to provide certificates. Error from flipper desktop:\n" + + errorMessage); + client_ = nullptr; + } else { + sendLegacyCertificateRequest(message); + } + }, + [e](...) { + log(("Error during certificate exchange:" + e.what()) + .c_str()); + }); + }); }); failedConnectionAttempts_ = 0; } -void FlipperConnectionManagerImpl::sendLegacyCertificateRequest(folly::dynamic message) { +void FlipperConnectionManagerImpl::sendLegacyCertificateRequest( + folly::dynamic message) { // Desktop is using an old version of Flipper. // Fall back to fireAndForget, instead of requestResponse. - auto sendingRequest = flipperState_->start("Sending fallback certificate request"); + auto sendingRequest = + flipperState_->start("Sending fallback certificate request"); client_->getRequester() - ->fireAndForget(rsocket::Payload(folly::toJson(message))) - ->subscribe([this, sendingRequest]() { - sendingRequest->complete(); - folly::dynamic config = folly::dynamic::object(); - contextStore_->storeConnectionConfig(config); - client_ = nullptr; - }); + ->fireAndForget(rsocket::Payload(folly::toJson(message))) + ->subscribe([this, sendingRequest]() { + sendingRequest->complete(); + folly::dynamic config = folly::dynamic::object(); + contextStore_->storeConnectionConfig(config); + client_ = nullptr; + }); } bool FlipperConnectionManagerImpl::isRunningInOwnThread() { diff --git a/xplat/FlipperTests/FlipperClientTests.cpp b/xplat/FlipperTests/FlipperClientTests.cpp index 1eb08eb91..1d7aecf97 100644 --- a/xplat/FlipperTests/FlipperClientTests.cpp +++ b/xplat/FlipperTests/FlipperClientTests.cpp @@ -6,8 +6,8 @@ * */ #include -#include #include +#include #include #include @@ -33,7 +33,8 @@ TEST(FlipperClientTests, testSaneMocks) { TEST(FlipperClientTests, testGetPlugins) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); client.start(); client.addPlugin(std::make_shared("Cat")); @@ -49,7 +50,8 @@ TEST(FlipperClientTests, testGetPlugins) { TEST(FlipperClientTests, testGetPlugin) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); const auto catPlugin = std::make_shared("Cat"); client.addPlugin(catPlugin); @@ -62,7 +64,8 @@ TEST(FlipperClientTests, testGetPlugin) { TEST(FlipperClientTests, testGetPluginWithDowncast) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); const auto catPlugin = std::make_shared("Cat"); client.addPlugin(catPlugin); @@ -71,7 +74,8 @@ TEST(FlipperClientTests, testGetPluginWithDowncast) { TEST(FlipperClientTests, testRemovePlugin) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); client.start(); auto plugin = std::make_shared("Test"); @@ -88,7 +92,8 @@ TEST(FlipperClientTests, testRemovePlugin) { TEST(FlipperClientTests, testStartStop) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); client.start(); EXPECT_TRUE(socket->isOpen()); @@ -99,15 +104,16 @@ TEST(FlipperClientTests, testStartStop) { TEST(FlipperClientTests, testConnectDisconnect) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); bool pluginConnected = false; const auto connectionCallback = [&](std::shared_ptr conn) { pluginConnected = true; }; const auto disconnectionCallback = [&]() { pluginConnected = false; }; - auto plugin = std::make_shared("Test", connectionCallback, - disconnectionCallback); + auto plugin = std::make_shared( + "Test", connectionCallback, disconnectionCallback); client.addPlugin(plugin); client.start(); @@ -122,15 +128,16 @@ TEST(FlipperClientTests, testConnectDisconnect) { TEST(FlipperClientTests, testInitDeinit) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); bool pluginConnected = false; const auto connectionCallback = [&](std::shared_ptr conn) { pluginConnected = true; }; const auto disconnectionCallback = [&]() { pluginConnected = false; }; - auto plugin = std::make_shared("Test", connectionCallback, - disconnectionCallback); + auto plugin = std::make_shared( + "Test", connectionCallback, disconnectionCallback); client.start(); client.addPlugin(plugin); @@ -160,15 +167,16 @@ TEST(FlipperClientTests, testInitDeinit) { TEST(FlipperClientTests, testRemovePluginWhenConnected) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); bool pluginConnected = false; const auto connectionCallback = [&](std::shared_ptr conn) { pluginConnected = true; }; const auto disconnectionCallback = [&]() { pluginConnected = false; }; - auto plugin = std::make_shared("Test", connectionCallback, - disconnectionCallback); + auto plugin = std::make_shared( + "Test", connectionCallback, disconnectionCallback); client.addPlugin(plugin); client.start(); @@ -181,7 +189,8 @@ TEST(FlipperClientTests, testRemovePluginWhenConnected) { TEST(FlipperClientTests, testUnhandleableMethod) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); auto plugin = std::make_shared("Test"); client.addPlugin(plugin); @@ -201,11 +210,12 @@ TEST(FlipperClientTests, testUnhandleableMethod) { TEST(FlipperClientTests, testExecute) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); client.start(); const auto connectionCallback = [](std::shared_ptr conn) { - const auto receiver = [](const dynamic ¶ms, + const auto receiver = [](const dynamic& params, std::unique_ptr responder) { dynamic payload = dynamic::object("message", "yes_i_hear_u"); responder->success(payload); @@ -231,13 +241,14 @@ TEST(FlipperClientTests, testExecute) { TEST(FlipperClientTests, testExecuteWithParams) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); const auto connectionCallback = [&](std::shared_ptr conn) { - const auto receiver = [](const dynamic ¶ms, + const auto receiver = [](const dynamic& params, std::unique_ptr responder) { - const auto &first = params["first"].asString(); - const auto &second = params["second"].asString(); + const auto& first = params["first"].asString(); + const auto& second = params["second"].asString(); std::map m{{"dog", "woof"}, {"cat", "meow"}}; dynamic payload = dynamic::object(first, m[first])(second, m[second]); responder->success(payload); @@ -264,28 +275,32 @@ TEST(FlipperClientTests, testExecuteWithParams) { TEST(FlipperClientTests, testExceptionUnknownPlugin) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); client.start(); dynamic messageInit = dynamic::object("method", "init")( "params", dynamic::object("plugin", "Unknown")); socket->callbacks->onMessageReceived(messageInit); - EXPECT_EQ(socket->messages.back()["error"]["message"], - "plugin Unknown not found for method init"); + EXPECT_EQ( + socket->messages.back()["error"]["message"], + "plugin Unknown not found for method init"); } TEST(FlipperClientTests, testExceptionUnknownApi) { auto socket = new FlipperConnectionManagerMock; - FlipperClient client(std::unique_ptr{socket}, state); + FlipperClient client( + std::unique_ptr{socket}, state); client.start(); dynamic messageInit = dynamic::object("method", "execute")( "params", dynamic::object("api", "Unknown")); socket->callbacks->onMessageReceived(messageInit); - EXPECT_EQ(socket->messages.back()["error"]["message"], - "connection Unknown not found for method execute"); + EXPECT_EQ( + socket->messages.back()["error"]["message"], + "connection Unknown not found for method execute"); } TEST(FlipperClientTests, testBackgroundPluginActivated) { @@ -328,6 +343,46 @@ TEST(FlipperClientTests, testNonBackgroundPluginNotActivated) { EXPECT_FALSE(pluginConnected); } +TEST(FlipperClientTests, testCrashInDidConnectDisConnectIsSuppressed) { + auto socket = new FlipperConnectionManagerMock; + FlipperClient client( + std::unique_ptr{socket}, state); + + const auto connectionCallback = [&](std::shared_ptr conn) { + throw std::runtime_error("Runtime Error in test"); + }; + const auto disconnectionCallback = [&]() { + throw std::runtime_error("Runtime Error in test"); + }; + auto plugin = std::make_shared( + "Test", connectionCallback, disconnectionCallback, true); + + client.addPlugin(plugin); + + EXPECT_NO_FATAL_FAILURE(client.start()); + EXPECT_NO_FATAL_FAILURE(client.stop()); +} + +TEST( + FlipperClientTests, + testNonStandardCrashInDidConnectDisConnectIsSuppressed) { + auto socket = new FlipperConnectionManagerMock; + FlipperClient client( + std::unique_ptr{socket}, state); + + const auto connectionCallback = [&](std::shared_ptr conn) { + throw "Non standard exception"; + }; + const auto disconnectionCallback = [&]() { throw "Non standard exception"; }; + auto plugin = std::make_shared( + "Test", connectionCallback, disconnectionCallback, true); + + client.addPlugin(plugin); + + EXPECT_NO_FATAL_FAILURE(client.start()); + EXPECT_NO_FATAL_FAILURE(client.stop()); +} + } // namespace test } // namespace flipper } // namespace facebook