Commit f81216be authored by Samir Halilcevic's avatar Samir Halilcevic

Refactor test cases and unify mock socket app

parent 4f20d587
This diff is collapsed.
......@@ -118,6 +118,59 @@ ptrdiff_t mock_stream_transport::handle_input() {
return result;
}
// -- mock_web_socket_app ------------------------------------------------------
mock_web_socket_app::mock_web_socket_app(bool behave_as_server)
: behave_as_server(behave_as_server) {
// nop
}
caf::error mock_web_socket_app::start(caf::net::web_socket::lower_layer* ll) {
down = ll;
if (behave_as_server)
down->request_messages();
return caf::none;
}
caf::error
mock_web_socket_app::accept(const caf::net::http::request_header& hdr) {
// Store the request information in cfg to evaluate them later.
auto& ws = cfg["web-socket"].as_dictionary();
put(ws, "method", to_rfc_string(hdr.method()));
put(ws, "path", std::string{hdr.path()});
put(ws, "query", hdr.query());
put(ws, "fragment", hdr.fragment());
put(ws, "http-version", hdr.version());
if (hdr.num_fields() > 0) {
auto& fields = ws["fields"].as_dictionary();
hdr.for_each_field([&fields](auto key, auto val) {
put(fields, std::string{key}, std::string{val});
});
}
return caf::none;
}
void mock_web_socket_app::abort(const caf::error& reason) {
if (expect_abort_) {
has_aborted = true;
err = reason;
expect_abort_ = false;
down->shutdown(reason);
} else {
CAF_FAIL("app::abort called: " << reason);
}
}
ptrdiff_t mock_web_socket_app::consume_text(std::string_view text) {
text_input.insert(text_input.end(), text.begin(), text.end());
return static_cast<ptrdiff_t>(text.size());
}
ptrdiff_t mock_web_socket_app::consume_binary(caf::byte_span bytes) {
binary_input.insert(binary_input.end(), bytes.begin(), bytes.end());
return static_cast<ptrdiff_t>(bytes.size());
}
// -- barrier ------------------------------------------------------------------
void barrier::arrive_and_wait() {
......
......@@ -5,6 +5,7 @@
#include "caf/net/octet_stream/upper_layer.hpp"
#include "caf/net/receive_policy.hpp"
#include "caf/net/socket.hpp"
#include "caf/net/web_socket/server.hpp"
#include "caf/settings.hpp"
#include "caf/span.hpp"
#include "caf/string_view.hpp"
......@@ -105,6 +106,63 @@ private:
caf::net::multiplexer* mpx_;
};
class mock_web_socket_app : public caf::net::web_socket::upper_layer::server {
public:
// -- constructor ------------------------------------------------------------
mock_web_socket_app(bool behave_as_server);
// -- factories --------------------------------------------------------------
static auto make(bool behave_as_server = false) {
return std::make_unique<mock_web_socket_app>(behave_as_server);
}
// -- initialization ---------------------------------------------------------
caf::error start(caf::net::web_socket::lower_layer* ll) override;
// -- implementation ---------------------------------------------------------
caf::error accept(const caf::net::http::request_header& hdr) override;
void prepare_send() override {
// nop
}
bool done_sending() override {
return true;
}
void abort(const caf::error& reason) override;
ptrdiff_t consume_text(std::string_view text) override;
ptrdiff_t consume_binary(caf::byte_span bytes) override;
void expect_abort() {
expect_abort_ = true;
}
// -- member variables -------------------------------------------------------
std::string text_input;
caf::byte_buffer binary_input;
caf::net::web_socket::lower_layer* down = nullptr;
caf::settings cfg;
bool behave_as_server = false;
caf::error err;
bool has_aborted = false;
bool expect_abort_ = false;
};
// Drop-in replacement for std::barrier (based on the TS API as of 2020).
class barrier {
public:
......
......@@ -14,43 +14,6 @@ namespace {
using svec = std::vector<std::string>;
class app_t : public net::web_socket::upper_layer {
public:
static auto make() {
return std::make_unique<app_t>();
}
std::string text_input;
caf::byte_buffer binary_input;
error start(net::web_socket::lower_layer*) override {
return none;
}
void prepare_send() override {
// nop
}
bool done_sending() override {
return true;
}
void abort(const error& reason) override {
CAF_FAIL("app::abort called: " << reason);
}
ptrdiff_t consume_text(std::string_view text) override {
text_input.insert(text_input.end(), text.begin(), text.end());
return static_cast<ptrdiff_t>(text.size());
}
ptrdiff_t consume_binary(byte_span bytes) override {
binary_input.insert(binary_input.end(), bytes.begin(), bytes.end());
return static_cast<ptrdiff_t>(bytes.size());
}
};
constexpr std::string_view key = "the sample nonce";
constexpr std::string_view http_request
......@@ -93,7 +56,7 @@ auto make_handshake() {
SCENARIO("the client performs the WebSocket handshake on startup") {
GIVEN("valid WebSocket handshake data") {
WHEN("starting a WebSocket client") {
auto app = app_t::make();
auto app = mock_web_socket_app::make();
auto ws = net::web_socket::client::make(make_handshake(), std::move(app));
auto uut = mock_stream_transport::make(std::move(ws));
THEN("the client sends its HTTP request when initializing it") {
......
......@@ -13,59 +13,13 @@ using namespace std::literals;
namespace {
class app_t : public net::web_socket::upper_layer {
public:
static auto make() {
return std::make_unique<app_t>();
}
std::string text_input;
caf::byte_buffer binary_input;
error err;
bool aborted = false;
net::web_socket::lower_layer* down = nullptr;
error start(net::web_socket::lower_layer* ll) override {
down = ll;
return none;
}
void prepare_send() override {
// nop
}
bool done_sending() override {
return true;
}
void abort(const error& reason) override {
aborted = true;
err = reason;
down->shutdown(reason);
}
ptrdiff_t consume_text(std::string_view text) override {
text_input.insert(text_input.end(), text.begin(), text.end());
return static_cast<ptrdiff_t>(text.size());
}
ptrdiff_t consume_binary(byte_span bytes) override {
binary_input.insert(binary_input.end(), bytes.begin(), bytes.end());
return static_cast<ptrdiff_t>(bytes.size());
}
};
struct fixture {
app_t* app;
mock_web_socket_app* app;
net::web_socket::framing* uut;
std::unique_ptr<mock_stream_transport> transport;
fixture() {
auto app_layer = app_t::make();
auto app_layer = mock_web_socket_app::make();
app = app_layer.get();
auto uut_layer
= net::web_socket::framing::make_server(std::move(app_layer));
......@@ -152,8 +106,9 @@ SCENARIO("the client sends an invalid ping that closes the connection") {
ping_frame);
transport->push(ping_frame);
THEN("the server aborts the application") {
app->expect_abort();
CHECK_EQ(transport->handle_input(), 0);
CHECK(app->aborted);
CHECK(app->has_aborted);
CHECK_EQ(app->err, sec::protocol_error);
MESSAGE("Aborted with: " << app->err);
}
......
......@@ -20,67 +20,10 @@ namespace {
using svec = std::vector<std::string>;
class app_t : public net::web_socket::upper_layer::server {
public:
std::string text_input;
byte_buffer binary_input;
settings cfg;
static auto make() {
return std::make_unique<app_t>();
}
error start(net::web_socket::lower_layer* down) override {
down->request_messages();
return none;
}
error accept(const net::http::request_header& hdr) override {
// Store the request information in cfg to evaluate them later.
auto& ws = cfg["web-socket"].as_dictionary();
put(ws, "method", to_rfc_string(hdr.method()));
put(ws, "path", std::string{hdr.path()});
put(ws, "query", hdr.query());
put(ws, "fragment", hdr.fragment());
put(ws, "http-version", hdr.version());
if (hdr.num_fields() > 0) {
auto& fields = ws["fields"].as_dictionary();
hdr.for_each_field([&fields](auto key, auto val) {
put(fields, std::string{key}, std::string{val});
});
}
return none;
}
void prepare_send() override {
// nop
}
bool done_sending() override {
return true;
}
void abort(const error& reason) override {
CAF_FAIL("app::abort called: " << reason);
}
ptrdiff_t consume_text(std::string_view text) override {
text_input.insert(text_input.end(), text.begin(), text.end());
return static_cast<ptrdiff_t>(text.size());
}
ptrdiff_t consume_binary(byte_span bytes) override {
binary_input.insert(binary_input.end(), bytes.begin(), bytes.end());
return static_cast<ptrdiff_t>(bytes.size());
}
};
struct fixture {
fixture() {
using namespace caf::net;
auto app_ptr = app_t::make();
auto app_ptr = mock_web_socket_app::make(/*behave_as_server=*/true);
app = app_ptr.get();
auto ws_ptr = net::web_socket::server::make(std::move(app_ptr));
transport = mock_stream_transport::make(std::move(ws_ptr));
......@@ -126,7 +69,7 @@ struct fixture {
std::unique_ptr<mock_stream_transport> transport;
app_t* app;
mock_web_socket_app* app;
std::minstd_rand rng;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment