mirror of
https://github.com/falk-werner/webfuse
synced 2025-06-13 12:54:15 +00:00
added unit tests for server
This commit is contained in:
parent
e4c32add31
commit
778435cf02
@ -77,7 +77,7 @@ bool File::hasSubdirectory(std::string const & subdir)
|
|||||||
bool File::hasContents(std::string const & contents)
|
bool File::hasContents(std::string const & contents)
|
||||||
{
|
{
|
||||||
std::stringstream command;
|
std::stringstream command;
|
||||||
command << "./fs_check -c has_contents -f " << path_ << " -a " << contents;
|
command << "./fs_check -c has_contents -f " << path_ << " -a \'" << contents << "\'";
|
||||||
|
|
||||||
return invoke(command.str());
|
return invoke(command.str());
|
||||||
}
|
}
|
||||||
|
36
test/webfuse/mocks/getattr_matcher.hpp
Normal file
36
test/webfuse/mocks/getattr_matcher.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef WF_GETATTR_MATCHER_HPP
|
||||||
|
#define WF_GETATTR_MATCHER_HPP
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
namespace webfuse_test
|
||||||
|
{
|
||||||
|
|
||||||
|
MATCHER_P(GetAttr, inode, "")
|
||||||
|
{
|
||||||
|
if (!json_is_array(arg))
|
||||||
|
{
|
||||||
|
*result_listener << "json array expected";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t * inode_ = json_array_get(arg, 1);
|
||||||
|
if (!json_is_integer(inode_))
|
||||||
|
{
|
||||||
|
*result_listener << "inode is expectoed to an integer";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inode != json_integer_value(inode_))
|
||||||
|
{
|
||||||
|
*result_listener << "inode mismatch: expected" << inode
|
||||||
|
<< " but was " << json_integer_value(inode_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
36
test/webfuse/mocks/open_matcher.hpp
Normal file
36
test/webfuse/mocks/open_matcher.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef WF_OPEN_MATCHER_HPP
|
||||||
|
#define WF_OPEN_MATCHER_HPP
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
namespace webfuse_test
|
||||||
|
{
|
||||||
|
|
||||||
|
MATCHER_P(Open, inode, "")
|
||||||
|
{
|
||||||
|
if (!json_is_array(arg))
|
||||||
|
{
|
||||||
|
*result_listener << "json array expected";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t * inode_ = json_array_get(arg, 1);
|
||||||
|
if (!json_is_integer(inode_))
|
||||||
|
{
|
||||||
|
*result_listener << "inode is expectoed to an integer";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inode != json_integer_value(inode_))
|
||||||
|
{
|
||||||
|
*result_listener << "inode mismatch: expected" << inode
|
||||||
|
<< " but was " << json_integer_value(inode_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
36
test/webfuse/mocks/readdir_matcher.hpp
Normal file
36
test/webfuse/mocks/readdir_matcher.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef WF_READDIR_MATCHER_HPP
|
||||||
|
#define WF_READDIR_MATCHER_HPP
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
namespace webfuse_test
|
||||||
|
{
|
||||||
|
|
||||||
|
MATCHER_P(ReadDir, inode, "")
|
||||||
|
{
|
||||||
|
if (!json_is_array(arg))
|
||||||
|
{
|
||||||
|
*result_listener << "json array expected";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t * inode_ = json_array_get(arg, 1);
|
||||||
|
if (!json_is_integer(inode_))
|
||||||
|
{
|
||||||
|
*result_listener << "inode is expectoed to an integer";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inode != json_integer_value(inode_))
|
||||||
|
{
|
||||||
|
*result_listener << "inode mismatch: expected" << inode
|
||||||
|
<< " but was " << json_integer_value(inode_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,5 +1,7 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -10,12 +12,26 @@
|
|||||||
#include "webfuse/server_config.h"
|
#include "webfuse/server_config.h"
|
||||||
#include "webfuse/test_util/server.hpp"
|
#include "webfuse/test_util/server.hpp"
|
||||||
#include "webfuse/test_util/ws_client.hpp"
|
#include "webfuse/test_util/ws_client.hpp"
|
||||||
|
#include "webfuse/integration/file.hpp"
|
||||||
#include "webfuse/mocks/mock_invokation_handler.hpp"
|
#include "webfuse/mocks/mock_invokation_handler.hpp"
|
||||||
#include "webfuse/protocol_names.h"
|
#include "webfuse/protocol_names.h"
|
||||||
|
#include "webfuse/mocks/open_matcher.hpp"
|
||||||
|
#include "webfuse/mocks/getattr_matcher.hpp"
|
||||||
|
#include "webfuse/mocks/lookup_matcher.hpp"
|
||||||
|
#include "webfuse/mocks/readdir_matcher.hpp"
|
||||||
|
|
||||||
using webfuse_test::MockInvokationHander;
|
using webfuse_test::MockInvokationHander;
|
||||||
using webfuse_test::WsClient;
|
using webfuse_test::WsClient;
|
||||||
using webfuse_test::Server;
|
using webfuse_test::Server;
|
||||||
|
using webfuse_test::File;
|
||||||
|
using webfuse_test::GetAttr;
|
||||||
|
using webfuse_test::Open;
|
||||||
|
using webfuse_test::Lookup;
|
||||||
|
using webfuse_test::ReadDir;
|
||||||
|
using testing::StrEq;
|
||||||
|
using testing::_;
|
||||||
|
using testing::AnyNumber;
|
||||||
|
using testing::Return;
|
||||||
|
|
||||||
#define TIMEOUT (std::chrono::seconds(10))
|
#define TIMEOUT (std::chrono::seconds(10))
|
||||||
|
|
||||||
@ -56,10 +72,102 @@ TEST(server, connect)
|
|||||||
WsClient client(handler, WF_PROTOCOL_NAME_PROVIDER_CLIENT);
|
WsClient client(handler, WF_PROTOCOL_NAME_PROVIDER_CLIENT);
|
||||||
|
|
||||||
auto connected = client.Connect(server.GetPort(), WF_PROTOCOL_NAME_ADAPTER_SERVER);
|
auto connected = client.Connect(server.GetPort(), WF_PROTOCOL_NAME_ADAPTER_SERVER);
|
||||||
ASSERT_EQ(std::future_status::ready, connected.wait_for(TIMEOUT));
|
ASSERT_TRUE(connected);
|
||||||
ASSERT_TRUE(connected.get());
|
|
||||||
|
|
||||||
auto disconnected = client.Disconnect();
|
auto disconnected = client.Disconnect();
|
||||||
ASSERT_EQ(std::future_status::ready, disconnected.wait_for(TIMEOUT));
|
ASSERT_TRUE(disconnected);
|
||||||
ASSERT_TRUE(disconnected.get());
|
}
|
||||||
|
|
||||||
|
TEST(server, add_filesystem)
|
||||||
|
{
|
||||||
|
Server server;
|
||||||
|
MockInvokationHander handler;
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber());
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("getattr"), GetAttr(1))).Times(1)
|
||||||
|
.WillOnce(Return("{\"mode\": 420, \"type\": \"dir\"}"));
|
||||||
|
WsClient client(handler, WF_PROTOCOL_NAME_PROVIDER_CLIENT);
|
||||||
|
|
||||||
|
auto connected = client.Connect(server.GetPort(), WF_PROTOCOL_NAME_ADAPTER_SERVER);
|
||||||
|
ASSERT_TRUE(connected);
|
||||||
|
|
||||||
|
std::string response_text = client.Invoke("{\"method\": \"add_filesystem\", \"params\": [\"test\"], \"id\": 42}");
|
||||||
|
json_t * response = json_loads(response_text.c_str(), 0, nullptr);
|
||||||
|
ASSERT_TRUE(json_is_object(response));
|
||||||
|
json_t * result = json_object_get(response, "result");
|
||||||
|
ASSERT_TRUE(json_is_object(result));
|
||||||
|
json_t * id = json_object_get(response, "id");
|
||||||
|
ASSERT_EQ(42, json_integer_value(id));
|
||||||
|
json_decref(response);
|
||||||
|
|
||||||
|
std::string base_dir = server.GetBaseDir();
|
||||||
|
File file(base_dir + "/test");
|
||||||
|
ASSERT_TRUE(file.isDirectory());
|
||||||
|
|
||||||
|
auto disconnected = client.Disconnect();
|
||||||
|
ASSERT_TRUE(disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(server, read)
|
||||||
|
{
|
||||||
|
Server server;
|
||||||
|
MockInvokationHander handler;
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber());
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("lookup"), Lookup(1, "a.file"))).Times(1)
|
||||||
|
.WillOnce(Return("{\"inode\": 2, \"mode\": 420, \"type\": \"file\", \"size\": 1}"));
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("open"), Open(2))).Times(1)
|
||||||
|
.WillOnce(Return("{\"handle\": 42}"));
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("read"), _)).Times(1)
|
||||||
|
.WillOnce(Return("{\"data\": \"*\", \"format\": \"identity\", \"count\": 1}"));
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("close"), _)).Times(1);
|
||||||
|
WsClient client(handler, WF_PROTOCOL_NAME_PROVIDER_CLIENT);
|
||||||
|
|
||||||
|
auto connected = client.Connect(server.GetPort(), WF_PROTOCOL_NAME_ADAPTER_SERVER);
|
||||||
|
ASSERT_TRUE(connected);
|
||||||
|
|
||||||
|
std::string response_text = client.Invoke("{\"method\": \"add_filesystem\", \"params\": [\"test\"], \"id\": 42}");
|
||||||
|
json_t * response = json_loads(response_text.c_str(), 0, nullptr);
|
||||||
|
ASSERT_TRUE(json_is_object(response));
|
||||||
|
json_t * result = json_object_get(response, "result");
|
||||||
|
ASSERT_TRUE(json_is_object(result));
|
||||||
|
json_t * id = json_object_get(response, "id");
|
||||||
|
ASSERT_EQ(42, json_integer_value(id));
|
||||||
|
json_decref(response);
|
||||||
|
|
||||||
|
std::string base_dir = server.GetBaseDir();
|
||||||
|
File file(base_dir + "/test/a.file");
|
||||||
|
ASSERT_TRUE(file.hasContents("*"));
|
||||||
|
|
||||||
|
auto disconnected = client.Disconnect();
|
||||||
|
ASSERT_TRUE(disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(server, readdir)
|
||||||
|
{
|
||||||
|
Server server;
|
||||||
|
MockInvokationHander handler;
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber());
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("getattr"), GetAttr(1))).Times(1)
|
||||||
|
.WillOnce(Return("{\"mode\": 420, \"type\": \"dir\"}"));
|
||||||
|
EXPECT_CALL(handler, Invoke(StrEq("readdir"), ReadDir(1))).Times(1)
|
||||||
|
.WillOnce(Return("[{\"name\": \"foo\", \"inode\": 23}]"));
|
||||||
|
WsClient client(handler, WF_PROTOCOL_NAME_PROVIDER_CLIENT);
|
||||||
|
|
||||||
|
auto connected = client.Connect(server.GetPort(), WF_PROTOCOL_NAME_ADAPTER_SERVER);
|
||||||
|
ASSERT_TRUE(connected);
|
||||||
|
|
||||||
|
std::string response_text = client.Invoke("{\"method\": \"add_filesystem\", \"params\": [\"test\"], \"id\": 42}");
|
||||||
|
json_t * response = json_loads(response_text.c_str(), 0, nullptr);
|
||||||
|
ASSERT_TRUE(json_is_object(response));
|
||||||
|
json_t * result = json_object_get(response, "result");
|
||||||
|
ASSERT_TRUE(json_is_object(result));
|
||||||
|
json_t * id = json_object_get(response, "id");
|
||||||
|
ASSERT_EQ(42, json_integer_value(id));
|
||||||
|
json_decref(response);
|
||||||
|
|
||||||
|
std::string base_dir = server.GetBaseDir();
|
||||||
|
File file(base_dir + "/test");
|
||||||
|
ASSERT_TRUE(file.hasSubdirectory("foo"));
|
||||||
|
|
||||||
|
auto disconnected = client.Disconnect();
|
||||||
|
ASSERT_TRUE(disconnected);
|
||||||
}
|
}
|
@ -1,12 +1,18 @@
|
|||||||
#include "webfuse/test_util/ws_client.hpp"
|
#include "webfuse/test_util/ws_client.hpp"
|
||||||
#include "webfuse/test_util/invokation_handler.hpp"
|
#include "webfuse/test_util/invokation_handler.hpp"
|
||||||
|
#include "webfuse/status.h"
|
||||||
|
|
||||||
#include <libwebsockets.h>
|
#include <libwebsockets.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#define TIMEOUT (std::chrono::seconds(10))
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -18,7 +24,7 @@ public:
|
|||||||
virtual void OnConnectionEstablished(lws * wsi) = 0;
|
virtual void OnConnectionEstablished(lws * wsi) = 0;
|
||||||
virtual void OnConnectionError(lws * wsi) = 0;
|
virtual void OnConnectionError(lws * wsi) = 0;
|
||||||
virtual void OnConnectionClosed(lws * wsi) = 0;
|
virtual void OnConnectionClosed(lws * wsi) = 0;
|
||||||
virtual void OnMessageReceived(lws * wsi, void * data, size_t length) = 0;
|
virtual void OnMessageReceived(lws * wsi, char * data, size_t length) = 0;
|
||||||
virtual int OnWritable(lws * wsi) = 0;
|
virtual int OnWritable(lws * wsi) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,7 +58,7 @@ static int webfuse_test_WsClient_callback(
|
|||||||
server->OnConnectionClosed(wsi);
|
server->OnConnectionClosed(wsi);
|
||||||
break;
|
break;
|
||||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||||
server->OnMessageReceived(wsi, in, len);
|
server->OnMessageReceived(wsi, reinterpret_cast<char*>(in), len);
|
||||||
break;
|
break;
|
||||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||||
// fall-through
|
// fall-through
|
||||||
@ -81,8 +87,8 @@ public:
|
|||||||
: wsi_(nullptr)
|
: wsi_(nullptr)
|
||||||
, handler_(handler)
|
, handler_(handler)
|
||||||
, protocol_(protocol)
|
, protocol_(protocol)
|
||||||
, promise_connected(nullptr)
|
, conn_state(connection_state::disconnected)
|
||||||
, promise_disconnected(nullptr)
|
, await_response(false)
|
||||||
, remote_port(0)
|
, remote_port(0)
|
||||||
, remote_use_tls(false)
|
, remote_use_tls(false)
|
||||||
{
|
{
|
||||||
@ -122,66 +128,75 @@ public:
|
|||||||
lws_context_destroy(context);
|
lws_context_destroy(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<bool> Connect(int port, std::string const & protocol, bool use_tls)
|
bool Connect(int port, std::string const & protocol, bool use_tls)
|
||||||
{
|
{
|
||||||
std::future<bool> result;
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
{
|
remote_port = port;
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
remote_protocol = protocol;
|
||||||
remote_port = port;
|
remote_use_tls = use_tls;
|
||||||
remote_protocol = protocol;
|
conn_state = connection_state::connecting;
|
||||||
remote_use_tls = use_tls;
|
commands.push(command::connect);
|
||||||
commands.push(command::connect);
|
|
||||||
promise_connected = new std::promise<bool>;
|
|
||||||
result = promise_connected->get_future();
|
|
||||||
}
|
|
||||||
lws_cancel_service(context);
|
|
||||||
|
|
||||||
return result;
|
lock.unlock();
|
||||||
|
lws_cancel_service(context);
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
convar.wait_for(lock, TIMEOUT, [&]() {
|
||||||
|
return (conn_state != connection_state::connecting);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (connection_state::connected == conn_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<bool> Disconnect()
|
bool Disconnect()
|
||||||
{
|
{
|
||||||
std::future<bool> result;
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
{
|
commands.push(command::disconnect);
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
conn_state = connection_state::disconnecting;
|
||||||
commands.push(command::disconnect);
|
|
||||||
promise_disconnected = new std::promise<bool>;
|
lock.unlock();
|
||||||
result = promise_disconnected->get_future();
|
|
||||||
}
|
|
||||||
lws_cancel_service(context);
|
lws_cancel_service(context);
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
return result;
|
convar.wait_for(lock, TIMEOUT, [&]() {
|
||||||
|
return (conn_state != connection_state::disconnecting);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (connection_state::disconnected == conn_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<std::string> Invoke(std::string const & message)
|
std::string Invoke(std::string const & message)
|
||||||
{
|
{
|
||||||
std::promise<std::string> p;
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
p.set_exception(std::make_exception_ptr(std::runtime_error("not implemented")));
|
send_queue.push(message);
|
||||||
return p.get_future();
|
commands.push(command::send);
|
||||||
|
await_response = true;
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
lws_cancel_service(context);
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
convar.wait_for(lock, TIMEOUT, [&]() {
|
||||||
|
return !await_response;
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnConnectionEstablished(lws * wsi)
|
void OnConnectionEstablished(lws * wsi)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
wsi_ = wsi;
|
wsi_ = wsi;
|
||||||
if (nullptr != promise_connected)
|
conn_state = connection_state::connected;
|
||||||
{
|
convar.notify_all();
|
||||||
promise_connected->set_value(true);
|
|
||||||
delete promise_connected;
|
|
||||||
promise_connected = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnConnectionError(lws * wsi)
|
void OnConnectionError(lws * wsi)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
if (nullptr != promise_connected)
|
wsi_ = nullptr;
|
||||||
{
|
conn_state = connection_state::disconnected;
|
||||||
promise_connected->set_value(false);
|
convar.notify_all();
|
||||||
delete promise_connected;
|
|
||||||
promise_connected = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnConnectionClosed(lws * wsi)
|
void OnConnectionClosed(lws * wsi)
|
||||||
@ -190,33 +205,97 @@ public:
|
|||||||
if (wsi == wsi_)
|
if (wsi == wsi_)
|
||||||
{
|
{
|
||||||
wsi_ = nullptr;
|
wsi_ = nullptr;
|
||||||
if (nullptr != promise_connected)
|
conn_state = connection_state::disconnected;
|
||||||
{
|
convar.notify_all();
|
||||||
promise_connected->set_value(false);
|
|
||||||
delete promise_connected;
|
|
||||||
promise_connected = nullptr;
|
|
||||||
}
|
|
||||||
if (nullptr != promise_disconnected)
|
|
||||||
{
|
|
||||||
promise_disconnected->set_value(true);
|
|
||||||
delete promise_disconnected;
|
|
||||||
promise_disconnected = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnMessageReceived(lws * wsi, void * data, size_t length)
|
void OnMessageReceived(lws * wsi, char * data, size_t length)
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
if (await_response)
|
||||||
|
{
|
||||||
|
response = std::string(data, length);
|
||||||
|
await_response = false;
|
||||||
|
convar.notify_all();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
json_t * request = json_loadb(data, length, 0, nullptr);
|
||||||
|
if (nullptr != request)
|
||||||
|
{
|
||||||
|
json_t * method = json_object_get(request, "method");
|
||||||
|
json_t * params = json_object_get(request, "params");
|
||||||
|
json_t * id = json_object_get(request, "id");
|
||||||
|
|
||||||
|
json_t * response = json_object();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::string result_text = handler_.Invoke(json_string_value(method), params);
|
||||||
|
json_t * result = json_loads(result_text.c_str(), 0, nullptr);
|
||||||
|
if (nullptr != result)
|
||||||
|
{
|
||||||
|
json_object_set_new(response, "result", result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_t * error = json_object();
|
||||||
|
json_object_set_new(error, "code", json_integer(WF_BAD));
|
||||||
|
json_object_set_new(response, "error",error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
json_t * error = json_object();
|
||||||
|
json_object_set_new(error, "code", json_integer(WF_BAD));
|
||||||
|
json_object_set_new(response, "error",error);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_set(response, "id", id);
|
||||||
|
|
||||||
|
char * response_text = json_dumps(response, 0);
|
||||||
|
lock.lock();
|
||||||
|
send_queue.push(response_text);
|
||||||
|
commands.push(command::send);
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
lws_cancel_service(context);
|
||||||
|
|
||||||
|
free(response_text);
|
||||||
|
|
||||||
|
json_decref(response);
|
||||||
|
json_decref(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int OnWritable(lws * wsi)
|
int OnWritable(lws * wsi)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
if (nullptr != promise_disconnected)
|
if (conn_state == connection_state::disconnecting)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else if (!send_queue.empty())
|
||||||
|
{
|
||||||
|
std::string message = send_queue.front();
|
||||||
|
send_queue.pop();
|
||||||
|
bool has_more = !send_queue.empty();
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
unsigned char * data = new unsigned char[LWS_PRE + message.size()];
|
||||||
|
memcpy(&data[LWS_PRE], message.c_str(), message.size());
|
||||||
|
lws_write(wsi, &data[LWS_PRE], message.size(), LWS_WRITE_TEXT);
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
if (has_more)
|
||||||
|
{
|
||||||
|
lws_callback_on_writable(wsi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -228,7 +307,16 @@ private:
|
|||||||
run,
|
run,
|
||||||
shutdown,
|
shutdown,
|
||||||
connect,
|
connect,
|
||||||
disconnect
|
disconnect,
|
||||||
|
send
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class connection_state
|
||||||
|
{
|
||||||
|
disconnected,
|
||||||
|
connected,
|
||||||
|
connecting,
|
||||||
|
disconnecting
|
||||||
};
|
};
|
||||||
|
|
||||||
static void Run(Private * self)
|
static void Run(Private * self)
|
||||||
@ -270,6 +358,9 @@ private:
|
|||||||
case command::disconnect:
|
case command::disconnect:
|
||||||
lws_callback_on_writable(self->wsi_);
|
lws_callback_on_writable(self->wsi_);
|
||||||
break;
|
break;
|
||||||
|
case command::send:
|
||||||
|
lws_callback_on_writable(self->wsi_);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -299,19 +390,22 @@ private:
|
|||||||
lws * wsi_;
|
lws * wsi_;
|
||||||
InvokationHandler & handler_;
|
InvokationHandler & handler_;
|
||||||
std::string protocol_;
|
std::string protocol_;
|
||||||
|
connection_state conn_state;
|
||||||
std::promise<bool> * promise_connected;
|
bool await_response;
|
||||||
std::promise<bool> * promise_disconnected;
|
std::string response;
|
||||||
|
|
||||||
lws_context_creation_info info;
|
lws_context_creation_info info;
|
||||||
lws_protocols protocols[2];
|
lws_protocols protocols[2];
|
||||||
lws_context * context;
|
lws_context * context;
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
|
std::condition_variable convar;
|
||||||
std::queue<command> commands;
|
std::queue<command> commands;
|
||||||
int remote_port;
|
int remote_port;
|
||||||
std::string remote_protocol;
|
std::string remote_protocol;
|
||||||
bool remote_use_tls;
|
bool remote_use_tls;
|
||||||
|
|
||||||
|
std::queue<std::string> send_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
WsClient::WsClient(
|
WsClient::WsClient(
|
||||||
@ -327,17 +421,17 @@ WsClient::~WsClient()
|
|||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<bool> WsClient::Connect(int port, std::string const & protocol, bool use_tls)
|
bool WsClient::Connect(int port, std::string const & protocol, bool use_tls)
|
||||||
{
|
{
|
||||||
return d->Connect(port, protocol, use_tls);
|
return d->Connect(port, protocol, use_tls);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<bool> WsClient::Disconnect()
|
bool WsClient::Disconnect()
|
||||||
{
|
{
|
||||||
return d->Disconnect();
|
return d->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<std::string> WsClient::Invoke(std::string const & message)
|
std::string WsClient::Invoke(std::string const & message)
|
||||||
{
|
{
|
||||||
return d->Invoke(message);
|
return d->Invoke(message);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define WF_TEST_UTIL_WS_CLIENT_HPP
|
#define WF_TEST_UTIL_WS_CLIENT_HPP
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <future>
|
|
||||||
|
|
||||||
namespace webfuse_test
|
namespace webfuse_test
|
||||||
{
|
{
|
||||||
@ -18,9 +17,9 @@ public:
|
|||||||
InvokationHandler& handler,
|
InvokationHandler& handler,
|
||||||
std::string const & protocol);
|
std::string const & protocol);
|
||||||
virtual ~WsClient();
|
virtual ~WsClient();
|
||||||
std::future<bool> Connect(int port, std::string const & protocol, bool use_tls = true);
|
bool Connect(int port, std::string const & protocol, bool use_tls = true);
|
||||||
std::future<bool> Disconnect();
|
bool Disconnect();
|
||||||
std::future<std::string> Invoke(std::string const & message);
|
std::string Invoke(std::string const & message);
|
||||||
private:
|
private:
|
||||||
class Private;
|
class Private;
|
||||||
Private *d;
|
Private *d;
|
||||||
|
@ -180,10 +180,9 @@ WsServer::Private::Private(
|
|||||||
|
|
||||||
WsServer::Private::~Private()
|
WsServer::Private::~Private()
|
||||||
{
|
{
|
||||||
{
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
is_shutdown_requested = true;
|
||||||
is_shutdown_requested = true;
|
lock.unlock();
|
||||||
}
|
|
||||||
|
|
||||||
lws_cancel_service(ws_context);
|
lws_cancel_service(ws_context);
|
||||||
context.join();
|
context.join();
|
||||||
|
Loading…
Reference in New Issue
Block a user