1
0
mirror of https://github.com/falk-werner/webfuse-provider synced 2026-03-02 04:09:18 +00:00

organized unit tests

This commit is contained in:
Falk Werner
2020-02-20 17:15:13 +01:00
parent abd6efe477
commit a27e68f5a6
52 changed files with 69 additions and 69 deletions

View File

@@ -0,0 +1,196 @@
#include "webfuse/fakes/fake_adapter_server.hpp"
#include "webfuse/utils/timeout_watcher.hpp"
#include "webfuse/core/util.h"
#include <libwebsockets.h>
#include <cstring>
#include <vector>
#include <queue>
#include <string>
using webfuse_test::TimeoutWatcher;
#define DEFAULT_TIMEOUT (std::chrono::milliseconds(5 * 1000))
namespace
{
class IServer
{
public:
virtual ~IServer() = default;
virtual void onConnectionEstablished(struct lws * wsi) = 0;
virtual void onConnectionClosed(struct lws * wsi) = 0;
virtual void onMessageReceived(struct lws * wsi, char const * data, size_t length) = 0;
virtual void onWritable(struct lws * wsi) = 0;
};
}
extern "C"
{
static int wf_test_fake_adapter_server_callback(
struct lws * wsi,
enum lws_callback_reasons reason,
void * WF_UNUSED_PARAM(user),
void * in,
size_t len)
{
struct lws_protocols const * ws_protocol = lws_get_protocol(wsi);
if (NULL == ws_protocol)
{
return 0;
}
auto * server = reinterpret_cast<IServer*>(ws_protocol->user);
switch(reason)
{
case LWS_CALLBACK_ESTABLISHED:
server->onConnectionEstablished(wsi);
break;
case LWS_CALLBACK_CLOSED:
server->onConnectionClosed(wsi);
break;
case LWS_CALLBACK_RECEIVE:
{
auto * data = reinterpret_cast<char const *>(in);
server->onMessageReceived(wsi, data, len);
}
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
server->onWritable(wsi);
break;
default:
break;
}
return 0;
}
}
namespace webfuse_test
{
class FakeAdapterServer::Private: public IServer
{
public:
explicit Private(int port)
: client_wsi(nullptr)
, message_received(false)
{
memset(ws_protocols, 0, sizeof(struct lws_protocols) * 2);
ws_protocols[0].name = "fs";
ws_protocols[0].callback = &wf_test_fake_adapter_server_callback;
ws_protocols[0].per_session_data_size = 0;
ws_protocols[0].user = reinterpret_cast<void*>(this);
memset(&info, 0, sizeof(struct lws_context_creation_info));
info.port = port;
info.mounts = NULL;
info.protocols =ws_protocols;
info.vhost_name = "localhost";
info.ws_ping_pong_interval = 10;
info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
context = lws_create_context(&info);
}
virtual ~Private()
{
lws_context_destroy(context);
}
void waitForConnection()
{
TimeoutWatcher watcher(DEFAULT_TIMEOUT);
while (nullptr == client_wsi)
{
watcher.check();
lws_service(context, 100);
}
}
void onConnectionEstablished(struct lws * wsi) override
{
client_wsi = wsi;
}
void onConnectionClosed(struct lws * wsi) override
{
if (wsi == client_wsi)
{
client_wsi = nullptr;
}
}
void onMessageReceived(struct lws * wsi, char const * data, size_t length) override
{
if (wsi == client_wsi)
{
last_message.assign(length, *data);
message_received = true;
}
}
void onWritable(struct lws * wsi) override
{
if (!queue.empty())
{
std::string const & message = queue.front();
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;
queue.pop();
if (!queue.empty())
{
lws_callback_on_writable(wsi);
}
}
}
private:
void send(std::string const & message)
{
if (nullptr != client_wsi)
{
queue.push(message);
lws_callback_on_writable(client_wsi);
}
}
struct lws * client_wsi;
bool message_received;
struct lws_protocols ws_protocols[2];
struct lws_context_creation_info info;
struct lws_context * context;
std::vector<char> last_message;
std::queue<std::string> queue;
};
FakeAdapterServer::FakeAdapterServer(int port)
: d(new Private(port))
{
}
FakeAdapterServer::~FakeAdapterServer()
{
delete d;
}
void FakeAdapterServer::waitForConnection()
{
d->waitForConnection();
}
}

View File

@@ -0,0 +1,24 @@
#ifndef WF_TEST_FAKE_SERVER_HPP
#define WF_TEST_FAKE_SERVER_HPP
#include <libwebsockets.h>
namespace webfuse_test
{
class FakeAdapterServer
{
FakeAdapterServer(FakeAdapterServer const &) = delete;
FakeAdapterServer & operator=(FakeAdapterServer const &) = delete;
public:
explicit FakeAdapterServer(int port);
~FakeAdapterServer();
void waitForConnection();
private:
class Private;
Private * d;
};
}
#endif

View File

@@ -0,0 +1,42 @@
#include "webfuse/mocks/mock_authenticator.hpp"
#define WF_AUTHENTICATOR_COUNT 3
namespace
{
webfuse_test::Authenticator * g_authenticators[WF_AUTHENTICATOR_COUNT];
}
namespace webfuse_test
{
void set_authenticator(Authenticator * authenticator)
{
set_authenticator(0, authenticator);
}
void set_authenticator(size_t i, Authenticator * authenticator)
{
g_authenticators[i] = authenticator;
}
bool authenticate(struct wf_credentials * creds, void * user_data)
{
return g_authenticators[0]->authenticate(creds, user_data);
}
bool authenticate_1(struct wf_credentials * creds, void * user_data)
{
return g_authenticators[1]->authenticate(creds, user_data);
}
bool authenticate_2(struct wf_credentials * creds, void * user_data)
{
return g_authenticators[2]->authenticate(creds, user_data);
}
}

View File

@@ -0,0 +1,34 @@
#ifndef MOCK_AUTHENTICATOR_H
#define MOCK_AUTHENTICATOR_H
#include <gmock/gmock.h>
#include "webfuse/adapter/impl/authenticator.h"
namespace webfuse_test
{
class Authenticator
{
public:
virtual ~Authenticator() { }
virtual bool authenticate(
struct wf_credentials * credentials,
void * user_data) = 0;
};
class MockAuthenticator: public Authenticator
{
public:
MOCK_METHOD2(authenticate, bool (struct wf_credentials * credentials, void * user_data));
};
void set_authenticator(Authenticator * authenticator);
void set_authenticator(size_t index, Authenticator * authenticator);
bool authenticate(struct wf_credentials * creds, void * user_data);
bool authenticate_1(struct wf_credentials * creds, void * user_data);
bool authenticate_2(struct wf_credentials * creds, void * user_data);
}
#endif

View File

@@ -0,0 +1,55 @@
#include "webfuse/mocks/mock_request.hpp"
#include <cstdlib>
namespace
{
extern "C" void
respond(
json_t * response,
void * user_data)
{
webfuse_test::Request * request = reinterpret_cast<webfuse_test::Request*>(user_data);
json_t * result = json_object_get(response, "result");
json_t * error = json_object_get(response, "error");
json_t * id_holder = json_object_get(response, "id");
int id = -1;
if (json_is_integer(id_holder))
{
id = json_integer_value(id_holder);
}
if (nullptr != result)
{
request->respond(result, id);
}
else
{
request->respond_error(error, id);
}
}
}
namespace webfuse_test
{
struct wfp_request *
request_create(
Request * req,
int id)
{
struct wfp_request * request = reinterpret_cast<struct wfp_request *>(malloc(sizeof(struct wfp_request)));
request->id = id;
request->user_data = reinterpret_cast<void*>(req);
request->respond = &respond;
return request;
}
}

View File

@@ -0,0 +1,122 @@
#ifndef WF_MOCK_REQUEST_HPP
#define WF_MOCK_REQUEST_HPP
#include <gmock/gmock.h>
#include <jansson.h>
#include <cstring>
#include "webfuse/provider/impl/request.h"
namespace webfuse_test
{
class Request
{
public:
virtual ~Request() { }
virtual void respond(json_t * result, int id) = 0;
virtual void respond_error(json_t * error, int id) = 0;
};
class MockRequest: public Request
{
public:
MOCK_METHOD2(respond, void(json_t * result, int id));
MOCK_METHOD2(respond_error, void(json_t * error, int id));
};
extern struct wfp_request *
request_create(
Request * req,
int id);
MATCHER_P3(GetAttrMatcher, inode, mode, file_type, "")
{
json_t * inode_holder = json_object_get(arg, "inode");
if ((!json_is_integer(inode_holder)) || (inode != json_integer_value(inode_holder)))
{
*result_listener << "missing inode";
return false;
}
json_t * mode_holder = json_object_get(arg, "mode");
if ((!json_is_integer(mode_holder)) || (mode != json_integer_value(mode_holder)))
{
*result_listener << "missing mode";
return false;
}
json_t * type_holder = json_object_get(arg, "type");
if ((!json_is_string(type_holder)) || (0 != strcmp(file_type, json_string_value(type_holder))))
{
*result_listener << "missing type";
return false;
}
return true;
}
MATCHER_P(ReaddirMatcher, contained_elements , "")
{
if (!json_is_array(arg))
{
*result_listener << "result is not array";
return false;
}
{
size_t i;
json_t * value;
json_array_foreach(arg, i, value)
{
json_t * inode = json_object_get(value, "inode");
json_t * name = json_object_get(value, "name");
if(!json_is_integer(inode))
{
*result_listener << "invalid result: missing inode";
return false;
}
if (!json_is_string(name))
{
*result_listener << "invalid result: missing name";
return false;
}
}
}
for(size_t i = 0; NULL != contained_elements[i]; i++)
{
char const * element = contained_elements[i];
bool found = false;
size_t j;
json_t * value;
json_array_foreach(arg, j, value)
{
json_t * name = json_object_get(value, "name");
found = (0 == strcmp(element, json_string_value(name)));
if (found)
{
break;
}
}
if (!found)
{
*result_listener << "missing required directory element: " << element;
return false;
}
}
return true;
}
}
#endif

View File

@@ -0,0 +1,112 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/request.h"
TEST(jsonrpc_is_request, request_with_object_params)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string("method"));
json_object_set_new(request, "params", json_object());
json_object_set_new(request, "id", json_integer(42));
ASSERT_TRUE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, request_with_array_params)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string("method"));
json_object_set_new(request, "params", json_array());
json_object_set_new(request, "id", json_integer(42));
ASSERT_TRUE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, null_request)
{
ASSERT_FALSE(wf_impl_jsonrpc_is_request(nullptr));
}
TEST(jsonrpc_is_request, invalid_request)
{
json_t * request = json_array();
json_array_append_new(request, json_string("method"));
json_array_append_new(request, json_object());
json_array_append_new(request, json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, invalid_request_without_id)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string("method"));
json_object_set_new(request, "params", json_object());
ASSERT_FALSE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, invalid_request_due_to_invalid_id)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string("method"));
json_object_set_new(request, "params", json_object());
json_object_set_new(request, "id", json_string("42"));
ASSERT_FALSE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, invalid_request_without_method)
{
json_t * request = json_object();
json_object_set_new(request, "params", json_object());
json_object_set_new(request, "id", json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, invalid_request_due_to_invalid_method)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_integer(42));
json_object_set_new(request, "params", json_object());
json_object_set_new(request, "id", json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, invalid_request_without_params)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string("method"));
json_object_set_new(request, "id", json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}
TEST(jsonrpc_is_request, invalid_request_due_to_invalid_params)
{
json_t * request = json_object();
json_object_set_new(request, "methdo", json_string("method"));
json_object_set_new(request, "params", json_string("params"));
json_object_set_new(request, "id", json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_request(request));
json_decref(request);
}

View File

@@ -0,0 +1,94 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/response.h"
TEST(jsonrpc_is_response, valid_result)
{
json_t * message = json_object();
json_object_set_new(message, "result", json_object());
json_object_set_new(message, "id", json_integer(42));
ASSERT_TRUE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}
TEST(jsonrpc_is_response, valid_result_string)
{
json_t * message = json_object();
json_object_set_new(message, "result", json_string("also valid"));
json_object_set_new(message, "id", json_integer(42));
ASSERT_TRUE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}
TEST(jsonrpc_is_response, valid_error)
{
json_t * message = json_object();
json_object_set_new(message, "error", json_object());
json_object_set_new(message, "id", json_integer(42));
ASSERT_TRUE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}
TEST(jsonrpc_is_response, invalid_null)
{
ASSERT_FALSE(wf_impl_jsonrpc_is_response(nullptr));
}
TEST(jsonrpc_is_response, invalid_message)
{
json_t * message = json_array();
json_array_append_new(message, json_object());
json_array_append_new(message, json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}
TEST(jsonrpc_is_response, invalid_missing_id)
{
json_t * message = json_object();
json_object_set_new(message, "result", json_object());
ASSERT_FALSE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}
TEST(jsonrpc_is_response, invalid_id_wrong_type)
{
json_t * message = json_object();
json_object_set_new(message, "result", json_object());
json_object_set_new(message, "id", json_string("42"));
ASSERT_FALSE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}
TEST(jsonrpc_is_response, invalid_missing_result_and_error)
{
json_t * message = json_object();
json_object_set_new(message, "id", json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}
TEST(jsonrpc_is_response, invalid_error_wrong_type)
{
json_t * message = json_object();
json_object_set_new(message, "error", json_array());
json_object_set_new(message, "id", json_integer(42));
ASSERT_FALSE(wf_impl_jsonrpc_is_response(message));
json_decref(message);
}

View File

@@ -0,0 +1,393 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/time/timeout_manager.h"
#include "webfuse/utils/msleep.hpp"
using webfuse_test::msleep;
#define WF_DEFAULT_TIMEOUT (10 * 1000)
namespace
{
struct SendContext
{
json_t * response;
bool result;
bool is_called;
explicit SendContext(bool result_ = true)
: response(nullptr)
, result(result_)
, is_called(false)
{
}
~SendContext()
{
if (nullptr != response)
{
json_decref(response);
}
}
};
bool jsonrpc_send(
json_t * request,
void * user_data)
{
SendContext * context = reinterpret_cast<SendContext*>(user_data);
context->is_called = true;
context->response = request;
json_incref(request);
return context->result;
}
struct FinishedContext
{
bool is_called;
wf_status status;
json_t * result;
FinishedContext()
: is_called(false)
, status(WF_BAD)
, result(nullptr)
{
}
~FinishedContext()
{
if (nullptr != result)
{
json_decref(result);
}
}
};
void jsonrpc_finished(
void * user_data,
wf_status status,
struct json_t const * result)
{
FinishedContext * context = reinterpret_cast<FinishedContext*>(user_data);
context->is_called = true;
context->status = status;
context->result = json_deep_copy(result);
}
}
TEST(jsonrpc_proxy, init)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext context;
void * user_data = reinterpret_cast<void*>(&context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, user_data);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
ASSERT_FALSE(context.is_called);
}
TEST(jsonrpc_proxy, invoke)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "si", "bar", 42);
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
json_t * method = json_object_get(send_context.response, "method");
ASSERT_TRUE(json_is_string(method));
ASSERT_STREQ("foo", json_string_value(method));
json_t * params = json_object_get(send_context.response, "params");
ASSERT_TRUE(json_is_array(params));
ASSERT_EQ(2, json_array_size(params));
ASSERT_TRUE(json_is_string(json_array_get(params, 0)));
ASSERT_STREQ("bar", json_string_value(json_array_get(params, 0)));
ASSERT_TRUE(json_is_integer(json_array_get(params, 1)));
ASSERT_EQ(42, json_integer_value(json_array_get(params, 1)));
json_t * id = json_object_get(send_context.response, "id");
ASSERT_TRUE(json_is_integer(id));
ASSERT_FALSE(finished_context.is_called);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
ASSERT_TRUE(finished_context.is_called);
ASSERT_FALSE(WF_GOOD == finished_context.status);
}
TEST(jsonrpc_proxy, invoke_calls_finish_if_send_fails)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context(false);
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "si", "bar", 42);
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
ASSERT_TRUE(finished_context.is_called);
ASSERT_FALSE(WF_GOOD == finished_context.status);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, invoke_fails_if_another_request_is_pending)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "si", "bar", 42);
FinishedContext finished_context2;
void * finished_data2 = reinterpret_cast<void*>(&finished_context2);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data2, "foo", "");
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
ASSERT_FALSE(finished_context.is_called);
ASSERT_TRUE(finished_context2.is_called);
ASSERT_EQ(WF_BAD_BUSY, finished_context2.status);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, invoke_fails_if_request_is_invalid)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "?", "error");
ASSERT_FALSE(send_context.is_called);
ASSERT_TRUE(finished_context.is_called);
ASSERT_EQ(WF_BAD, finished_context.status);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, on_result)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "si", "bar", 42);
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
json_t * id = json_object_get(send_context.response, "id");
ASSERT_TRUE(json_is_number(id));
json_t * response = json_object();
json_object_set_new(response, "result", json_string("okay"));
json_object_set(response, "id", id);
wf_impl_jsonrpc_proxy_onresult(&proxy, response);
json_decref(response);
ASSERT_TRUE(finished_context.is_called);
ASSERT_EQ(WF_GOOD, finished_context.status);
ASSERT_TRUE(json_is_string(finished_context.result));
ASSERT_STREQ("okay", json_string_value(finished_context.result));
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, on_result_reject_response_with_unknown_id)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "si", "bar", 42);
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
json_t * id = json_object_get(send_context.response, "id");
ASSERT_TRUE(json_is_number(id));
json_t * response = json_object();
json_object_set_new(response, "result", json_string("okay"));
json_object_set_new(response, "id", json_integer(1 + json_integer_value(id)));
wf_impl_jsonrpc_proxy_onresult(&proxy, response);
json_decref(response);
ASSERT_FALSE(finished_context.is_called);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, timeout)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, 0, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "si", "bar", 42);
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
msleep(10);
wf_impl_timeout_manager_check(&timeout_manager);
ASSERT_TRUE(finished_context.is_called);
ASSERT_EQ(WF_BAD_TIMEOUT, finished_context.status);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, cleanup_pending_request)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, 10, &jsonrpc_send, send_data);
FinishedContext finished_context;
void * finished_data = reinterpret_cast<void*>(&finished_context);
wf_impl_jsonrpc_proxy_invoke(&proxy, &jsonrpc_finished, finished_data, "foo", "si", "bar", 42);
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
ASSERT_FALSE(finished_context.is_called);
ASSERT_NE(nullptr, timeout_manager.timers);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
ASSERT_TRUE(finished_context.is_called);
ASSERT_EQ(nullptr, timeout_manager.timers);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, notify)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
wf_impl_jsonrpc_proxy_notify(&proxy, "foo", "si", "bar", 42);
ASSERT_TRUE(send_context.is_called);
ASSERT_TRUE(json_is_object(send_context.response));
json_t * method = json_object_get(send_context.response, "method");
ASSERT_TRUE(json_is_string(method));
ASSERT_STREQ("foo", json_string_value(method));
json_t * params = json_object_get(send_context.response, "params");
ASSERT_TRUE(json_is_array(params));
ASSERT_EQ(2, json_array_size(params));
ASSERT_TRUE(json_is_string(json_array_get(params, 0)));
ASSERT_STREQ("bar", json_string_value(json_array_get(params, 0)));
ASSERT_TRUE(json_is_integer(json_array_get(params, 1)));
ASSERT_EQ(42, json_integer_value(json_array_get(params, 1)));
json_t * id = json_object_get(send_context.response, "id");
ASSERT_EQ(nullptr, id);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}
TEST(jsonrpc_proxy, notify_dont_send_invalid_request)
{
struct wf_impl_timeout_manager timeout_manager;
wf_impl_timeout_manager_init(&timeout_manager);
SendContext send_context;
void * send_data = reinterpret_cast<void*>(&send_context);
struct wf_impl_jsonrpc_proxy proxy;
wf_impl_jsonrpc_proxy_init(&proxy, &timeout_manager, WF_DEFAULT_TIMEOUT, &jsonrpc_send, send_data);
wf_impl_jsonrpc_proxy_notify(&proxy, "foo", "?");
ASSERT_FALSE(send_context.is_called);
wf_impl_jsonrpc_proxy_cleanup(&proxy);
wf_impl_timeout_manager_cleanup(&timeout_manager);
}

View File

@@ -0,0 +1,102 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/request.h"
namespace
{
struct Context
{
json_t * response;
};
bool jsonrpc_send(
json_t * request,
void * user_data)
{
Context * context = reinterpret_cast<Context*>(user_data);
context->response = request;
json_incref(request);
return true;
}
}
TEST(jsonrpc_request, create_dispose)
{
Context context{nullptr};
void * user_data = reinterpret_cast<void*>(&context);
struct wf_impl_jsonrpc_request * request =
wf_impl_jsonrpc_request_create(42, &jsonrpc_send, user_data);
ASSERT_NE(nullptr, request);
ASSERT_EQ(user_data, wf_impl_jsonrpc_request_get_userdata(request));
wf_impl_jsonrpc_request_dispose(request);
}
TEST(jsonrpc_request, respond)
{
Context context{nullptr};
void * user_data = reinterpret_cast<void*>(&context);
struct wf_impl_jsonrpc_request * request =
wf_impl_jsonrpc_request_create(42, &jsonrpc_send, user_data);
wf_impl_jsonrpc_respond(request, json_string("okay"));
ASSERT_NE(nullptr, context.response);
json_t * response = reinterpret_cast<json_t*>(context.response);
ASSERT_TRUE(json_is_object(response));
json_t * id = json_object_get(response, "id");
ASSERT_TRUE(json_is_integer(id));
ASSERT_EQ(42, json_integer_value(id));
json_t * result = json_object_get(response, "result");
ASSERT_TRUE(json_is_string(result));
ASSERT_STREQ("okay", json_string_value(result));
ASSERT_EQ(nullptr, json_object_get(response, "error"));
json_decref(response);
}
TEST(jsonrpc_request, respond_error)
{
Context context{nullptr};
void * user_data = reinterpret_cast<void*>(&context);
struct wf_impl_jsonrpc_request * request =
wf_impl_jsonrpc_request_create(42, &jsonrpc_send, user_data);
wf_impl_jsonrpc_respond_error(request, WF_BAD);
ASSERT_NE(nullptr, context.response);
json_t * response = reinterpret_cast<json_t*>(context.response);
ASSERT_TRUE(json_is_object(response));
json_t * id = json_object_get(response, "id");
ASSERT_TRUE(json_is_integer(id));
ASSERT_EQ(42, json_integer_value(id));
ASSERT_EQ(nullptr, json_object_get(response, "result"));
json_t * err = json_object_get(response, "error");
ASSERT_TRUE(json_is_object(err));
json_t * err_code = json_object_get(err, "code");
ASSERT_TRUE(json_is_integer(err_code));
ASSERT_EQ(WF_BAD, json_integer_value(err_code));
json_t * err_message = json_object_get(err, "message");
ASSERT_TRUE(json_is_string(err_message));
ASSERT_STREQ("Bad", json_string_value(err_message));
json_decref(response);
}

View File

@@ -0,0 +1,56 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/response.h"
TEST(json_response, init_result)
{
json_t * message = json_object();
json_object_set_new(message, "result", json_integer(47));
json_object_set_new(message, "id", json_integer(11));
struct wf_impl_jsonrpc_response response;
wf_impl_jsonrpc_response_init(&response, message);
ASSERT_EQ(WF_GOOD, response.status);
ASSERT_TRUE(json_is_integer(response.result));
ASSERT_EQ(47, json_integer_value(response.result));
ASSERT_EQ(11, response.id);
wf_impl_jsonrpc_response_cleanup(&response);
json_decref(message);
}
TEST(json_response, init_error)
{
json_t * message = json_object();
json_t * err = json_object();
json_object_set_new(err, "code", json_integer(WF_BAD_ACCESS_DENIED));
json_object_set_new(err, "message", json_string("access denied"));
json_object_set_new(message, "error", err);
json_object_set_new(message, "id", json_integer(23));
struct wf_impl_jsonrpc_response response;
wf_impl_jsonrpc_response_init(&response, message);
ASSERT_EQ(WF_BAD_ACCESS_DENIED, response.status);
ASSERT_EQ(nullptr, response.result);
ASSERT_EQ(23, response.id);
wf_impl_jsonrpc_response_cleanup(&response);
json_decref(message);
}
TEST(json_response, init_format_error)
{
json_t * message = json_object();
json_object_set_new(message, "id", json_integer(12));
struct wf_impl_jsonrpc_response response;
wf_impl_jsonrpc_response_init(&response, message);
ASSERT_EQ(WF_BAD_FORMAT, response.status);
ASSERT_EQ(nullptr, response.result);
ASSERT_EQ(12, response.id);
wf_impl_jsonrpc_response_cleanup(&response);
json_decref(message);
}

View File

@@ -0,0 +1,125 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/request.h"
namespace
{
struct Context
{
json_t * response;
bool is_called;
};
bool jsonrpc_send(
json_t * request,
void * user_data)
{
Context * context = reinterpret_cast<Context*>(user_data);
context->is_called = true;
context->response = request;
json_incref(request);
return true;
}
void sayHello(
struct wf_impl_jsonrpc_request * request,
char const * method_name,
json_t * params,
void * user_data)
{
(void) method_name;
(void) params;
(void) user_data;
json_t * result = json_string("Hello");
wf_impl_jsonrpc_respond(request, result);
}
}
TEST(jsonrpc_server, process_request)
{
struct wf_impl_jsonrpc_server server;
wf_impl_jsonrpc_server_init(&server);
wf_impl_jsonrpc_server_add(&server, "sayHello", &sayHello, nullptr);
Context context{nullptr, false};
void * user_data = reinterpret_cast<void*>(&context);
json_t * request = json_object();
json_object_set_new(request, "method", json_string("sayHello"));
json_object_set_new(request, "params", json_array());
json_object_set_new(request, "id", json_integer(23));
wf_impl_jsonrpc_server_process(&server, request, &jsonrpc_send, user_data);
ASSERT_TRUE(context.is_called);
ASSERT_NE(nullptr, context.response);
ASSERT_TRUE(json_is_object(context.response));
json_t * id = json_object_get(context.response, "id");
ASSERT_TRUE(json_is_integer(id));
ASSERT_EQ(23, json_integer_value(id));
json_t * result = json_object_get(context.response, "result");
ASSERT_TRUE(json_is_string(result));
ASSERT_STREQ("Hello", json_string_value(result));
json_decref(context.response);
json_decref(request);
wf_impl_jsonrpc_server_cleanup(&server);
}
TEST(jsonrpc_server, invoke_unknown_method)
{
struct wf_impl_jsonrpc_server server;
wf_impl_jsonrpc_server_init(&server);
wf_impl_jsonrpc_server_add(&server, "sayHello", &sayHello, nullptr);
Context context{nullptr, false};
void * user_data = reinterpret_cast<void*>(&context);
json_t * request = json_object();
json_object_set_new(request, "method", json_string("greet"));
json_object_set_new(request, "params", json_array());
json_object_set_new(request, "id", json_integer(42));
wf_impl_jsonrpc_server_process(&server, request, &jsonrpc_send, user_data);
ASSERT_TRUE(context.is_called);
ASSERT_NE(nullptr, context.response);
ASSERT_TRUE(json_is_object(context.response));
json_t * id = json_object_get(context.response, "id");
ASSERT_TRUE(json_is_integer(id));
ASSERT_EQ(42, json_integer_value(id));
json_t * err = json_object_get(context.response, "error");
ASSERT_TRUE(json_is_object(err));
json_t * err_code = json_object_get(err, "code");
ASSERT_TRUE(json_is_integer(err_code));
ASSERT_EQ(WF_BAD_NOTIMPLEMENTED, json_integer_value(err_code));
json_t * err_message = json_object_get(err, "message");
ASSERT_TRUE(json_is_string(err_message));
json_decref(context.response);
json_decref(request);
wf_impl_jsonrpc_server_cleanup(&server);
}
TEST(jsonrpc_server, skip_invalid_request)
{
struct wf_impl_jsonrpc_server server;
wf_impl_jsonrpc_server_init(&server);
Context context{nullptr, false};
void * user_data = reinterpret_cast<void*>(&context);
json_t * request = json_object();
json_object_set_new(request, "method", json_string("sayHello"));
json_object_set_new(request, "params", json_array());
wf_impl_jsonrpc_server_process(&server, request, &jsonrpc_send, user_data);
ASSERT_FALSE(context.is_called);
json_decref(request);
wf_impl_jsonrpc_server_cleanup(&server);
}

View File

@@ -0,0 +1,47 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/util.h"
TEST(jsonrpc_util, get_int)
{
json_t * object = json_object();
json_object_set_new(object, "key", json_integer(23));
int value = wf_impl_json_get_int(object, "key", 42);
ASSERT_EQ(23, value);
json_decref(object);
}
TEST(jsonrpc_util, failed_to_get_null_object)
{
int value = wf_impl_json_get_int(nullptr, "key", 42);
ASSERT_EQ(42, value);
}
TEST(jsonrpc_util, failed_to_get_not_object)
{
json_t * object = json_array();
int value = wf_impl_json_get_int(nullptr, "key", 42);
ASSERT_EQ(42, value);
json_decref(object);
}
TEST(jsonrpc_util, failed_to_get_invalid_key)
{
json_t * object = json_object();
int value = wf_impl_json_get_int(object, "key", 42);
ASSERT_EQ(42, value);
json_decref(object);
}
TEST(jsonrpc_util, failed_to_get_invalid_value_type)
{
json_t * object = json_object();
json_object_set_new(object, "key", json_string("42"));
int value = wf_impl_json_get_int(object, "key", 42);
ASSERT_EQ(42, value);
json_decref(object);
}

View File

@@ -0,0 +1,63 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "webfuse/mocks/mock_authenticator.hpp"
#include "webfuse/adapter/impl/authenticator.h"
#include "webfuse/adapter/impl/credentials.h"
using ::testing::Return;
using ::testing::_;
using ::webfuse_test::Authenticator;
using ::webfuse_test::MockAuthenticator;
using ::webfuse_test::set_authenticator;
using ::webfuse_test::authenticate;
TEST(Authenticator, Authenticate)
{
MockAuthenticator mock;
set_authenticator(&mock);
struct wf_credentials creds;
wf_impl_credentials_init(&creds, "username", nullptr);
char dummy[] = "usr_data";
void * user_data = reinterpret_cast<void*>(dummy);
EXPECT_CALL(mock, authenticate(&creds, user_data))
.Times(1)
.WillRepeatedly(Return(true));
struct wf_impl_authenticator * authenticator = wf_impl_authenticator_create(
"username",
&authenticate,
user_data);
bool result = wf_impl_authenticator_autenticate(authenticator, &creds);
ASSERT_TRUE(result);
wf_impl_authenticator_dispose(authenticator);
wf_impl_credentials_cleanup(&creds);
}
TEST(Authenticator, SkipAuthenticationWithWrongType)
{
MockAuthenticator mock;
set_authenticator(&mock);
struct wf_credentials creds;
wf_impl_credentials_init(&creds, "username", nullptr);
EXPECT_CALL(mock, authenticate(_, _))
.Times(0);
struct wf_impl_authenticator * authenticator = wf_impl_authenticator_create(
"certificate",
&authenticate,
nullptr);
bool result = wf_impl_authenticator_autenticate(authenticator, &creds);
ASSERT_FALSE(result);
wf_impl_authenticator_dispose(authenticator);
wf_impl_credentials_cleanup(&creds);
}

View File

@@ -0,0 +1,154 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "webfuse/adapter/impl/authenticators.h"
#include "webfuse/adapter/impl/credentials.h"
#include "webfuse/mocks/mock_authenticator.hpp"
using ::testing::_;
using ::testing::Return;
using ::webfuse_test::MockAuthenticator;
using ::webfuse_test::set_authenticator;
using ::webfuse_test::authenticate;
using ::webfuse_test::authenticate_1;
using ::webfuse_test::authenticate_2;
TEST(Authenticators, CloneEmpty)
{
struct wf_impl_authenticators authenticators;
struct wf_impl_authenticators clone;
wf_impl_authenticators_init(&authenticators);
ASSERT_EQ(nullptr, authenticators.first);
wf_impl_authenticators_clone(&authenticators, &clone);
ASSERT_EQ(nullptr, clone.first);
wf_impl_authenticators_cleanup(&authenticators);
wf_impl_authenticators_cleanup(&clone);
}
TEST(Authenticators, Clone)
{
struct wf_impl_authenticators authenticators;
struct wf_impl_authenticators clone;
wf_impl_authenticators_init(&authenticators);
wf_impl_authenticators_add(&authenticators, "username", &authenticate, nullptr);
ASSERT_NE(nullptr, authenticators.first);
wf_impl_authenticators_clone(&authenticators, &clone);
ASSERT_NE(nullptr, clone.first);
ASSERT_NE(nullptr, authenticators.first);
ASSERT_NE(authenticators.first, clone.first);
wf_impl_authenticators_cleanup(&authenticators);
wf_impl_authenticators_cleanup(&clone);
}
TEST(Authenticators, Move)
{
struct wf_impl_authenticators authenticators;
struct wf_impl_authenticators clone;
wf_impl_authenticators_init(&authenticators);
wf_impl_authenticators_add(&authenticators, "username", &authenticate, nullptr);
ASSERT_NE(nullptr, authenticators.first);
wf_impl_authenticators_move(&authenticators, &clone);
ASSERT_NE(nullptr, clone.first);
ASSERT_EQ(nullptr, authenticators.first);
ASSERT_NE(authenticators.first, clone.first);
wf_impl_authenticators_cleanup(&authenticators);
wf_impl_authenticators_cleanup(&clone);
}
TEST(Authenticators, AuthenticateWithoutAuthenticators)
{
struct wf_credentials creds;
wf_impl_credentials_init(&creds, "username", nullptr);
struct wf_impl_authenticators authenticators;
wf_impl_authenticators_init(&authenticators);
bool result = wf_impl_authenticators_authenticate(&authenticators, &creds);
ASSERT_TRUE(result);
result = wf_impl_authenticators_authenticate(&authenticators, nullptr);
ASSERT_TRUE(result);
wf_impl_authenticators_cleanup(&authenticators);
wf_impl_credentials_cleanup(&creds);
}
TEST(Authenticators, FailToAuthenticateWithoutCredentials)
{
MockAuthenticator mock;
set_authenticator(&mock);
struct wf_impl_authenticators authenticators;
wf_impl_authenticators_init(&authenticators);
wf_impl_authenticators_add(&authenticators, "username", &authenticate, nullptr);
bool result = wf_impl_authenticators_authenticate(&authenticators, nullptr);
ASSERT_FALSE(result);
wf_impl_authenticators_cleanup(&authenticators);
}
TEST(Authenticators, AuthenticateWithMultipleCredentials)
{
struct wf_credentials creds;
wf_impl_credentials_init(&creds, "username", nullptr);
MockAuthenticator username_mock;
set_authenticator(1, &username_mock);
EXPECT_CALL(username_mock, authenticate(&creds, nullptr))
.Times(1)
.WillRepeatedly(Return(true));
MockAuthenticator certificate_mock;
set_authenticator(2, &certificate_mock);
EXPECT_CALL(certificate_mock, authenticate(_, _))
.Times(0);
struct wf_impl_authenticators authenticators;
wf_impl_authenticators_init(&authenticators);
wf_impl_authenticators_add(&authenticators, "username", &authenticate_1, nullptr);
wf_impl_authenticators_add(&authenticators, "certificate", &authenticate_2, nullptr);
bool result = wf_impl_authenticators_authenticate(&authenticators, &creds);
ASSERT_TRUE(result);
wf_impl_authenticators_cleanup(&authenticators);
wf_impl_credentials_cleanup(&creds);
}
TEST(Authenticators, FailedAuthenticateWithWrongType)
{
struct wf_credentials creds;
wf_impl_credentials_init(&creds, "token", nullptr);
MockAuthenticator username_mock;
set_authenticator(1, &username_mock);
EXPECT_CALL(username_mock, authenticate(&creds, nullptr))
.Times(0);
MockAuthenticator certificate_mock;
set_authenticator(2, &certificate_mock);
EXPECT_CALL(certificate_mock, authenticate(_, _))
.Times(0);
struct wf_impl_authenticators authenticators;
wf_impl_authenticators_init(&authenticators);
wf_impl_authenticators_add(&authenticators, "username", &authenticate_1, nullptr);
wf_impl_authenticators_add(&authenticators, "certificate", &authenticate_2, nullptr);
bool result = wf_impl_authenticators_authenticate(&authenticators, &creds);
ASSERT_FALSE(result);
wf_impl_authenticators_cleanup(&authenticators);
wf_impl_credentials_cleanup(&creds);
}

View File

@@ -0,0 +1,70 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/credentials.h"
#include <jansson.h>
TEST(Credentials, Type)
{
struct wf_credentials creds;
wf_impl_credentials_init(&creds, "test", nullptr);
ASSERT_STREQ("test", wf_impl_credentials_type(&creds));
wf_impl_credentials_cleanup(&creds);
}
TEST(Credentials, Get)
{
struct wf_credentials creds;
json_t * data = json_object();
json_object_set_new(data, "username", json_string("bob"));
json_object_set_new(data, "password", json_string("<secret>"));
wf_impl_credentials_init(&creds, "username", data);
ASSERT_STREQ("username", wf_impl_credentials_type(&creds));
ASSERT_STREQ("bob", wf_impl_credentials_get(&creds, "username"));
ASSERT_STREQ("<secret>", wf_impl_credentials_get(&creds, "password"));
wf_impl_credentials_cleanup(&creds);
json_decref(data);
}
TEST(Credentials, FailedToGetNonexistingValue)
{
struct wf_credentials creds;
json_t * data = json_object();
wf_impl_credentials_init(&creds, "username", data);
ASSERT_STREQ("username", wf_impl_credentials_type(&creds));
ASSERT_STREQ(nullptr, wf_impl_credentials_get(&creds, "username"));
ASSERT_STREQ(nullptr, wf_impl_credentials_get(&creds, "password"));
wf_impl_credentials_cleanup(&creds);
json_decref(data);
}
TEST(Credentials, FailedToGetWithoutData)
{
struct wf_credentials creds;
wf_impl_credentials_init(&creds, "username", nullptr);
ASSERT_STREQ("username", wf_impl_credentials_type(&creds));
ASSERT_STREQ(nullptr, wf_impl_credentials_get(&creds, "username"));
ASSERT_STREQ(nullptr, wf_impl_credentials_get(&creds, "password"));
wf_impl_credentials_cleanup(&creds);
}
TEST(Credentials, FailedToGetWrongDataType)
{
struct wf_credentials creds;
json_t * data = json_string("invalid_creds");
wf_impl_credentials_init(&creds, "username", data);
ASSERT_STREQ("username", wf_impl_credentials_type(&creds));
ASSERT_STREQ(nullptr, wf_impl_credentials_get(&creds, "username"));
ASSERT_STREQ(nullptr, wf_impl_credentials_get(&creds, "password"));
wf_impl_credentials_cleanup(&creds);
json_decref(data);
}

View File

@@ -0,0 +1,7 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/fuse_wrapper.h"
TEST(libfuse, fuse_req_t_size)
{
ASSERT_EQ(sizeof(void*), sizeof(fuse_req_t));
}

View File

@@ -0,0 +1,47 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "webfuse/adapter/mountpoint.h"
namespace
{
class MockUserDataDisposer
{
public:
MOCK_METHOD1(dispose, void(void * mountpoint));
};
MockUserDataDisposer * global_disposer = nullptr;
void ondispose(void * user_data)
{
global_disposer->dispose(user_data);
}
}
TEST(mountpoint, get_path)
{
wf_mountpoint * mountpoint = wf_mountpoint_create("/some/path");
ASSERT_NE(nullptr, mountpoint);
ASSERT_STREQ("/some/path", wf_mountpoint_get_path(mountpoint));
wf_mountpoint_dispose(mountpoint);
}
TEST(mountpoint, ondispose)
{
MockUserDataDisposer disposer;
global_disposer = &disposer;
wf_mountpoint * mountpoint = wf_mountpoint_create("/some/path");
ASSERT_NE(nullptr, mountpoint);
int value = 42;
void * user_data = reinterpret_cast<void*>(&value);
wf_mountpoint_set_userdata(mountpoint, user_data, ondispose);
EXPECT_CALL(disposer, dispose(user_data)).Times(1);
wf_mountpoint_dispose(mountpoint);
}

View File

@@ -0,0 +1,54 @@
#include <string>
#include <gtest/gtest.h>
#include "webfuse/adapter/impl/jsonrpc/response.h"
static void response_parse_str(
std::string const & buffer,
struct wf_impl_jsonrpc_response * response)
{
json_t * message = json_loadb(buffer.c_str(), buffer.size(), 0, nullptr);
if (nullptr != message)
{
wf_impl_jsonrpc_response_init(response, message);
json_decref(message);
}
}
TEST(response_parser, test)
{
struct wf_impl_jsonrpc_response response;
// no object
response_parse_str("[]", &response);
ASSERT_NE(WF_GOOD, response.status);
ASSERT_EQ(-1, response.id);
ASSERT_EQ(nullptr, response.result);
// empty
response_parse_str("{}", &response);
ASSERT_NE(WF_GOOD, response.status);
ASSERT_EQ(-1, response.id);
ASSERT_EQ(nullptr, response.result);
// no data
response_parse_str("{\"id\":42}", &response);
ASSERT_NE(WF_GOOD, response.status);
ASSERT_EQ(42, response.id);
ASSERT_EQ(nullptr, response.result);
// custom error code
response_parse_str("{\"error\":{\"code\": 42}, \"id\": 42}", &response);
ASSERT_NE(WF_GOOD, response.status);
ASSERT_EQ(42, response.status);
ASSERT_EQ(42, response.id);
ASSERT_EQ(nullptr, response.result);
// valid response
response_parse_str("{\"result\": true, \"id\": 42}", &response);
ASSERT_EQ(WF_GOOD, response.status);
ASSERT_EQ(42, response.id);
ASSERT_NE(nullptr, response.result);
json_decref(response.result);
}

View File

@@ -0,0 +1,25 @@
#include <gtest/gtest.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "webfuse/adapter/server.h"
#include "webfuse/adapter/server_config.h"
TEST(server, create_dispose)
{
mkdir("test", 0700);
struct wf_server_config * config = wf_server_config_create();
wf_server_config_set_mountpoint(config, "test");
struct wf_server * server = wf_server_create(config);
ASSERT_NE(nullptr, server);
wf_server_dispose(server);
wf_server_config_dispose(config);
rmdir("test");
}

View File

@@ -0,0 +1,175 @@
#include <gtest/gtest.h>
#include "webfuse/adapter/server_config.h"
#include "webfuse/adapter/impl/server_config.h"
#include "webfuse/adapter/impl/authenticator.h"
#include "webfuse/utils/tempdir.hpp"
using webfuse_test::TempDir;
namespace
{
wf_mountpoint * create_mountpoint(
char const * filesystem,
void * user_data)
{
(void) filesystem;
(void) user_data;
return nullptr;
}
bool authenticate(
wf_credentials * credentials,
void * user_data)
{
(void) credentials;
(void) user_data;
return false;
}
}
TEST(server_config, create_dispose)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
wf_server_config_dispose(config);
}
TEST(server_config, set_documentroot)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(nullptr, config->document_root);
wf_server_config_set_documentroot(config, "www");
ASSERT_STREQ("www", config->document_root);
wf_server_config_set_documentroot(config, "/var/www");
ASSERT_STREQ("/var/www", config->document_root);
wf_server_config_dispose(config);
}
TEST(server_config, set_keypath)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(nullptr, config->key_path);
wf_server_config_set_keypath(config, "key.pem");
ASSERT_STREQ("key.pem", config->key_path);
wf_server_config_set_keypath(config, "pki/self/key.pem");
ASSERT_STREQ("pki/self/key.pem", config->key_path);
wf_server_config_dispose(config);
}
TEST(server_config, set_certpath)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(nullptr, config->key_path);
wf_server_config_set_certpath(config, "cert.pem");
ASSERT_STREQ("cert.pem", config->cert_path);
wf_server_config_set_certpath(config, "pki/self/cert.pem");
ASSERT_STREQ("pki/self/cert.pem", config->cert_path);
wf_server_config_dispose(config);
}
TEST(server_config, set_vhostname)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(nullptr, config->key_path);
wf_server_config_set_vhostname(config, "webfuse");
ASSERT_STREQ("webfuse", config->vhost_name);
wf_server_config_set_vhostname(config, "localhost");
ASSERT_STREQ("localhost", config->vhost_name);
wf_server_config_dispose(config);
}
TEST(server_config, set_port)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(0, config->port);
wf_server_config_set_port(config, 8443);
ASSERT_EQ(8443, config->port);
wf_server_config_set_port(config, 8080);
ASSERT_EQ(8080, config->port);
wf_server_config_dispose(config);
}
TEST(server_config, set_mountpoint)
{
TempDir temp("server_config");
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(nullptr, config->mountpoint_factory.create_mountpoint);
ASSERT_EQ(nullptr, config->mountpoint_factory.user_data);
ASSERT_EQ(nullptr, config->mountpoint_factory.dispose);
wf_server_config_set_mountpoint(config, temp.path());
ASSERT_NE(nullptr, config->mountpoint_factory.create_mountpoint);
ASSERT_NE(nullptr, config->mountpoint_factory.user_data);
ASSERT_NE(nullptr, config->mountpoint_factory.dispose);
wf_server_config_dispose(config);
}
TEST(server_config, set_mounpoint_factory)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(nullptr, config->mountpoint_factory.create_mountpoint);
ASSERT_EQ(nullptr, config->mountpoint_factory.user_data);
ASSERT_EQ(nullptr, config->mountpoint_factory.dispose);
int value = 42;
void * user_data = reinterpret_cast<void*>(&value);
wf_server_config_set_mountpoint_factory(config, &create_mountpoint, user_data);
ASSERT_EQ(&create_mountpoint, config->mountpoint_factory.create_mountpoint);
ASSERT_EQ(user_data, config->mountpoint_factory.user_data);
ASSERT_EQ(nullptr, config->mountpoint_factory.dispose);
wf_server_config_dispose(config);
}
TEST(server_config, add_authenticator)
{
wf_server_config * config = wf_server_config_create();
ASSERT_NE(nullptr, config);
ASSERT_EQ(nullptr, config->authenticators.first);
int value = 42;
void * user_data = reinterpret_cast<void*>(&value);
wf_server_config_add_authenticator(config, "username", &authenticate, user_data);
wf_impl_authenticator * authenticator = config->authenticators.first;
ASSERT_STREQ("username", authenticator->type);
ASSERT_EQ(&authenticate, authenticator->authenticate);
ASSERT_EQ(user_data, authenticator->user_data);
wf_server_config_dispose(config);
}

View File

@@ -0,0 +1,36 @@
#include <gtest/gtest.h>
#include "webfuse/utils/msleep.hpp"
#include "webfuse/adapter/impl/time/timepoint.h"
using webfuse_test::msleep;
TEST(timepoint, now)
{
wf_impl_timepoint start = wf_impl_timepoint_now();
msleep(42);
wf_impl_timepoint end = wf_impl_timepoint_now();
ASSERT_LT(start, end);
ASSERT_LT(end, start + 500);
}
TEST(timepoint, in_msec)
{
wf_impl_timepoint now = wf_impl_timepoint_now();
wf_impl_timepoint later = wf_impl_timepoint_in_msec(42);
ASSERT_LT(now, later);
ASSERT_LT(later, now + 500);
}
TEST(wf_impl_timepoint, elapsed)
{
wf_impl_timepoint now;
now = wf_impl_timepoint_now();
ASSERT_TRUE(wf_impl_timepoint_is_elapsed(now - 1));
now =wf_impl_timepoint_now();
ASSERT_FALSE(wf_impl_timepoint_is_elapsed(now + 500));
}

View File

@@ -0,0 +1,149 @@
#include <gtest/gtest.h>
#include <cstddef>
#include "webfuse/utils/msleep.hpp"
#include "webfuse/adapter/impl/time/timer.h"
#include "webfuse/adapter/impl/time/timeout_manager.h"
using std::size_t;
using webfuse_test::msleep;
namespace
{
void on_timeout(struct wf_impl_timer * timer)
{
bool * triggered = reinterpret_cast<bool*>(timer->user_data);
*triggered = true;
}
}
TEST(timer, init)
{
struct wf_impl_timeout_manager manager;
struct wf_impl_timer timer;
wf_impl_timeout_manager_init(&manager);
wf_impl_timer_init(&timer, &manager);
wf_impl_timer_cleanup(&timer);
wf_impl_timeout_manager_cleanup(&manager);
}
TEST(timer, trigger)
{
struct wf_impl_timeout_manager manager;
struct wf_impl_timer timer;
wf_impl_timeout_manager_init(&manager);
wf_impl_timer_init(&timer, &manager);
bool triggered = false;
wf_impl_timer_start(&timer, wf_impl_timepoint_in_msec(250), &on_timeout, reinterpret_cast<void*>(&triggered));
msleep(500);
wf_impl_timeout_manager_check(&manager);
ASSERT_TRUE(triggered);
wf_impl_timer_cleanup(&timer);
wf_impl_timeout_manager_cleanup(&manager);
}
TEST(timer, trigger_on_cleanup)
{
struct wf_impl_timeout_manager manager;
struct wf_impl_timer timer;
wf_impl_timeout_manager_init(&manager);
wf_impl_timer_init(&timer, &manager);
bool triggered = false;
wf_impl_timer_start(&timer, wf_impl_timepoint_in_msec(5 * 60 * 1000), &on_timeout, reinterpret_cast<void*>(&triggered));
wf_impl_timeout_manager_cleanup(&manager);
ASSERT_TRUE(triggered);
wf_impl_timer_cleanup(&timer);
}
TEST(timer, cancel)
{
struct wf_impl_timeout_manager manager;
struct wf_impl_timer timer;
wf_impl_timeout_manager_init(&manager);
wf_impl_timer_init(&timer, &manager);
bool triggered = false;
wf_impl_timer_start(&timer, wf_impl_timepoint_in_msec(250), &on_timeout, &triggered);
msleep(500);
wf_impl_timer_cancel(&timer);
wf_impl_timeout_manager_check(&manager);
ASSERT_FALSE(triggered);
wf_impl_timer_cleanup(&timer);
wf_impl_timeout_manager_cleanup(&manager);
}
TEST(timer, cancel_multiple_timers)
{
static size_t const count = 5;
struct wf_impl_timeout_manager manager;
struct wf_impl_timer timer[count];
wf_impl_timeout_manager_init(&manager);
bool triggered = false;
for(size_t i = 0; i < count; i++)
{
wf_impl_timer_init(&timer[i], &manager);
wf_impl_timer_start(&timer[i], wf_impl_timepoint_in_msec(0), &on_timeout, &triggered);
}
msleep(10);
for(size_t i = 0; i < count; i++)
{
wf_impl_timer_cancel(&timer[i]);
}
wf_impl_timeout_manager_check(&manager);
ASSERT_FALSE(triggered);
for(size_t i = 0; i < count; i++)
{
wf_impl_timer_cleanup(&timer[0]);
}
wf_impl_timeout_manager_cleanup(&manager);
}
TEST(timer, multiple_timers)
{
static size_t const count = 5;
struct wf_impl_timeout_manager manager;
struct wf_impl_timer timer[count];
bool triggered[count];
wf_impl_timeout_manager_init(&manager);
for(size_t i = 0; i < count; i++)
{
wf_impl_timer_init(&timer[i], &manager);
triggered[i] = false;
wf_impl_timer_start(&timer[i], wf_impl_timepoint_in_msec(300 - (50 * i)), &on_timeout, &triggered[i]);
}
for(size_t i = 0; i < count; i++)
{
msleep(100);
wf_impl_timeout_manager_check(&manager);
}
for(size_t i = 0; i < count; i++)
{
ASSERT_TRUE(triggered[i]);
wf_impl_timer_cleanup(&timer[i]);
}
wf_impl_timeout_manager_cleanup(&manager);
}

View File

@@ -0,0 +1,72 @@
#include <gtest/gtest.h>
#include "webfuse/utils/tempdir.hpp"
#include "webfuse/utils/file_utils.hpp"
#include "webfuse_adapter.h"
#include "webfuse/adapter/impl/uuid_mountpoint.h"
#include <string>
using webfuse_test::TempDir;
using webfuse_test::is_dir;
using webfuse_test::is_symlink;
using webfuse_test::is_same_path;
TEST(uuid_mountpoint, create)
{
TempDir temp("uuid_mountpoint");
std::string filesystem_path = std::string(temp.path()) + "/dummy";
std::string default_path = std::string(temp.path()) + "/dummy/default";
wf_mountpoint * mountpoint = wf_impl_uuid_mountpoint_create(temp.path(), "dummy");
std::string path = wf_mountpoint_get_path(mountpoint);
ASSERT_NE(nullptr, mountpoint);
ASSERT_TRUE(is_dir(filesystem_path));
ASSERT_TRUE(is_symlink(default_path));
ASSERT_TRUE(is_dir(default_path));
ASSERT_TRUE(is_dir(path));
ASSERT_TRUE(is_same_path(default_path, path));
wf_mountpoint_dispose(mountpoint);
ASSERT_FALSE(is_dir(filesystem_path));
ASSERT_FALSE(is_symlink(default_path));
ASSERT_FALSE(is_dir(default_path));
ASSERT_FALSE(is_dir(path));
}
TEST(uuid_mountpoint, relink_default)
{
TempDir temp("uuid_mountpoint");
std::string filesystem_path = std::string(temp.path()) + "/dummy";
std::string default_path = std::string(temp.path()) + "/dummy/default";
wf_mountpoint * mountpoint_a = wf_impl_uuid_mountpoint_create(temp.path(), "dummy");
std::string path_a = wf_mountpoint_get_path(mountpoint_a);
wf_mountpoint * mountpoint_b = wf_impl_uuid_mountpoint_create(temp.path(), "dummy");
std::string path_b = wf_mountpoint_get_path(mountpoint_b);
ASSERT_TRUE(is_dir(filesystem_path));
ASSERT_TRUE(is_symlink(default_path));
ASSERT_TRUE(is_dir(default_path));
ASSERT_TRUE(is_dir(path_a));
ASSERT_TRUE(is_dir(path_b));
ASSERT_TRUE(is_same_path(default_path, path_a));
wf_mountpoint_dispose(mountpoint_a);
ASSERT_TRUE(is_dir(filesystem_path));
ASSERT_TRUE(is_symlink(default_path));
ASSERT_TRUE(is_dir(default_path));
ASSERT_FALSE(is_dir(path_a));
ASSERT_TRUE(is_dir(path_b));
ASSERT_TRUE(is_same_path(default_path, path_b));
wf_mountpoint_dispose(mountpoint_b);
ASSERT_FALSE(is_dir(filesystem_path));
ASSERT_FALSE(is_symlink(default_path));
ASSERT_FALSE(is_dir(default_path));
ASSERT_FALSE(is_dir(path_a));
ASSERT_FALSE(is_dir(path_b));
}

View File

@@ -0,0 +1,61 @@
#include <gtest/gtest.h>
#include "webfuse_adapter.h"
#include "webfuse/adapter/impl/uuid_mountpoint_factory.h"
#include "webfuse/utils/tempdir.hpp"
#include "webfuse/utils/file_utils.hpp"
using webfuse_test::TempDir;
using webfuse_test::is_dir;
TEST(uuid_mountpoint_factory, create_existing_dir)
{
TempDir temp("uuid_mountpoint_factory");
struct wf_impl_mountpoint_factory factory;
bool factory_created = wf_impl_uuid_mountpoint_factory_init(&factory, temp.path());
ASSERT_TRUE(factory_created);
ASSERT_TRUE(is_dir(temp.path()));
wf_mountpoint * mountpoint = wf_impl_mountpoint_factory_create_mountpoint(&factory, "dummy");
std::string path = wf_mountpoint_get_path(mountpoint);
ASSERT_TRUE(is_dir(path));
wf_mountpoint_dispose(mountpoint);
ASSERT_FALSE(is_dir(path));
wf_impl_mountpoint_factory_cleanup(&factory);
// keep dir not created by factory
ASSERT_TRUE(is_dir(temp.path()));
}
TEST(uuid_mountpoint_factory, create_nonexisting_dir)
{
TempDir temp("uuid_mountpoint_factory");
std::string root_path = std::string(temp.path()) + "/root";
struct wf_impl_mountpoint_factory factory;
bool factory_created = wf_impl_uuid_mountpoint_factory_init(&factory, root_path.c_str());
ASSERT_TRUE(factory_created);
ASSERT_TRUE(is_dir(root_path));
wf_mountpoint * mountpoint = wf_impl_mountpoint_factory_create_mountpoint(&factory, "dummy");
std::string path = wf_mountpoint_get_path(mountpoint);
ASSERT_TRUE(is_dir(path));
wf_mountpoint_dispose(mountpoint);
ASSERT_FALSE(is_dir(path));
wf_impl_mountpoint_factory_cleanup(&factory);
// remove dir, created by factory
ASSERT_FALSE(is_dir(root_path));
}
TEST(uuid_mountpoint_factory, fail_to_created_nested_dir)
{
TempDir temp("uuid_mountpoint_factory");
std::string root_path = std::string(temp.path()) + "/nested/root";
struct wf_impl_mountpoint_factory factory;
bool factory_created = wf_impl_uuid_mountpoint_factory_init(&factory, root_path.c_str());
ASSERT_FALSE(factory_created);
}

View File

@@ -0,0 +1,122 @@
#include <gtest/gtest.h>
#include "webfuse/core/base64.h"
TEST(Base64, EncodedSize)
{
ASSERT_EQ(4, wf_base64_encoded_size(1));
ASSERT_EQ(4, wf_base64_encoded_size(2));
ASSERT_EQ(4, wf_base64_encoded_size(3));
ASSERT_EQ(8, wf_base64_encoded_size(4));
ASSERT_EQ(8, wf_base64_encoded_size(5));
ASSERT_EQ(8, wf_base64_encoded_size(6));
ASSERT_EQ(120, wf_base64_encoded_size(90));
}
TEST(Base64, Encode)
{
char buffer[42];
std::string in = "Hello";
size_t length = wf_base64_encode((uint8_t const*) in.c_str(), in.size(), buffer, 42);
ASSERT_EQ(8, length);
ASSERT_STREQ("SGVsbG8=", buffer);
in = "Hello\n";
length = wf_base64_encode((uint8_t const*) in.c_str(), in.size(), buffer, 42);
ASSERT_EQ(8, length);
ASSERT_STREQ("SGVsbG8K", buffer);
in = "Blue";
length = wf_base64_encode((uint8_t const*) in.c_str(), in.size(), buffer, 42);
ASSERT_EQ(8, length);
ASSERT_STREQ("Qmx1ZQ==", buffer);
}
TEST(Base64, FailedToEncodeBufferTooSmall)
{
char buffer[1];
std::string in = "Hello";
size_t length = wf_base64_encode((uint8_t const*) in.c_str(), in.size(), buffer, 1);
ASSERT_EQ(0, length);
}
TEST(Base64, DecodedSize)
{
std::string in = "SGVsbG8="; // Hello
size_t length = wf_base64_decoded_size(in.c_str(), in.size());
ASSERT_EQ(5, length);
in = "SGVsbG8K"; // Hello\n
length = wf_base64_decoded_size(in.c_str(), in.size());
ASSERT_EQ(6, length);
in = "Qmx1ZQ=="; // Blue
length = wf_base64_decoded_size(in.c_str(), in.size());
ASSERT_EQ(4, length);
}
TEST(Base64, IsValid)
{
std::string in = "SGVsbG8="; // Hello
ASSERT_TRUE(wf_base64_isvalid(in.c_str(), in.size()));
in = "SGVsbG8K"; // Hello\n
ASSERT_TRUE(wf_base64_isvalid(in.c_str(), in.size()));
in = "Qmx1ZQ=="; // Blue
ASSERT_TRUE(wf_base64_isvalid(in.c_str(), in.size()));
in = "Qmx1ZQ=a";
ASSERT_FALSE(wf_base64_isvalid(in.c_str(), in.size()));
in = "Qmx1ZQ";
ASSERT_FALSE(wf_base64_isvalid(in.c_str(), in.size()));
in = "Qmx1ZQ=";
ASSERT_FALSE(wf_base64_isvalid(in.c_str(), in.size()));
in = "Qmx1Z===";
ASSERT_FALSE(wf_base64_isvalid(in.c_str(), in.size()));
in = "Qmx1ZQ?=";
ASSERT_FALSE(wf_base64_isvalid(in.c_str(), in.size()));
in = "Qm?1ZQ==";
ASSERT_FALSE(wf_base64_isvalid(in.c_str(), in.size()));
}
TEST(Base64, Decode)
{
char buffer[42];
std::string in = "SGVsbG8="; // Hello
size_t length = wf_base64_decode(in.c_str(), in.size(), (uint8_t*) buffer, 42);
ASSERT_EQ(5, length);
buffer[length] = '\0';
ASSERT_STREQ("Hello", buffer);
in = "SGVsbG8K"; // Hello\n
length = wf_base64_decode(in.c_str(), in.size(), (uint8_t*) buffer, 42);
ASSERT_EQ(6, length);
buffer[length] = '\0';
ASSERT_STREQ("Hello\n", buffer);
in = "Qmx1ZQ=="; // Blue
length = wf_base64_decode(in.c_str(), in.size(), (uint8_t*) buffer, 42);
ASSERT_EQ(4, length);
buffer[length] = '\0';
ASSERT_STREQ("Blue", buffer);
}
TEST(Base64, FailToDecodeBufferTooSmall)
{
char buffer[1];
std::string in = "SGVsbG8="; // Hello
size_t length = wf_base64_decode(in.c_str(), in.size(), (uint8_t*) buffer, 1);
ASSERT_EQ(0, length);
}

View File

@@ -0,0 +1,29 @@
#include <gtest/gtest.h>
#include "webfuse/core/container_of.h"
namespace
{
struct MyStruct
{
int first;
int second;
};
}
TEST(ContainerOf, FirstMember)
{
MyStruct my_struct = {23, 42};
int * first = &my_struct.first;
ASSERT_EQ(&my_struct, wf_container_of(first, MyStruct, first));
}
TEST(ContainerOf, SecondMember)
{
MyStruct my_struct = {23, 42};
int * second = &my_struct.second;
ASSERT_EQ(&my_struct, wf_container_of(second, MyStruct, second));
}

View File

@@ -0,0 +1,22 @@
#include <gtest/gtest.h>
#include <cstring>
#include "webfuse/core/message.h"
TEST(wf_message, create)
{
json_t * value = json_object();
struct wf_message * message = wf_message_create(value);
ASSERT_NE(nullptr, message);
ASSERT_EQ(2, message->length);
ASSERT_TRUE(0 == strncmp("{}", message->data, 2));
wf_message_dispose(message);
json_decref(value);
}
TEST(wf_message, fail_to_create)
{
struct wf_message * message = wf_message_create(nullptr);
ASSERT_EQ(nullptr, message);
}

View File

@@ -0,0 +1,52 @@
#include <gtest/gtest.h>
#include "webfuse/core/message_queue.h"
#include "webfuse/core/message.h"
#include "webfuse/core/slist.h"
namespace
{
struct wf_slist_item * create_message(char const * content)
{
json_t * value = json_object();
json_object_set_new(value, "content", json_string(content));
struct wf_message * message = wf_message_create(value);
json_decref(value);
return &message->item;
}
}
TEST(wf_message_queue, cleanup_empty_list)
{
struct wf_slist queue;
wf_slist_init(&queue);
wf_message_queue_cleanup(&queue);
ASSERT_TRUE(wf_slist_empty(&queue));
}
TEST(wf_message_queue, cleanup_one_element)
{
struct wf_slist queue;
wf_slist_init(&queue);
wf_slist_append(&queue, create_message("Hello"));
wf_message_queue_cleanup(&queue);
ASSERT_TRUE(wf_slist_empty(&queue));
}
TEST(wf_message_queue, cleanup_multiple_element)
{
struct wf_slist queue;
wf_slist_init(&queue);
wf_slist_append(&queue, create_message("Hello"));
wf_slist_append(&queue, create_message("World"));
wf_slist_append(&queue, create_message("!"));
wf_message_queue_cleanup(&queue);
ASSERT_TRUE(wf_slist_empty(&queue));
}

View File

@@ -0,0 +1,58 @@
#include <gtest/gtest.h>
#include "webfuse/core/path.h"
TEST(wf_path, empty)
{
struct wf_path * path = wf_path_create("");
ASSERT_EQ(0, wf_path_element_count(path));
ASSERT_EQ(nullptr, wf_path_get_element(path, 0));
wf_path_dispose(path);
}
TEST(wf_path, relative_file)
{
struct wf_path * path = wf_path_create("some.file");
ASSERT_EQ(1, wf_path_element_count(path));
ASSERT_STREQ("some.file", wf_path_get_element(path, 0));
wf_path_dispose(path);
}
TEST(wf_path, absolute_file)
{
struct wf_path * path = wf_path_create("/absolute.file");
ASSERT_EQ(1, wf_path_element_count(path));
ASSERT_STREQ("absolute.file", wf_path_get_element(path, 0));
wf_path_dispose(path);
}
TEST(wf_path, nested_path)
{
struct wf_path * path = wf_path_create("/a/nested/path");
ASSERT_EQ(3, wf_path_element_count(path));
ASSERT_STREQ("a", wf_path_get_element(path, 0));
ASSERT_STREQ("nested", wf_path_get_element(path, 1));
ASSERT_STREQ("path", wf_path_get_element(path, 2));
wf_path_dispose(path);
}
TEST(wf_path, deep_nested_path)
{
struct wf_path * path = wf_path_create("/this/is/a/very/deep/nested/path/to/some/file");
ASSERT_EQ(10, wf_path_element_count(path));
ASSERT_STREQ("this", wf_path_get_element(path, 0));
ASSERT_STREQ("is", wf_path_get_element(path, 1));
ASSERT_STREQ("a", wf_path_get_element(path, 2));
ASSERT_STREQ("very", wf_path_get_element(path, 3));
ASSERT_STREQ("deep", wf_path_get_element(path, 4));
ASSERT_STREQ("nested", wf_path_get_element(path, 5));
ASSERT_STREQ("path", wf_path_get_element(path, 6));
ASSERT_STREQ("to", wf_path_get_element(path, 7));
ASSERT_STREQ("some", wf_path_get_element(path, 8));
ASSERT_STREQ("file", wf_path_get_element(path, 9));
wf_path_dispose(path);
}

View File

@@ -0,0 +1,139 @@
#include <gtest/gtest.h>
#include "webfuse/core/slist.h"
TEST(wf_slist, init)
{
struct wf_slist list;
wf_slist_init(&list);
ASSERT_EQ(nullptr, list.head.next);
ASSERT_EQ(nullptr, list.last->next);
ASSERT_EQ(&list.head, list.last);
ASSERT_TRUE(wf_slist_empty(&list));
ASSERT_EQ(nullptr, wf_slist_first(&list));
}
TEST(wf_slist, append)
{
struct wf_slist list;
struct wf_slist_item item[3];
wf_slist_init(&list);
ASSERT_TRUE(wf_slist_empty(&list));
wf_slist_append(&list, &item[0]);
ASSERT_NE(&list.head, list.last);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[0], wf_slist_first(&list));
ASSERT_EQ(&item[0], list.head.next);
ASSERT_EQ(&item[0], list.last);
ASSERT_EQ(nullptr, list.last->next);
ASSERT_EQ(nullptr, item[0].next);
wf_slist_append(&list, &item[1]);
ASSERT_NE(&list.head, list.last);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[0], wf_slist_first(&list));
ASSERT_EQ(&item[0], list.head.next);
ASSERT_EQ(&item[1], list.last);
ASSERT_EQ(nullptr, list.last->next);
ASSERT_EQ(&item[1], item[0].next);
ASSERT_EQ(nullptr, item[1].next);
wf_slist_append(&list, &item[2]);
ASSERT_NE(&list.head, list.last);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[0], wf_slist_first(&list));
ASSERT_EQ(&item[0], list.head.next);
ASSERT_EQ(&item[2], list.last);
ASSERT_EQ(nullptr, list.last->next);
ASSERT_EQ(&item[1], item[0].next);
ASSERT_EQ(&item[2], item[1].next);
ASSERT_EQ(nullptr, item[2].next);
}
TEST(wf_slist_remove_after, remove_first)
{
struct wf_slist list;
struct wf_slist_item item[3];
wf_slist_init(&list);
wf_slist_append(&list, &item[0]);
wf_slist_append(&list, &item[1]);
wf_slist_append(&list, &item[2]);
wf_slist_item * removed;
removed = wf_slist_remove_first(&list);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[0], removed);
removed = wf_slist_remove_first(&list);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[1], removed);
removed = wf_slist_remove_first(&list);
ASSERT_TRUE(wf_slist_empty(&list));
ASSERT_EQ(&item[2], removed);
ASSERT_EQ(nullptr, list.head.next);
ASSERT_EQ(nullptr, list.last->next);
ASSERT_EQ(&list.head, list.last);
ASSERT_EQ(nullptr, wf_slist_first(&list));
}
TEST(wf_slist_remove_after, remove_last)
{
struct wf_slist list;
struct wf_slist_item item[3];
wf_slist_init(&list);
wf_slist_append(&list, &item[0]);
wf_slist_append(&list, &item[1]);
wf_slist_append(&list, &item[2]);
wf_slist_item * removed;
removed = wf_slist_remove_after(&list, &item[1]);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[2], removed);
removed = wf_slist_remove_after(&list, &item[0]);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[1], removed);
removed = wf_slist_remove_after(&list, &list.head);
ASSERT_TRUE(wf_slist_empty(&list));
ASSERT_EQ(&item[0], removed);
ASSERT_EQ(nullptr, list.head.next);
ASSERT_EQ(nullptr, list.last->next);
ASSERT_EQ(&list.head, list.last);
ASSERT_EQ(nullptr, wf_slist_first(&list));
}
TEST(wf_slist_remove_after, remove_after)
{
struct wf_slist list;
struct wf_slist_item item[3];
wf_slist_init(&list);
wf_slist_append(&list, &item[0]);
wf_slist_append(&list, &item[1]);
wf_slist_append(&list, &item[2]);
wf_slist_item * removed;
removed = wf_slist_remove_after(&list, &item[0]);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[1], removed);
ASSERT_NE(&list.head, list.last);
ASSERT_FALSE(wf_slist_empty(&list));
ASSERT_EQ(&item[0], wf_slist_first(&list));
ASSERT_EQ(&item[0], list.head.next);
ASSERT_EQ(&item[2], list.last);
ASSERT_EQ(nullptr, list.last->next);
ASSERT_EQ(&item[2], item[0].next);
ASSERT_EQ(nullptr, item[2].next);
}

View File

@@ -0,0 +1,30 @@
#include <gtest/gtest.h>
#include "webfuse/core/status_intern.h"
TEST(wf_status, tostring)
{
ASSERT_STREQ("Good", wf_status_tostring(WF_GOOD));
ASSERT_STREQ("Bad", wf_status_tostring(WF_BAD));
ASSERT_STREQ("Bad (not implemented)", wf_status_tostring(WF_BAD_NOTIMPLEMENTED));
ASSERT_STREQ("Bad (busy)", wf_status_tostring(WF_BAD_BUSY));
ASSERT_STREQ("Bad (timeout)", wf_status_tostring(WF_BAD_TIMEOUT));
ASSERT_STREQ("Bad (format)", wf_status_tostring(WF_BAD_FORMAT));
ASSERT_STREQ("Bad (no entry)", wf_status_tostring(WF_BAD_NOENTRY));
ASSERT_STREQ("Bad (access denied)", wf_status_tostring(WF_BAD_ACCESS_DENIED));
ASSERT_STREQ("Bad (unknown)", wf_status_tostring(-1));
}
TEST(wf_status, to_rc)
{
ASSERT_EQ(0, wf_status_to_rc(WF_GOOD));
ASSERT_EQ(-ENOENT, wf_status_to_rc(WF_BAD));
ASSERT_EQ(-ENOSYS, wf_status_to_rc(WF_BAD_NOTIMPLEMENTED));
ASSERT_EQ(-ENOENT, wf_status_to_rc(WF_BAD_BUSY));
ASSERT_EQ(-ETIMEDOUT, wf_status_to_rc(WF_BAD_TIMEOUT));
ASSERT_EQ(-ENOENT, wf_status_to_rc(WF_BAD_FORMAT));
ASSERT_EQ(-ENOENT, wf_status_to_rc(WF_BAD_NOENTRY));
ASSERT_EQ(-EACCES, wf_status_to_rc(WF_BAD_ACCESS_DENIED));
ASSERT_EQ(-ENOENT, wf_status_to_rc(-1));
}

View File

@@ -0,0 +1,18 @@
#include <gtest/gtest.h>
#include <stdlib.h>
#include "webfuse/core/string.h"
TEST(wf_string_create, Default)
{
char * value = wf_create_string("test %s/%d", "hello", 42);
ASSERT_STREQ("test hello/42", value);
free(value);
}
TEST(wf_string_create, EmptyString)
{
char * value = wf_create_string("");
ASSERT_STREQ("", value);
free(value);
}

View File

@@ -0,0 +1,85 @@
#include "webfuse/tests/integration/provider.hpp"
#include "webfuse_provider.h"
#include "webfuse/provider/impl/client.h"
#include <thread>
#include <mutex>
#include <string>
#include "webfuse/utils/msleep.hpp"
namespace webfuse_test
{
class Provider::Private
{
public:
explicit Private(char const * url)
: is_shutdown_requested(false)
{
config = wfp_client_config_create();
fs = wfp_static_filesystem_create(config);
wfp_static_filesystem_add_text(fs, "hello.txt", 0444, "Hello, World");
client = wfp_client_create(config);
wfp_client_connect(client, url);
while (!wfp_impl_client_is_connected(client))
{
wfp_client_service(client, 100);
}
thread = std::thread(Run, this);
webfuse_test::msleep(200);
}
~Private()
{
RequestShutdown();
thread.join();
wfp_client_dispose(client);
wfp_static_filesystem_dispose(fs);
wfp_client_config_dispose(config);
}
bool IsShutdownRequested()
{
std::lock_guard<std::mutex> lock(shutdown_lock);
return is_shutdown_requested;
}
private:
void RequestShutdown()
{
std::lock_guard<std::mutex> lock(shutdown_lock);
is_shutdown_requested = true;
}
static void Run(Provider::Private * context)
{
while (!context->IsShutdownRequested())
{
wfp_client_service(context->client, 100);
}
}
std::mutex shutdown_lock;
std::thread thread;
bool is_shutdown_requested;
wfp_client_config * config;
wfp_static_filesystem * fs;
public:
wfp_client * client;
};
Provider::Provider(char const * url)
: d(new Provider::Private(url))
{
}
Provider::~Provider()
{
delete d;
}
}

View File

@@ -0,0 +1,19 @@
#ifndef WF_TEST_INTEGRATION_PROVIDER
#define WF_TEST_INTEGRATION_PROVIDER
namespace webfuse_test
{
class Provider
{
public:
explicit Provider(char const * url);
~Provider();
private:
class Private;
Private * d;
};
}
#endif

View File

@@ -0,0 +1,99 @@
#include "webfuse/tests/integration/server.hpp"
#include <thread>
#include <mutex>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include "webfuse_adapter.h"
#include "webfuse/adapter/impl/server.h"
#include "webfuse/utils/msleep.hpp"
#define WF_PATH_MAX (100)
namespace webfuse_test
{
class Server::Private
{
public:
Private()
: is_shutdown_requested(false)
{
snprintf(base_dir, WF_PATH_MAX, "%s", "/tmp/webfuse_test_integration_XXXXXX");
mkdtemp(base_dir);
config = wf_server_config_create();
wf_server_config_set_port(config, 8080);
wf_server_config_set_mountpoint(config, base_dir);
server = wf_server_create(config);
while (!wf_impl_server_is_operational(server))
{
wf_server_service(server, 100);
}
thread = std::thread(Run, this);
}
~Private()
{
RequestShutdown();
thread.join();
rmdir(base_dir);
wf_server_dispose(server);
wf_server_config_dispose(config);
}
bool IsShutdownRequested()
{
std::lock_guard<std::mutex> lock(shutdown_lock);
return is_shutdown_requested;
}
private:
void RequestShutdown()
{
std::lock_guard<std::mutex> lock(shutdown_lock);
is_shutdown_requested = true;
}
static void Run(Server::Private * context)
{
while (!context->IsShutdownRequested())
{
wf_server_service(context->server, 100);
}
}
std::mutex shutdown_lock;
std::thread thread;
bool is_shutdown_requested;
public:
char base_dir[WF_PATH_MAX];
wf_server_config * config;
wf_server * server;
};
Server::Server()
: d(new Server::Private())
{
}
Server::~Server()
{
delete d;
}
char const * Server::GetBaseDir(void) const
{
return d->base_dir;
}
}

View File

@@ -0,0 +1,22 @@
#ifndef WF_TEST_INTEGRATION_SERVER_HPP
#define WF_TEST_INTEGRATION_SERVER_HPP
namespace webfuse_test
{
class Server
{
public:
Server();
~Server();
void Start(void);
void Stop(void);
char const * GetBaseDir(void) const;
private:
class Private;
Private * d;
};
}
#endif

View File

@@ -0,0 +1,156 @@
#include <gtest/gtest.h>
#include "webfuse/tests/integration/server.hpp"
#include "webfuse/tests/integration/provider.hpp"
#include <cstdio>
#include <csignal>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <jansson.h>
#include "webfuse/core/lws_log.h"
#include "webfuse/utils/die_if.hpp"
using webfuse_test::Server;
using webfuse_test::Provider;
using webfuse_test::die_if;
namespace
{
class IntegrationTest: public ::testing::Test
{
public:
IntegrationTest()
: server(nullptr)
, provider(nullptr)
{
json_object_seed(0);
wf_lwslog_disable();
}
protected:
void SetUp()
{
server = new Server();
provider = new Provider("ws://localhost:8080/");
}
void TearDown()
{
delete provider;
delete server;
}
char const * GetBaseDir() const
{
return server->GetBaseDir();
}
private:
Server * server;
Provider * provider;
};
}
TEST_F(IntegrationTest, HasMountpoint)
{
struct stat buffer;
int rc = stat(GetBaseDir(), &buffer);
ASSERT_EQ(0, rc);
ASSERT_TRUE(S_ISDIR(buffer.st_mode));
}
TEST_F(IntegrationTest, ProvidesTextFile)
{
std::string file_name = std::string(GetBaseDir()) + "/cprovider/default/hello.txt";
ASSERT_EXIT({
struct stat buffer;
int rc = stat(file_name.c_str(), &buffer);
die_if(0 != rc);
die_if(!S_ISREG(buffer.st_mode));
die_if(0444 != (buffer.st_mode & 0777));
die_if(12 != buffer.st_size);
exit(0);
}, ::testing::ExitedWithCode(0), ".*");
}
TEST_F(IntegrationTest, ReadTextFile)
{
std::string file_name = std::string(GetBaseDir()) + "/cprovider/default/hello.txt";
ASSERT_EXIT({
FILE * file = fopen(file_name.c_str(), "rb");
die_if(nullptr == file);
char buffer[13];
ssize_t count = fread(buffer, 1, 12, file);
int rc = fclose(file);
die_if(12 != count);
die_if(0 != strncmp("Hello, World", buffer, 12));
die_if(0 != rc);
exit(0);
}, ::testing::ExitedWithCode(0), ".*");
}
TEST_F(IntegrationTest, ReadDir)
{
std::string dir_name = std::string(GetBaseDir()) + "/cprovider/default";
ASSERT_EXIT({
DIR * dir = opendir(dir_name.c_str());
die_if(nullptr == dir);
bool found_self = false;
bool found_parent = false;
bool found_hello_txt = false;
bool found_other = false;
dirent * entry = readdir(dir);
while (NULL != entry)
{
if (0 == strcmp(".", entry->d_name))
{
found_self = true;
}
else if (0 == strcmp("..", entry->d_name))
{
found_parent = true;
}
else if (0 == strcmp("hello.txt", entry->d_name))
{
found_hello_txt = true;
}
else
{
found_other = true;
}
entry = readdir(dir);
}
closedir(dir);
die_if(!found_self);
die_if(!found_parent);
die_if(!found_hello_txt);
die_if(found_other);
exit(0);
}, ::testing::ExitedWithCode(0), ".*");
}

View File

@@ -0,0 +1,72 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <webfuse/provider/client_protocol.h>
#include <webfuse/provider/client_config.h>
#include "webfuse/fakes/fake_adapter_server.hpp"
#include <cstring>
#include <thread>
#include <atomic>
using webfuse_test::FakeAdapterServer;
using testing::_;
namespace
{
struct Context
{
lws_context * context;
std::atomic<bool> isShutdownRequested;
};
void run(Context * context)
{
while (!context->isShutdownRequested)
{
lws_service(context->context, 100);
}
}
}
TEST(client_protocol, connect)
{
FakeAdapterServer server(54321);
wfp_client_config * config = wfp_client_config_create();
wfp_client_protocol * protocol = wfp_client_protocol_create(config);
struct lws_protocols protocols[2];
memset(protocols, 0, sizeof(struct lws_protocols) * 2);
protocols[0].name = "fs";
wfp_client_protocol_init_lws(protocol, &protocols[0]);
struct lws_context_creation_info info;
memset(&info, 0, sizeof(struct lws_context_creation_info));
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = protocols;
info.uid = -1;
info.gid = -1;
struct lws_context * context = lws_create_context(&info);
wfp_client_protocol_connect(protocol, context, "ws://localhost:54321/");
Context ctx;
ctx.context = context;
ctx.isShutdownRequested = false;
std::thread client_thread(run, &ctx);
server.waitForConnection();
ctx.isShutdownRequested = true;
client_thread.join();
lws_context_destroy(context);
wfp_client_protocol_dispose(protocol);
wfp_client_config_dispose(config);
}

View File

@@ -0,0 +1,61 @@
#include <gtest/gtest.h>
#include "webfuse/provider/impl/static_filesystem.h"
#include "webfuse/provider/client_config.h"
#include "webfuse/provider/impl/client_config.h"
#include "webfuse/mocks/mock_request.hpp"
using webfuse_test::request_create;
using webfuse_test::MockRequest;
using webfuse_test::GetAttrMatcher;
using webfuse_test::ReaddirMatcher;
using testing::_;
TEST(wfp_static_filesystem, has_root_dir)
{
struct wfp_client_config * config = wfp_client_config_create();
struct wfp_static_filesystem * filesystem = wfp_impl_static_filesystem_create(config);
MockRequest mock;
struct wfp_request * request = request_create(&mock, 42);
EXPECT_CALL(mock, respond(GetAttrMatcher(1, 0555, "dir"), 42)).Times(1);
config->provider.getattr(request, 1, config->user_data);
wfp_impl_static_filesystem_dispose(filesystem);
wfp_client_config_dispose(config);
}
TEST(wfp_static_filesystem, contains_default_dirs)
{
struct wfp_client_config * config = wfp_client_config_create();
struct wfp_static_filesystem * filesystem = wfp_impl_static_filesystem_create(config);
MockRequest mock;
struct wfp_request * request = request_create(&mock, 23);
char const * default_dirs[] = {".", "..", nullptr};
EXPECT_CALL(mock, respond(ReaddirMatcher(default_dirs), 23)).Times(1);
config->provider.readdir(request, 1, config->user_data);
wfp_impl_static_filesystem_dispose(filesystem);
wfp_client_config_dispose(config);
}
TEST(wfp_static_filesystem, add_text)
{
struct wfp_client_config * config = wfp_client_config_create();
struct wfp_static_filesystem * filesystem = wfp_impl_static_filesystem_create(config);
wfp_impl_static_filesystem_add_text(filesystem, "text.file", 666, "some text");
MockRequest mock;
struct wfp_request * request = request_create(&mock, 23);
char const * contained_elements[] = {"text.file", nullptr};
EXPECT_CALL(mock, respond(ReaddirMatcher(contained_elements), 23)).Times(1);
config->provider.readdir(request, 1, config->user_data);
wfp_impl_static_filesystem_dispose(filesystem);
wfp_client_config_dispose(config);
}

View File

@@ -0,0 +1,92 @@
#include <gtest/gtest.h>
#include "webfuse/provider/impl/url.h"
TEST(url, ParseWs)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "ws://localhost/");
ASSERT_TRUE(result);
ASSERT_EQ(80, url.port);
ASSERT_FALSE(url.use_tls);
ASSERT_STREQ("localhost", url.host);
ASSERT_STREQ("/", url.path);
wfp_impl_url_cleanup(&url);
}
TEST(url, ParswWss)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "wss://localhost/");
ASSERT_TRUE(result);
ASSERT_EQ(443, url.port);
ASSERT_TRUE(url.use_tls);
ASSERT_STREQ("localhost", url.host);
ASSERT_STREQ("/", url.path);
wfp_impl_url_cleanup(&url);
}
TEST(url, ParseIPAdress)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "ws://127.0.0.1/");
ASSERT_TRUE(result);
ASSERT_EQ(80, url.port);
ASSERT_STREQ("127.0.0.1", url.host);
ASSERT_STREQ("/", url.path);
wfp_impl_url_cleanup(&url);
}
TEST(url, ParsePort)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "ws://localhost:54321/");
ASSERT_TRUE(result);
ASSERT_EQ(54321, url.port);
wfp_impl_url_cleanup(&url);
}
TEST(url, ParseNonEmptyPath)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "ws://localhost/some_path?query");
ASSERT_TRUE(result);
ASSERT_STREQ("/some_path?query", url.path);
wfp_impl_url_cleanup(&url);
}
TEST(url, FailToParseUnknownProtocol)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "unknown://localhost/");
ASSERT_FALSE(result);
ASSERT_EQ(0, url.port);
ASSERT_EQ(nullptr, url.path);
ASSERT_EQ(nullptr, url.host);
}
TEST(url, FailToParseMissingProtocol)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "unknown");
ASSERT_FALSE(result);
ASSERT_EQ(0, url.port);
ASSERT_EQ(nullptr, url.path);
ASSERT_EQ(nullptr, url.host);
}
TEST(url, FailToParseMissingPath)
{
struct wfp_impl_url url;
bool result = wfp_impl_url_init(&url, "ws://localhost");
ASSERT_FALSE(result);
ASSERT_EQ(0, url.port);
ASSERT_EQ(nullptr, url.path);
ASSERT_EQ(nullptr, url.host);
}

View File

@@ -0,0 +1,15 @@
#include "webfuse/utils/die_if.hpp"
#include <cstdlib>
namespace webfuse_test
{
void die_if(bool expression)
{
if (expression)
{
exit(EXIT_FAILURE);
}
}
}

View File

@@ -0,0 +1,11 @@
#ifndef WF_TEST_DIE_IF_HPP
#define WF_TEST_DIE_IF_HPP
namespace webfuse_test
{
extern void die_if(bool expression);
}
#endif

View File

@@ -0,0 +1,38 @@
#include "webfuse/utils/file_utils.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace webfuse_test
{
bool is_dir(std::string const & path)
{
struct stat info;
int rc = stat(path.c_str(), &info);
return (0 == rc) && (S_ISDIR(info.st_mode));
}
bool is_symlink(std::string const & path)
{
struct stat info;
int rc = lstat(path.c_str(), &info);
return (0 == rc) && (S_ISLNK(info.st_mode));
}
bool is_same_path(std::string const & path, std::string const & other)
{
struct stat info;
int rc = stat(path.c_str(), &info);
struct stat info_other;
int rc_other = stat(other.c_str(), &info_other);
return (0 == rc) && (0 == rc_other) && (info.st_ino == info_other.st_ino);
}
}

View File

@@ -0,0 +1,17 @@
#ifndef WF_TEST_FILE_UTILS_HPP
#define WF_TEST_FILE_UTILS_HPP
#include <string>
namespace webfuse_test
{
bool is_dir(std::string const & path);
bool is_symlink(std::string const & path);
bool is_same_path(std::string const & path, std::string const & other);
}
#endif

View File

@@ -0,0 +1,19 @@
#include "webfuse/utils/msleep.hpp"
#include <ctime>
namespace webfuse_test
{
void msleep(long millis)
{
long const secs_per_msec = 1000;
long const msecs_per_nsec = (1000 * 1000);
long const seconds = millis / secs_per_msec;
long const nanos = (millis % secs_per_msec) * msecs_per_nsec;
struct timespec timeout = { seconds, nanos };
while (0 != nanosleep(&timeout, &timeout));
}
}

View File

@@ -0,0 +1,12 @@
#ifndef WF_TEST_MSLEEP_HPP
#define WF_TEST_MSLEEP_HPP
namespace webfuse_test
{
extern void msleep(long millis);
}
#endif

View File

@@ -0,0 +1,33 @@
#include "webfuse/core/string.h"
#include "webfuse/utils/tempdir.hpp"
#include <unistd.h>
#include <cstdlib>
#include <stdexcept>
namespace webfuse_test
{
TempDir::TempDir(char const * prefix)
: path_(wf_create_string("/tmp/%s_XXXXXX", prefix))
{
char * result = mkdtemp(path_);
if (NULL == result)
{
throw std::runtime_error("unable to create temp dir");
}
}
TempDir::~TempDir()
{
rmdir(path_);
free(path_);
}
char const * TempDir::path()
{
return path_;
}
}

View File

@@ -0,0 +1,21 @@
#ifndef WF_TEST_TEMPDIR_HPP
#define WF_TEST_TEMPDIR_HPP
namespace webfuse_test
{
class TempDir
{
TempDir(TempDir const &) = delete;
TempDir & operator=(TempDir const &) = delete;
public:
explicit TempDir(char const * prefix);
~TempDir();
char const * path();
private:
char * path_;
};
}
#endif

View File

@@ -0,0 +1,44 @@
#include "webfuse/utils/timeout_watcher.hpp"
#include <stdexcept>
using std::chrono::milliseconds;
using std::chrono::duration_cast;
using std::chrono::steady_clock;
namespace
{
milliseconds now()
{
return duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
}
}
namespace webfuse_test
{
TimeoutWatcher::TimeoutWatcher(milliseconds timeout)
: startedAt(now())
, timeout_(timeout)
{
}
TimeoutWatcher::~TimeoutWatcher()
{
}
bool TimeoutWatcher::isTimeout()
{
return (now() - startedAt) > timeout_;
}
void TimeoutWatcher::check()
{
if (isTimeout())
{
throw std::runtime_error("timeout");
}
}
}

View File

@@ -0,0 +1,26 @@
#ifndef WF_TEST_TIMEOUT_WATCHER_HPP
#define WF_TEST_TIMEOUT_WATCHER_HPP
#include <chrono>
namespace webfuse_test
{
class TimeoutWatcher final
{
TimeoutWatcher(TimeoutWatcher const & other) = delete;
TimeoutWatcher& operator=(TimeoutWatcher const & other) = delete;
public:
explicit TimeoutWatcher(std::chrono::milliseconds timeout);
~TimeoutWatcher();
bool isTimeout();
void check();
private:
std::chrono::milliseconds startedAt;
std::chrono::milliseconds timeout_;
};
}
#endif