Wrap flipper client methods to avoid crash
Summary: Wraps flipper client methods to avoid crash. Also added a tests which makes sure that malcious plugin cannot cause a crash Reviewed By: jknoxville Differential Revision: D13153277 fbshipit-source-id: ac21731fa3c4eb447f189e61f61b9e83aad91e13
This commit is contained in:
committed by
Facebook Github Bot
parent
37c973d0c9
commit
bf3be3e16c
@@ -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 <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#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 <vector>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
@@ -31,8 +30,10 @@ using folly::dynamic;
|
||||
void FlipperClient::init(FlipperInitConfig config) {
|
||||
auto state = std::make_shared<FlipperState>();
|
||||
auto context = std::make_shared<ConnectionContextStore>(config.deviceData);
|
||||
kInstance =
|
||||
new FlipperClient(std::make_unique<FlipperConnectionManagerImpl>(std::move(config), state, context), state);
|
||||
kInstance = new FlipperClient(
|
||||
std::make_unique<FlipperConnectionManagerImpl>(
|
||||
std::move(config), state, context),
|
||||
state);
|
||||
}
|
||||
|
||||
FlipperClient* FlipperClient::instance() {
|
||||
@@ -41,16 +42,18 @@ FlipperClient* FlipperClient::instance() {
|
||||
|
||||
void FlipperClient::setStateListener(
|
||||
std::shared_ptr<FlipperStateUpdateListener> stateListener) {
|
||||
log("Setting state listener");
|
||||
flipperState_->setUpdateListener(stateListener);
|
||||
performAndReportError([this, &stateListener]() {
|
||||
log("Setting state listener");
|
||||
flipperState_->setUpdateListener(stateListener);
|
||||
});
|
||||
}
|
||||
|
||||
void FlipperClient::addPlugin(std::shared_ptr<FlipperPlugin> 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<std::mutex> lock(mutex_);
|
||||
performAndReportError([this, plugin, step]() {
|
||||
std::lock_guard<std::mutex> 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<FlipperPlugin> plugin) {
|
||||
}
|
||||
|
||||
void FlipperClient::removePlugin(std::shared_ptr<FlipperPlugin> plugin) {
|
||||
log("FlipperClient::removePlugin " + plugin->identifier());
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
performAndReportError([this, plugin]() {
|
||||
log("FlipperClient::removePlugin " + plugin->identifier());
|
||||
|
||||
std::lock_guard<std::mutex> 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<FlipperPlugin> plugin) {
|
||||
});
|
||||
}
|
||||
|
||||
void FlipperClient::startBackgroundPlugins() {
|
||||
std::cout << "Activating Background Plugins..." << std::endl;
|
||||
for (std::map<std::string, std::shared_ptr<FlipperPlugin>>::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<FlipperConnectionImpl>(socket_.get(),it->first);
|
||||
it->second.get()->didConnect(conn);
|
||||
}
|
||||
|
||||
void FlipperClient::startBackgroundPlugins() {
|
||||
std::cout << "Activating Background Plugins..." << std::endl;
|
||||
for (std::map<std::string, std::shared_ptr<FlipperPlugin>>::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<FlipperConnectionImpl>(socket_.get(), it->first);
|
||||
it->second.get()->didConnect(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<FlipperPlugin> FlipperClient::getPlugin(
|
||||
const std::string& identifier) {
|
||||
@@ -115,26 +120,28 @@ void FlipperClient::disconnect(std::shared_ptr<FlipperPlugin> 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<std::mutex> lock(mutex_);
|
||||
connected_ = true;
|
||||
startBackgroundPlugins();
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
connected_ = true;
|
||||
startBackgroundPlugins();
|
||||
});
|
||||
}
|
||||
|
||||
void FlipperClient::onDisconnected() {
|
||||
log("FlipperClient::onDisconnected");
|
||||
auto step = flipperState_->start("Trigger onDisconnected callbacks");
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
connected_ = false;
|
||||
performAndReportError([this, step]() {
|
||||
performAndReportError([this]() {
|
||||
log("FlipperClient::onDisconnected");
|
||||
auto step = flipperState_->start("Trigger onDisconnected callbacks");
|
||||
std::lock_guard<std::mutex> 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<std::mutex> lock(mutex_);
|
||||
performAndReportError([this, &message]() {
|
||||
std::lock_guard<std::mutex> 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<FlipperConnectionImpl>(socket_.get(), plugin->identifier());
|
||||
conn = std::make_shared<FlipperConnectionImpl>(
|
||||
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<void()>& 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", "<none>"));
|
||||
dynamic message = dynamic::object(
|
||||
"error", dynamic::object("message", e.what())("stacktrace", "<none>"));
|
||||
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() {
|
||||
|
||||
@@ -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 <map>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include "FlipperConnectionImpl.h"
|
||||
#include "FlipperConnectionManager.h"
|
||||
#include "FlipperInitConfig.h"
|
||||
#include "FlipperPlugin.h"
|
||||
#include "FlipperState.h"
|
||||
#include "FlipperConnectionManager.h"
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include "FlipperStep.h"
|
||||
#include <vector>
|
||||
|
||||
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<FlipperConnectionManager> socket, std::shared_ptr<FlipperState> state)
|
||||
FlipperClient(
|
||||
std::unique_ptr<FlipperConnectionManager> socket,
|
||||
std::shared_ptr<FlipperState> 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<void()>& func);
|
||||
|
||||
private:
|
||||
static FlipperClient* instance_;
|
||||
@@ -96,7 +103,6 @@ class FlipperClient : public FlipperConnectionManager::Callbacks {
|
||||
std::mutex mutex_;
|
||||
std::shared_ptr<FlipperState> flipperState_;
|
||||
|
||||
void performAndReportError(const std::function<void()>& func);
|
||||
void disconnect(std::shared_ptr<FlipperPlugin> plugin);
|
||||
void startBackgroundPlugins();
|
||||
};
|
||||
|
||||
@@ -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 <folly/String.h>
|
||||
#include <folly/futures/Future.h>
|
||||
#include <folly/io/async/AsyncSocketException.h>
|
||||
#include <folly/io/async/SSLContext.h>
|
||||
#include <folly/json.h>
|
||||
#include <rsocket/Payload.h>
|
||||
#include <rsocket/RSocket.h>
|
||||
#include <rsocket/transports/tcp/TcpConnectionFactory.h>
|
||||
#include <thread>
|
||||
#include <folly/io/async/AsyncSocketException.h>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#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<FlipperState> state, std::shared_ptr<ConnectionContextStore> 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<FlipperState> state,
|
||||
std::shared_ptr<ConnectionContextStore> 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<folly::SSLContext> sslContext = contextStore_->getSSLContext();
|
||||
std::shared_ptr<folly::SSLContext> 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() {
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
*
|
||||
*/
|
||||
#include <Flipper/FlipperClient.h>
|
||||
#include <FlipperTestLib/FlipperPluginMock.h>
|
||||
#include <FlipperTestLib/FlipperConnectionManagerMock.h>
|
||||
#include <FlipperTestLib/FlipperPluginMock.h>
|
||||
|
||||
#include <folly/json.h>
|
||||
#include <gtest/gtest.h>
|
||||
@@ -33,7 +33,8 @@ TEST(FlipperClientTests, testSaneMocks) {
|
||||
|
||||
TEST(FlipperClientTests, testGetPlugins) {
|
||||
auto socket = new FlipperConnectionManagerMock;
|
||||
FlipperClient client(std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
client.start();
|
||||
|
||||
client.addPlugin(std::make_shared<FlipperPluginMock>("Cat"));
|
||||
@@ -49,7 +50,8 @@ TEST(FlipperClientTests, testGetPlugins) {
|
||||
|
||||
TEST(FlipperClientTests, testGetPlugin) {
|
||||
auto socket = new FlipperConnectionManagerMock;
|
||||
FlipperClient client(std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
const auto catPlugin = std::make_shared<FlipperPluginMock>("Cat");
|
||||
client.addPlugin(catPlugin);
|
||||
@@ -62,7 +64,8 @@ TEST(FlipperClientTests, testGetPlugin) {
|
||||
|
||||
TEST(FlipperClientTests, testGetPluginWithDowncast) {
|
||||
auto socket = new FlipperConnectionManagerMock;
|
||||
FlipperClient client(std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
const auto catPlugin = std::make_shared<FlipperPluginMock>("Cat");
|
||||
client.addPlugin(catPlugin);
|
||||
@@ -71,7 +74,8 @@ TEST(FlipperClientTests, testGetPluginWithDowncast) {
|
||||
|
||||
TEST(FlipperClientTests, testRemovePlugin) {
|
||||
auto socket = new FlipperConnectionManagerMock;
|
||||
FlipperClient client(std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
client.start();
|
||||
|
||||
auto plugin = std::make_shared<FlipperPluginMock>("Test");
|
||||
@@ -88,7 +92,8 @@ TEST(FlipperClientTests, testRemovePlugin) {
|
||||
|
||||
TEST(FlipperClientTests, testStartStop) {
|
||||
auto socket = new FlipperConnectionManagerMock;
|
||||
FlipperClient client(std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{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<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
bool pluginConnected = false;
|
||||
const auto connectionCallback = [&](std::shared_ptr<FlipperConnection> conn) {
|
||||
pluginConnected = true;
|
||||
};
|
||||
const auto disconnectionCallback = [&]() { pluginConnected = false; };
|
||||
auto plugin = std::make_shared<FlipperPluginMock>("Test", connectionCallback,
|
||||
disconnectionCallback);
|
||||
auto plugin = std::make_shared<FlipperPluginMock>(
|
||||
"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<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
bool pluginConnected = false;
|
||||
const auto connectionCallback = [&](std::shared_ptr<FlipperConnection> conn) {
|
||||
pluginConnected = true;
|
||||
};
|
||||
const auto disconnectionCallback = [&]() { pluginConnected = false; };
|
||||
auto plugin = std::make_shared<FlipperPluginMock>("Test", connectionCallback,
|
||||
disconnectionCallback);
|
||||
auto plugin = std::make_shared<FlipperPluginMock>(
|
||||
"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<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
bool pluginConnected = false;
|
||||
const auto connectionCallback = [&](std::shared_ptr<FlipperConnection> conn) {
|
||||
pluginConnected = true;
|
||||
};
|
||||
const auto disconnectionCallback = [&]() { pluginConnected = false; };
|
||||
auto plugin = std::make_shared<FlipperPluginMock>("Test", connectionCallback,
|
||||
disconnectionCallback);
|
||||
auto plugin = std::make_shared<FlipperPluginMock>(
|
||||
"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<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
auto plugin = std::make_shared<FlipperPluginMock>("Test");
|
||||
client.addPlugin(plugin);
|
||||
@@ -201,11 +210,12 @@ TEST(FlipperClientTests, testUnhandleableMethod) {
|
||||
|
||||
TEST(FlipperClientTests, testExecute) {
|
||||
auto socket = new FlipperConnectionManagerMock;
|
||||
FlipperClient client(std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
client.start();
|
||||
|
||||
const auto connectionCallback = [](std::shared_ptr<FlipperConnection> conn) {
|
||||
const auto receiver = [](const dynamic ¶ms,
|
||||
const auto receiver = [](const dynamic& params,
|
||||
std::unique_ptr<FlipperResponder> 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<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
const auto connectionCallback = [&](std::shared_ptr<FlipperConnection> conn) {
|
||||
const auto receiver = [](const dynamic ¶ms,
|
||||
const auto receiver = [](const dynamic& params,
|
||||
std::unique_ptr<FlipperResponder> 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<std::string, std::string> 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<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{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<FlipperConnectionManagerMock>{socket}, state);
|
||||
FlipperClient client(
|
||||
std::unique_ptr<FlipperConnectionManagerMock>{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<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
const auto connectionCallback = [&](std::shared_ptr<FlipperConnection> 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<FlipperPluginMock>(
|
||||
"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<FlipperConnectionManagerMock>{socket}, state);
|
||||
|
||||
const auto connectionCallback = [&](std::shared_ptr<FlipperConnection> conn) {
|
||||
throw "Non standard exception";
|
||||
};
|
||||
const auto disconnectionCallback = [&]() { throw "Non standard exception"; };
|
||||
auto plugin = std::make_shared<FlipperPluginMock>(
|
||||
"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
|
||||
|
||||
Reference in New Issue
Block a user