More C++ Client cleanup (#7551)

This commit is contained in:
BrennanConroy 2019-02-14 08:31:15 -08:00 committed by GitHub
parent 6ea3f27dbb
commit bca85b92fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 196 additions and 223 deletions

View File

@ -41,7 +41,7 @@ namespace signalr
SIGNALRCLIENT_API pplx::task<void> __cdecl stop();
SIGNALRCLIENT_API connection_state __cdecl get_connection_state() const;
SIGNALRCLIENT_API connection_state __cdecl get_connection_state() const noexcept;
SIGNALRCLIENT_API utility::string_t __cdecl get_connection_id() const;
private:

View File

@ -43,20 +43,11 @@ namespace signalr
SIGNALRCLIENT_API void __cdecl on(const utility::string_t& event_name, const method_invoked_handler& handler);
pplx::task<web::json::value> invoke(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array())
{
return invoke_json(method_name, arguments);
}
SIGNALRCLIENT_API pplx::task<web::json::value> invoke(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array());
pplx::task<void> send(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array())
{
return invoke_void(method_name, arguments);
}
SIGNALRCLIENT_API pplx::task<void> send(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array());
private:
std::shared_ptr<hub_connection_impl> m_pImpl;
SIGNALRCLIENT_API pplx::task<web::json::value> __cdecl invoke_json(const utility::string_t& method_name, const web::json::value& arguments);
SIGNALRCLIENT_API pplx::task<void> __cdecl invoke_void(const utility::string_t& method_name, const web::json::value& arguments);
};
}

View File

@ -4,10 +4,8 @@
#pragma once
#include <stdexcept>
#include "cpprest/details/basic_types.h"
#include "cpprest/json.h"
#include "cpprest/asyncrt_utils.h"
#include "signalr_exception.h"
#include "cpprest/details/basic_types.h"
namespace signalr
{

View File

@ -22,10 +22,10 @@ namespace signalr
SIGNALRCLIENT_API web::http::client::http_client_config __cdecl get_http_client_config() const;
SIGNALRCLIENT_API void __cdecl set_http_client_config(const web::http::client::http_client_config& http_client_config);
SIGNALRCLIENT_API web::websockets::client::websocket_client_config __cdecl get_websocket_client_config() const;
SIGNALRCLIENT_API web::websockets::client::websocket_client_config __cdecl get_websocket_client_config() const noexcept;
SIGNALRCLIENT_API void __cdecl set_websocket_client_config(const web::websockets::client::websocket_client_config& websocket_client_config);
SIGNALRCLIENT_API web::http::http_headers __cdecl get_http_headers() const;
SIGNALRCLIENT_API web::http::http_headers __cdecl get_http_headers() const noexcept;
SIGNALRCLIENT_API void __cdecl set_http_headers(const web::http::http_headers& http_headers);
private:
@ -33,4 +33,4 @@ namespace signalr
web::websockets::client::websocket_client_config m_websocket_client_config;
web::http::http_headers m_http_headers;
};
}
}

View File

@ -16,13 +16,13 @@ namespace signalr
all = messages | events | state_changes | errors | info
};
inline trace_level operator|(trace_level lhs, trace_level rhs)
inline trace_level operator|(trace_level lhs, trace_level rhs) noexcept
{
return static_cast<trace_level>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
inline trace_level operator&(trace_level lhs, trace_level rhs)
inline trace_level operator&(trace_level lhs, trace_level rhs) noexcept
{
return static_cast<trace_level>(static_cast<int>(lhs) & static_cast<int>(rhs));
}
}
}

View File

@ -16,7 +16,7 @@ namespace signalr
: runtime_error(utility::conversions::to_utf8string(what)), m_status_code(status_code)
{}
unsigned short status_code() const
unsigned short status_code() const noexcept
{
return m_status_code;
}
@ -24,4 +24,4 @@ namespace signalr
private:
unsigned short m_status_code;
};
}
}

View File

@ -168,7 +168,4 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@ -83,7 +83,7 @@ namespace signalr
utility::string_t callback_manager::get_callback_id()
{
auto callback_id = m_id++;
const auto callback_id = m_id++;
utility::stringstream_t ss;
ss << callback_id;
return ss.str();

View File

@ -35,7 +35,7 @@ namespace signalr
struct case_insensitive_hash : std::unary_function<utility::string_t, std::size_t>
{
std::size_t operator()(const utility::string_t& s) const
std::size_t operator()(const utility::string_t& s) const noexcept
{
size_t hash = 0;
std::hash<size_t> hasher;
@ -47,4 +47,4 @@ namespace signalr
return hash;
}
};
}
}

View File

@ -46,7 +46,7 @@ namespace signalr
return m_pImpl->stop();
}
connection_state connection::get_connection_state() const
connection_state connection::get_connection_state() const noexcept
{
return m_pImpl->get_connection_state();
}

View File

@ -4,7 +4,6 @@
#include "stdafx.h"
#include <thread>
#include <algorithm>
#include "cpprest/asyncrt_utils.h"
#include "constants.h"
#include "connection_impl.h"
#include "request_sender.h"
@ -39,7 +38,7 @@ namespace signalr
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory)
: m_base_url(url), m_query_string(query_string), m_connection_state(connection_state::disconnected), m_logger(log_writer, trace_level),
m_transport(nullptr), m_web_request_factory(std::move(web_request_factory)), m_transport_factory(std::move(transport_factory)),
m_message_received([](const utility::string_t&){}), m_disconnected([](){})
m_message_received([](const utility::string_t&) noexcept {}), m_disconnected([]() noexcept {})
{ }
connection_impl::~connection_impl()
@ -87,28 +86,49 @@ namespace signalr
pplx::task_completion_event<void> start_tce;
auto connection = shared_from_this();
auto weak_connection = weak_from_this();
pplx::task_from_result()
.then([connection]()
.then([weak_connection]()
{
auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<negotiation_response>(_XPLATSTR("connection no longer exists"));
}
return request_sender::negotiate(*connection->m_web_request_factory, connection->m_base_url,
connection->m_query_string, connection->m_signalr_client_config);
}, m_disconnect_cts.get_token())
.then([connection](negotiation_response negotiation_response)
.then([weak_connection](negotiation_response negotiation_response)
{
connection->m_connection_id = negotiation_response.connection_id;
auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
}
connection->m_connection_id = std::move(negotiation_response.connection_id);
// TODO: check available transports
return connection->start_transport(negotiation_response)
.then([connection, negotiation_response](std::shared_ptr<transport> transport)
return connection->start_transport()
.then([weak_connection](std::shared_ptr<transport> transport)
{
auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
}
connection->m_transport = transport;
return pplx::task_from_result();
});
}, m_disconnect_cts.get_token())
.then([start_tce, connection](pplx::task<void> previous_task)
.then([start_tce, weak_connection](pplx::task<void> previous_task)
{
auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
}
try
{
previous_task.get();
@ -144,20 +164,22 @@ namespace signalr
connection->m_start_completed_event.set();
start_tce.set_exception(std::current_exception());
}
return pplx::task_from_result();
});
return pplx::create_task(start_tce);
}
pplx::task<std::shared_ptr<transport>> connection_impl::start_transport(negotiation_response negotiation_response)
pplx::task<std::shared_ptr<transport>> connection_impl::start_transport()
{
auto connection = shared_from_this();
pplx::task_completion_event<void> connect_request_tce;
auto weak_connection = std::weak_ptr<connection_impl>(connection);
auto& disconnect_cts = m_disconnect_cts;
auto& logger = m_logger;
const auto& disconnect_cts = m_disconnect_cts;
const auto& logger = m_logger;
auto process_response_callback =
[weak_connection, disconnect_cts, logger](const utility::string_t& response) mutable
@ -169,7 +191,7 @@ namespace signalr
if (disconnect_cts.get_token().is_canceled())
{
logger.log(trace_level::info,
utility::string_t(_XPLATSTR("ignoring stray message received after connection was restarted. message: "))
utility::string_t{ _XPLATSTR("ignoring stray message received after connection was restarted. message: " })
.append(response));
return;
}
@ -192,7 +214,7 @@ namespace signalr
if (disconnect_cts.get_token().is_canceled())
{
logger.log(trace_level::info,
utility::string_t(_XPLATSTR("ignoring stray error received after connection was restarted. error: "))
utility::string_t{ _XPLATSTR("ignoring stray error received after connection was restarted. error: " })
.append(utility::conversions::to_string_t(e.what())));
return;
@ -206,7 +228,7 @@ namespace signalr
transport_type::websockets, connection->m_logger, connection->m_signalr_client_config,
process_response_callback, error_callback);
pplx::create_task([negotiation_response, connect_request_tce, disconnect_cts, weak_connection]()
pplx::create_task([connect_request_tce, disconnect_cts, weak_connection]()
{
// TODO? std::this_thread::sleep_for(std::chrono::milliseconds(negotiation_response.transport_connect_timeout));
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
@ -290,11 +312,11 @@ namespace signalr
// we won't crash.
auto transport = m_transport;
auto connection_state = get_connection_state();
const auto connection_state = get_connection_state();
if (connection_state != signalr::connection_state::connected || !transport)
{
return pplx::task_from_exception<void>(signalr_exception(
utility::string_t{_XPLATSTR("cannot send data when the connection is not in the connected state. current connection state: " })
utility::string_t(_XPLATSTR("cannot send data when the connection is not in the connected state. current connection state: "))
.append(translate_connection_state(connection_state))));
}
@ -368,7 +390,7 @@ namespace signalr
std::lock_guard<std::mutex> lock(m_stop_lock);
m_logger.log(trace_level::info, _XPLATSTR("acquired lock in shutdown()"));
auto current_state = get_connection_state();
const auto current_state = get_connection_state();
if (current_state == connection_state::disconnected)
{
return pplx::task_from_result();
@ -381,7 +403,7 @@ namespace signalr
// affect the other invocation which is using it.
auto cts = pplx::cancellation_token_source();
cts.cancel();
return pplx::create_task([](){}, cts.get_token());
return pplx::create_task([]() noexcept {}, cts.get_token());
}
// we request a cancellation of the ongoing start (if any) and wait until it is canceled
@ -408,7 +430,7 @@ namespace signalr
return m_transport->disconnect();
}
connection_state connection_impl::get_connection_state() const
connection_state connection_impl::get_connection_state() const noexcept
{
return m_connection_state.load();
}
@ -429,13 +451,6 @@ namespace signalr
m_message_received = message_received;
}
void connection_impl::set_connection_data(const utility::string_t& connection_data)
{
_ASSERTE(get_connection_state() == connection_state::disconnected);
m_connection_data = connection_data;
}
void connection_impl::set_client_config(const signalr_client_config& config)
{
ensure_disconnected(_XPLATSTR("cannot set client config when the connection is not in the disconnected state. "));
@ -450,7 +465,7 @@ namespace signalr
void connection_impl::ensure_disconnected(const utility::string_t& error_message)
{
auto state = get_connection_state();
const auto state = get_connection_state();
if (state != connection_state::disconnected)
{
throw signalr_exception(

View File

@ -41,15 +41,13 @@ namespace signalr
pplx::task<void> send(const utility::string_t &data);
pplx::task<void> stop();
connection_state get_connection_state() const;
connection_state get_connection_state() const noexcept;
utility::string_t get_connection_id() const;
void set_message_received(const std::function<void(const utility::string_t&)>& message_received);
void set_disconnected(const std::function<void()>& disconnected);
void set_client_config(const signalr_client_config& config);
void set_connection_data(const utility::string_t& connection_data);
private:
web::uri m_base_url;
utility::string_t m_query_string;
@ -74,7 +72,7 @@ namespace signalr
connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr<log_writer>& log_writer,
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory);
pplx::task<std::shared_ptr<transport>> start_transport(negotiation_response negotiation_response);
pplx::task<std::shared_ptr<transport>> start_transport();
pplx::task<void> send_connect_request(const std::shared_ptr<transport>& transport,
const pplx::task_completion_event<void>& connect_request_tce);

View File

@ -8,7 +8,7 @@ namespace signalr
{
namespace
{
static web::websockets::client::websocket_client_config create_client_config(const signalr_client_config& signalr_client_config)
static web::websockets::client::websocket_client_config create_client_config(const signalr_client_config& signalr_client_config) noexcept
{
auto websocket_client_config = signalr_client_config.get_websocket_client_config();
websocket_client_config.headers() = signalr_client_config.get_http_headers();
@ -17,7 +17,7 @@ namespace signalr
}
}
default_websocket_client::default_websocket_client(const signalr_client_config& signalr_client_config)
default_websocket_client::default_websocket_client(const signalr_client_config& signalr_client_config) noexcept
: m_underlying_client(create_client_config(signalr_client_config))
{ }
@ -47,4 +47,4 @@ namespace signalr
{
return m_underlying_client.close();
}
}
}

View File

@ -12,7 +12,7 @@ namespace signalr
class default_websocket_client : public websocket_client
{
public:
explicit default_websocket_client(const signalr_client_config& signalr_client_config = signalr_client_config{});
explicit default_websocket_client(const signalr_client_config& signalr_client_config = signalr_client_config{}) noexcept;
pplx::task<void> connect(const web::uri &url) override;
@ -25,4 +25,4 @@ namespace signalr
private:
web::websockets::client::websocket_client m_underlying_client;
};
}
}

View File

@ -19,7 +19,7 @@ namespace signalr
static const unsigned int timeout_infinite = 0xFFFFFFFF;
event()
event() noexcept
: m_signaled(false)
{
}
@ -42,13 +42,13 @@ namespace signalr
std::unique_lock<std::mutex> lock(m_lock);
if (timeout == event::timeout_infinite)
{
m_condition.wait(lock, [this]() { return m_signaled; });
m_condition.wait(lock, [this]() noexcept { return m_signaled; });
return 0;
}
else
{
std::chrono::milliseconds period(timeout);
auto status = m_condition.wait_for(lock, period, [this]() { return m_signaled; });
const std::chrono::milliseconds period(timeout);
const auto status = m_condition.wait_for(lock, period, [this]() noexcept { return m_signaled; });
assert(status == m_signaled);
// Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite
return status ? 0 : event::timeout_infinite;

View File

@ -37,24 +37,24 @@ namespace signalr
return m_pImpl->on(event_name, handler);
}
pplx::task<web::json::value> hub_connection::invoke_json(const utility::string_t& method_name, const web::json::value& arguments)
pplx::task<web::json::value> hub_connection::invoke(const utility::string_t& method_name, const web::json::value& arguments)
{
if (!m_pImpl)
{
throw signalr_exception(_XPLATSTR("invoke() cannot be called on uninitialized hub_connection instance"));
}
return m_pImpl->invoke_json(method_name, arguments);
return m_pImpl->invoke(method_name, arguments);
}
pplx::task<void> hub_connection::invoke_void(const utility::string_t& method_name, const web::json::value& arguments)
pplx::task<void> hub_connection::send(const utility::string_t& method_name, const web::json::value& arguments)
{
if (!m_pImpl)
{
throw signalr_exception(_XPLATSTR("invoke() cannot be called on uninitialized hub_connection instance"));
throw signalr_exception(_XPLATSTR("send() cannot be called on uninitialized hub_connection instance"));
}
return m_pImpl->invoke_void(method_name, arguments);
return m_pImpl->send(method_name, arguments);
}
connection_state hub_connection::get_connection_state() const

View File

@ -45,7 +45,7 @@ namespace signalr
: m_connection(connection_impl::create(url, query_string, trace_level, log_writer,
std::move(web_request_factory), std::move(transport_factory))),m_logger(log_writer, trace_level),
m_callback_manager(json::value::parse(_XPLATSTR("{ \"error\" : \"connection went out of scope before invocation result was received\"}"))),
m_disconnected([]() {})
m_disconnected([]() noexcept {}), m_handshakeReceived(false)
{ }
void hub_connection_impl::initialize()
@ -108,9 +108,9 @@ namespace signalr
m_handshakeTask = pplx::task_completion_event<void>();
m_handshakeReceived = false;
auto weak_connection = m_connection->weak_from_this();
auto weak_connection = weak_from_this();
return m_connection->start()
.then([weak_connection, this](pplx::task<void> startTask)
.then([weak_connection](pplx::task<void> startTask)
{
startTask.get();
auto connection = weak_connection.lock();
@ -119,11 +119,17 @@ namespace signalr
// The connection has been destructed
return pplx::task_from_exception<void>(signalr_exception(_XPLATSTR("the hub connection has been deconstructed")));
}
return connection->send(_XPLATSTR("{\"protocol\":\"json\",\"version\":1}\x1e"))
.then([this](pplx::task<void> previous_task)
return connection->m_connection->send(_XPLATSTR("{\"protocol\":\"json\",\"version\":1}\x1e"))
.then([weak_connection](pplx::task<void> previous_task)
{
auto connection = weak_connection.lock();
if (!connection)
{
// The connection has been destructed
return pplx::task_from_exception<void>(signalr_exception(_XPLATSTR("the hub connection has been deconstructed")));
}
previous_task.get();
return pplx::task<void>(m_handshakeTask);
return pplx::task<void>(connection->m_handshakeTask);
})
.then([weak_connection](pplx::task<void> previous_task)
{
@ -137,7 +143,7 @@ namespace signalr
auto connection = weak_connection.lock();
if (connection)
{
connection->stop();
connection->m_connection->stop();
}
throw;
}
@ -267,7 +273,7 @@ namespace signalr
return true;
}
pplx::task<json::value> hub_connection_impl::invoke_json(const utility::string_t& method_name, const json::value& arguments)
pplx::task<json::value> hub_connection_impl::invoke(const utility::string_t& method_name, const json::value& arguments)
{
_ASSERTE(arguments.is_array());
@ -283,7 +289,7 @@ namespace signalr
return pplx::create_task(tce);
}
pplx::task<void> hub_connection_impl::invoke_void(const utility::string_t& method_name, const json::value& arguments)
pplx::task<void> hub_connection_impl::send(const utility::string_t& method_name, const json::value& arguments)
{
_ASSERTE(arguments.is_array());
@ -337,7 +343,7 @@ namespace signalr
});
}
connection_state hub_connection_impl::get_connection_state() const
connection_state hub_connection_impl::get_connection_state() const noexcept
{
return m_connection->get_connection_state();
}

View File

@ -33,13 +33,13 @@ namespace signalr
void on(const utility::string_t& event_name, const std::function<void(const json::value &)>& handler);
pplx::task<json::value> invoke_json(const utility::string_t& method_name, const json::value& arguments);
pplx::task<void> invoke_void(const utility::string_t& method_name, const json::value& arguments);
pplx::task<json::value> invoke(const utility::string_t& method_name, const json::value& arguments);
pplx::task<void> send(const utility::string_t& method_name, const json::value& arguments);
pplx::task<void> start();
pplx::task<void> stop();
connection_state get_connection_state() const;
connection_state get_connection_state() const noexcept;
utility::string_t get_connection_id() const;
void set_client_config(const signalr_client_config& config);

View File

@ -8,11 +8,11 @@
namespace signalr
{
logger::logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level)
logger::logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level) noexcept
: m_log_writer(log_writer), m_trace_level(trace_level)
{ }
void logger::log(trace_level level, const utility::string_t& entry)
void logger::log(trace_level level, const utility::string_t& entry) const
{
if ((level & m_trace_level) != trace_level::none)
{
@ -54,4 +54,4 @@ namespace signalr
return _XPLATSTR("(unknown)");
}
}
}
}

View File

@ -12,9 +12,9 @@ namespace signalr
class logger
{
public:
logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level);
logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level) noexcept;
void log(trace_level level, const utility::string_t& entry);
void log(trace_level level, const utility::string_t& entry) const;
private:
std::shared_ptr<log_writer> m_log_writer;
@ -22,4 +22,4 @@ namespace signalr
static utility::string_t translate_trace_level(trace_level trace_level);
};
}
}

View File

@ -26,8 +26,8 @@ namespace signalr
negotiation_response_json[_XPLATSTR("availableTransports")],
};
return response;
return std::move(response);
});
}
}
}
}

View File

@ -30,7 +30,7 @@ namespace signalr
m_http_client_config = http_client_config;
}
web::websockets::client::websocket_client_config signalr_client_config::get_websocket_client_config() const
web::websockets::client::websocket_client_config signalr_client_config::get_websocket_client_config() const noexcept
{
return m_websocket_client_config;
}
@ -40,7 +40,7 @@ namespace signalr
m_websocket_client_config = websocket_client_config;
}
web::http::http_headers signalr_client_config::get_http_headers() const
web::http::http_headers signalr_client_config::get_http_headers() const noexcept
{
return m_http_headers;
}
@ -49,4 +49,4 @@ namespace signalr
{
m_http_headers = http_headers;
}
}
}

View File

@ -15,8 +15,8 @@ namespace signalr
_ASSERTE(transport == transport_type::websockets || transport == transport_type::long_polling);
return transport == transport_type::websockets
? _XPLATSTR("webSockets")
: _XPLATSTR("longPolling");
? utility::string_t(_XPLATSTR("webSockets"))
: utility::string_t(_XPLATSTR("longPolling"));
}
void append_transport(web::uri_builder &builder, transport_type transport)

View File

@ -36,7 +36,7 @@ namespace signalr
{}
}
transport_type websocket_transport::get_transport_type() const
transport_type websocket_transport::get_transport_type() const noexcept
{
return transport_type::websockets;
}
@ -236,10 +236,10 @@ namespace signalr
std::shared_ptr<websocket_client> websocket_transport::safe_get_websocket_client()
{
{
std::lock_guard<std::mutex> lock(m_websocket_client_lock);
const std::lock_guard<std::mutex> lock(m_websocket_client_lock);
auto websocket_client = m_websocket_client;
return websocket_client;
}
}
}
}

View File

@ -31,7 +31,7 @@ namespace signalr
pplx::task<void> disconnect() override;
transport_type get_transport_type() const override;
transport_type get_transport_type() const noexcept override;
private:
websocket_transport(const std::function<std::shared_ptr<websocket_client>()>& websocket_client_factory,
@ -52,4 +52,4 @@ namespace signalr
std::shared_ptr<websocket_client> safe_get_websocket_client();
};
}
}

View File

@ -170,7 +170,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@ -64,7 +64,7 @@ TEST(connection_impl_start, connection_state_is_connecting_when_connection_is_be
auto connection = create_connection(websocket_client, writer, trace_level::errors);
connection->start()
auto startTask = connection->start()
// this test is not set up to connect successfully so we have to observe exceptions otherwise
// other tests may fail due to an unobserved exception from the outstanding start task
.then([](pplx::task<void> start_task)
@ -78,6 +78,7 @@ TEST(connection_impl_start, connection_state_is_connecting_when_connection_is_be
});
ASSERT_EQ(connection->get_connection_state(), connection_state::connecting);
startTask.get();
}
TEST(connection_impl_start, connection_state_is_connected_when_connection_established_succesfully)

View File

@ -223,7 +223,7 @@ TEST(stop, stop_cancels_pending_callbacks)
auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get();
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array());
auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
hub_connection->stop();
try
@ -262,7 +262,7 @@ TEST(stop, pending_callbacks_finished_if_hub_connections_goes_out_of_scope)
{
auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get();
t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array());
t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
}
try
@ -309,7 +309,7 @@ TEST(hub_invocation, hub_connection_invokes_users_code_on_hub_invocations)
ASSERT_EQ(_XPLATSTR("[\"message\",1]"), *payload);
}
TEST(invoke, invoke_creates_correct_payload)
TEST(send, creates_correct_payload)
{
utility::string_t payload;
bool handshakeReceived = false;
@ -321,7 +321,7 @@ TEST(invoke, invoke_creates_correct_payload)
if (handshakeReceived)
{
payload = m;
return pplx::task_from_exception<void>(std::runtime_error("error"));
return pplx::task_from_result();
}
handshakeReceived = true;
return pplx::task_from_result();
@ -330,16 +330,74 @@ TEST(invoke, invoke_creates_correct_payload)
auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get();
hub_connection->send(_XPLATSTR("method"), json::value::array()).get();
ASSERT_EQ(_XPLATSTR("{\"arguments\":[],\"target\":\"method\",\"type\":1}\x1e"), payload);
}
TEST(send, does_not_wait_for_server_response)
{
int call_number = -1;
pplx::task_completion_event<void> waitForSend;
auto websocket_client = create_test_websocket_client(
/* receive function */ [waitForSend, call_number]() mutable
{
std::string responses[]
{
"{ }\x1e",
"{}"
};
call_number = std::min(call_number + 1, 1);
if (call_number == 1)
{
pplx::task<void>(waitForSend).get();
}
return pplx::task_from_result(responses[call_number]);
});
auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get();
// wont block waiting for server response
hub_connection->send(_XPLATSTR("method"), json::value::array()).get();
waitForSend.set();
}
TEST(invoke, creates_correct_payload)
{
utility::string_t payload;
bool handshakeReceived = false;
auto websocket_client = create_test_websocket_client(
/* receive function */ []() { return pplx::task_from_result(std::string("{ }\x1e")); },
/* send function */[&payload, &handshakeReceived](const utility::string_t& m)
{
if (handshakeReceived)
{
payload = m;
return pplx::task_from_exception<void>(std::runtime_error("error"));
}
handshakeReceived = true;
return pplx::task_from_result();
});
auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get();
try
{
hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()).get();
hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
}
catch (...)
{
// the send is not setup to succeed because it's not needed in this test
// the invoke is not setup to succeed because it's not needed in this test
}
ASSERT_EQ(_XPLATSTR("{\"arguments\":[],\"target\":\"method\",\"type\":1}\x1e"), payload);
ASSERT_EQ(_XPLATSTR("{\"arguments\":[],\"invocationId\":\"0\",\"target\":\"method\",\"type\":1}\x1e"), payload);
}
TEST(invoke, callback_not_called_if_send_throws)
@ -362,7 +420,7 @@ TEST(invoke, callback_not_called_if_send_throws)
try
{
hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()).get();
hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
ASSERT_TRUE(false); // exception expected but not thrown
}
catch (const std::runtime_error& e)
@ -376,7 +434,7 @@ TEST(invoke, callback_not_called_if_send_throws)
hub_connection->stop().get();
}
TEST(invoke_json, invoke_returns_value_returned_from_the_server)
TEST(invoke, invoke_returns_value_returned_from_the_server)
{
auto callback_registered_event = std::make_shared<event>();
@ -404,7 +462,7 @@ TEST(invoke_json, invoke_returns_value_returned_from_the_server)
auto result = hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array());
auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
@ -412,7 +470,7 @@ TEST(invoke_json, invoke_returns_value_returned_from_the_server)
ASSERT_EQ(_XPLATSTR("\"abc\""), result.serialize());
}
TEST(invoke_json, invoke_propagates_errors_from_server_as_exceptions)
TEST(invoke, invoke_propagates_hub_errors_from_server_as_hub_exceptions)
{
auto callback_registered_event = std::make_shared<event>();
@ -442,50 +500,7 @@ TEST(invoke_json, invoke_propagates_errors_from_server_as_exceptions)
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
ASSERT_TRUE(false); // exception expected but not thrown
}
catch (const std::runtime_error& e)
{
ASSERT_STREQ("\"Ooops\"", e.what());
}
}
TEST(invoke_json, invoke_propagates_hub_errors_from_server_as_hub_exceptions)
{
auto callback_registered_event = std::make_shared<event>();
int call_number = -1;
auto websocket_client = create_test_websocket_client(
/* receive function */ [call_number, callback_registered_event]()
mutable {
std::string responses[]
{
"{ }\x1e",
"{ \"type\": 3, \"invocationId\": \"0\", \"error\": \"Ooops\" }\x1e"
};
call_number = std::min(call_number + 1, 1);
if (call_number > 0)
{
callback_registered_event->wait();
}
return pplx::task_from_result(responses[call_number]);
});
auto hub_connection = create_hub_connection(websocket_client);
try
{
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array());
auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
@ -498,7 +513,7 @@ TEST(invoke_json, invoke_propagates_hub_errors_from_server_as_hub_exceptions)
}
}
TEST(invoke_void, invoke_unblocks_task_when_server_completes_call)
TEST(invoke, unblocks_task_when_server_completes_call)
{
auto callback_registered_event = std::make_shared<event>();
@ -509,7 +524,7 @@ TEST(invoke_void, invoke_unblocks_task_when_server_completes_call)
std::string responses[]
{
"{ }\x1e",
"{\"I\":\"0\"}\x1e"
"{ \"type\": 3, \"invocationId\": \"0\" }\x1e"
};
call_number = std::min(call_number + 1, 1);
@ -526,7 +541,7 @@ TEST(invoke_void, invoke_unblocks_task_when_server_completes_call)
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array());
auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
@ -535,7 +550,7 @@ TEST(invoke_void, invoke_unblocks_task_when_server_completes_call)
ASSERT_TRUE(true);
}
TEST(invoke_void, invoke_logs_if_callback_for_given_id_not_found)
TEST(receive, logs_if_callback_for_given_id_not_found)
{
auto message_received_event = std::make_shared<event>();
auto handshake_sent = std::make_shared<event>();
@ -547,7 +562,7 @@ TEST(invoke_void, invoke_logs_if_callback_for_given_id_not_found)
std::string responses[]
{
"{ }\x1e",
"{ \"type\": 3, \"invocationId\": \"0\", \"error\": \"Ooops\" }\x1e"
"{ \"type\": 3, \"invocationId\": \"0\" }\x1e"
"{}"
};
@ -582,7 +597,7 @@ TEST(invoke_void, invoke_logs_if_callback_for_given_id_not_found)
}
// TODO Flaky until hub_connection.start waits for handshake response
TEST(invoke_void, DISABLED_invoke_propagates_errors_from_server_as_exceptions)
TEST(invoke, DISABLED_invoke_propagates_errors_from_server_as_exceptions)
{
auto callback_registered_event = std::make_shared<event>();
@ -613,7 +628,7 @@ TEST(invoke_void, DISABLED_invoke_propagates_errors_from_server_as_exceptions)
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array());
auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
@ -626,51 +641,6 @@ TEST(invoke_void, DISABLED_invoke_propagates_errors_from_server_as_exceptions)
}
}
// TODO Flaky until hub_connection.start waits for handshake response
TEST(invoke_void, DISABLED_invoke_propagates_hub_errors_from_server_as_hub_exceptions)
{
auto callback_registered_event = std::make_shared<event>();
int call_number = -1;
auto websocket_client = create_test_websocket_client(
/* receive function */ [call_number, callback_registered_event]()
mutable {
std::string responses[]
{
"{ }\x1e",
"{ \"type\": 3, \"invocationId\": \"0\", \"error\": \"Ooops\" }\x1e"
"{}"
};
call_number = std::min(call_number + 1, 2);
if (call_number > 0)
{
callback_registered_event->wait();
}
return pplx::task_from_result(responses[call_number]);
});
auto hub_connection = create_hub_connection(websocket_client);
try
{
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
ASSERT_TRUE(false); // exception expected but not thrown
}
catch (const hub_exception& e)
{
ASSERT_STREQ("\"Ooops\"", e.what());
}
}
// TODO Flaky until hub_connection.start waits for handshake response
TEST(invoke_void, DISABLED_invoke_creates_runtime_error)
{
@ -702,7 +672,7 @@ TEST(invoke_void, DISABLED_invoke_creates_runtime_error)
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array());
auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
@ -783,13 +753,13 @@ TEST(on, cannot_register_handler_if_connection_not_in_disconnected_state)
}
}
TEST(invoke_json, invoke_throws_when_the_underlying_connection_is_not_valid)
TEST(invoke, invoke_throws_when_the_underlying_connection_is_not_valid)
{
auto hub_connection = create_hub_connection();
try
{
hub_connection->invoke_json(_XPLATSTR("method"), json::value::array()).get();
hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
ASSERT_TRUE(true); // exception expected but not thrown
}
catch (const signalr_exception& e)
@ -798,13 +768,13 @@ TEST(invoke_json, invoke_throws_when_the_underlying_connection_is_not_valid)
}
}
TEST(invoke_void, send_throws_when_the_underlying_connection_is_not_valid)
TEST(invoke, send_throws_when_the_underlying_connection_is_not_valid)
{
auto hub_connection = create_hub_connection();
try
{
hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()).get();
hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
ASSERT_TRUE(true); // exception expected but not thrown
}
catch (const signalr_exception& e)