Add negotiation response support (#7675)
This commit is contained in:
parent
6fea3a6e95
commit
e455c2c22b
|
|
@ -21,8 +21,7 @@ namespace signalr
|
|||
public:
|
||||
typedef std::function<void __cdecl(const utility::string_t&)> message_received_handler;
|
||||
|
||||
SIGNALRCLIENT_API explicit connection(const utility::string_t& url, const utility::string_t& query_string = _XPLATSTR(""),
|
||||
trace_level trace_level = trace_level::all, std::shared_ptr<log_writer> log_writer = nullptr);
|
||||
SIGNALRCLIENT_API explicit connection(const utility::string_t& url, trace_level trace_level = trace_level::all, std::shared_ptr<log_writer> log_writer = nullptr);
|
||||
|
||||
SIGNALRCLIENT_API ~connection();
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ namespace signalr
|
|||
public:
|
||||
typedef std::function<void __cdecl (const web::json::value&)> method_invoked_handler;
|
||||
|
||||
SIGNALRCLIENT_API explicit hub_connection(const utility::string_t& url, const utility::string_t& query_string = _XPLATSTR(""),
|
||||
trace_level trace_level = trace_level::all, std::shared_ptr<log_writer> log_writer = nullptr);
|
||||
SIGNALRCLIENT_API explicit hub_connection(const utility::string_t& url, trace_level trace_level = trace_level::all,
|
||||
std::shared_ptr<log_writer> log_writer = nullptr);
|
||||
|
||||
SIGNALRCLIENT_API ~hub_connection();
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ void send_message(signalr::hub_connection& connection, const utility::string_t&
|
|||
|
||||
void chat(const utility::string_t& name)
|
||||
{
|
||||
signalr::hub_connection connection(U("http://localhost:5000/default"), U(""), signalr::trace_level::all, std::make_shared<logger>());
|
||||
signalr::hub_connection connection(U("http://localhost:5000/default"), signalr::trace_level::all, std::make_shared<logger>());
|
||||
connection.on(U("Send"), [](const web::json::value& m)
|
||||
{
|
||||
ucout << std::endl << m.at(0).as_string() << /*U(" wrote:") << m.at(1).as_string() <<*/ std::endl << U("Enter your message: ");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\Build\SignalRClient.Build.Settings" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
|
|
@ -36,7 +36,6 @@
|
|||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<Import Project="..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
|
|
@ -110,10 +109,10 @@
|
|||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
|
||||
<Error Condition="!Exists('..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.2.9.1\build\native\cpprestsdk.v140.windesktop.msvcstl.dyn.rt-dyn.targets'))" />
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
<Exec Command="copy /y "$(SolutionDir)bin\Desktop\$(Platform)\$(Configuration)\dll\$(SignalrClientTargetName).dll" "$(SolutionDir)$(Configuration)\$(SignalrClientTargetName).dll"" />
|
||||
<Exec Command="copy /y "$(SolutionDir)bin\Desktop\$(Platform)\$(Configuration)\dll\$(SignalrClientTargetName).dll" "$(SolutionDir)bin\Desktop\$(Platform)\$(Configuration)\$(SignalrClientTargetName).dll"" />
|
||||
<Exec Command="copy /y "$(SolutionDir)bin\Desktop\$(Platform)\$(Configuration)\dll\$(SignalrClientTargetName).pdb" "$(SolutionDir)bin\Desktop\$(Platform)\$(Configuration)\$(SignalrClientTargetName).pdb"" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace signalr
|
||||
{
|
||||
connection::connection(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, std::shared_ptr<log_writer> log_writer)
|
||||
: m_pImpl(connection_impl::create(url, query_string, trace_level, std::move(log_writer)))
|
||||
connection::connection(const utility::string_t& url, trace_level trace_level, std::shared_ptr<log_writer> log_writer)
|
||||
: m_pImpl(connection_impl::create(url, trace_level, std::move(log_writer)))
|
||||
{}
|
||||
|
||||
// Do NOT remove this destructor. Letting the compiler generate and inline the default dtor may lead to
|
||||
|
|
|
|||
|
|
@ -21,22 +21,21 @@ namespace signalr
|
|||
static void log(const logger& logger, trace_level level, const utility::string_t& entry);
|
||||
}
|
||||
|
||||
std::shared_ptr<connection_impl> connection_impl::create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer)
|
||||
std::shared_ptr<connection_impl> connection_impl::create(const utility::string_t& url, trace_level trace_level, const std::shared_ptr<log_writer>& log_writer)
|
||||
{
|
||||
return connection_impl::create(url, query_string, trace_level, log_writer, std::make_unique<web_request_factory>(), std::make_unique<transport_factory>());
|
||||
return connection_impl::create(url, trace_level, log_writer, std::make_unique<web_request_factory>(), std::make_unique<transport_factory>());
|
||||
}
|
||||
|
||||
std::shared_ptr<connection_impl> connection_impl::create(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)
|
||||
std::shared_ptr<connection_impl> connection_impl::create(const utility::string_t& url, 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)
|
||||
{
|
||||
return std::shared_ptr<connection_impl>(new connection_impl(url, query_string, trace_level,
|
||||
return std::shared_ptr<connection_impl>(new connection_impl(url, trace_level,
|
||||
log_writer ? log_writer : std::make_shared<trace_log_writer>(), std::move(web_request_factory), std::move(transport_factory)));
|
||||
}
|
||||
|
||||
connection_impl::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,
|
||||
connection_impl::connection_impl(const utility::string_t& url, 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)
|
||||
: m_base_url(url), m_query_string(query_string), m_connection_state(connection_state::disconnected), m_logger(log_writer, trace_level),
|
||||
: m_base_url(url), 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&) noexcept {}), m_disconnected([]() noexcept {})
|
||||
{ }
|
||||
|
|
@ -84,94 +83,138 @@ namespace signalr
|
|||
m_message_id = m_groups_token = m_connection_id = _XPLATSTR("");
|
||||
}
|
||||
|
||||
return start_negotiate(m_base_url, 0);
|
||||
}
|
||||
|
||||
pplx::task<void> connection_impl::start_negotiate(const web::uri& url, int redirect_count)
|
||||
{
|
||||
if (redirect_count >= MAX_NEGOTIATE_REDIRECTS)
|
||||
{
|
||||
return pplx::task_from_exception<void>(signalr_exception(_XPLATSTR("Negotiate redirection limit exceeded.")));
|
||||
}
|
||||
|
||||
pplx::task_completion_event<void> start_tce;
|
||||
|
||||
auto weak_connection = weak_from_this();
|
||||
|
||||
pplx::task_from_result()
|
||||
.then([weak_connection]()
|
||||
.then([weak_connection, url]()
|
||||
{
|
||||
auto connection = weak_connection.lock();
|
||||
if (!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, url, connection->m_signalr_client_config);
|
||||
}, m_disconnect_cts.get_token())
|
||||
.then([weak_connection, start_tce, redirect_count, url](negotiation_response negotiation_response)
|
||||
{
|
||||
auto connection = weak_connection.lock();
|
||||
if (!connection)
|
||||
{
|
||||
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
|
||||
}
|
||||
|
||||
if (!negotiation_response.error.empty())
|
||||
{
|
||||
return pplx::task_from_exception<void>(signalr_exception(negotiation_response.error));
|
||||
}
|
||||
|
||||
if (!negotiation_response.url.empty())
|
||||
{
|
||||
if (!negotiation_response.accessToken.empty())
|
||||
{
|
||||
return pplx::task_from_exception<negotiation_response>(_XPLATSTR("connection no longer exists"));
|
||||
auto headers = connection->m_signalr_client_config.get_http_headers();
|
||||
headers[_XPLATSTR("Authorization")] = _XPLATSTR("Bearer ") + negotiation_response.accessToken;
|
||||
connection->m_signalr_client_config.set_http_headers(headers);
|
||||
}
|
||||
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([weak_connection](negotiation_response negotiation_response)
|
||||
return connection->start_negotiate(negotiation_response.url, redirect_count + 1);
|
||||
}
|
||||
|
||||
connection->m_connection_id = std::move(negotiation_response.connectionId);
|
||||
|
||||
// TODO: fallback logic
|
||||
|
||||
bool foundWebsockets = false;
|
||||
for (auto availableTransport : negotiation_response.availableTransports)
|
||||
{
|
||||
if (availableTransport.transport == _XPLATSTR("WebSockets"))
|
||||
{
|
||||
foundWebsockets = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundWebsockets)
|
||||
{
|
||||
return pplx::task_from_exception<void>(signalr_exception(_XPLATSTR("The server does not support WebSockets which is currently the only transport supported by this client.")));
|
||||
}
|
||||
|
||||
// TODO: use transfer format
|
||||
|
||||
return connection->start_transport(url)
|
||||
.then([weak_connection, start_tce](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_connection_id = std::move(negotiation_response.connection_id);
|
||||
connection->m_transport = transport;
|
||||
|
||||
// TODO: check available transports
|
||||
|
||||
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, weak_connection](pplx::task<void> previous_task)
|
||||
{
|
||||
auto connection = weak_connection.lock();
|
||||
if (!connection)
|
||||
if (!connection->change_state(connection_state::connecting, connection_state::connected))
|
||||
{
|
||||
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
|
||||
}
|
||||
try
|
||||
{
|
||||
previous_task.get();
|
||||
if (!connection->change_state(connection_state::connecting, connection_state::connected))
|
||||
{
|
||||
connection->m_logger.log(trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("internal error - transition from an unexpected state. expected state: connecting, actual state: "))
|
||||
.append(translate_connection_state(connection->get_connection_state())));
|
||||
connection->m_logger.log(trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("internal error - transition from an unexpected state. expected state: connecting, actual state: "))
|
||||
.append(translate_connection_state(connection->get_connection_state())));
|
||||
|
||||
_ASSERTE(false);
|
||||
}
|
||||
|
||||
connection->m_start_completed_event.set();
|
||||
start_tce.set();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
auto task_canceled_exception = dynamic_cast<const pplx::task_canceled *>(&e);
|
||||
if (task_canceled_exception)
|
||||
{
|
||||
connection->m_logger.log(trace_level::info,
|
||||
_XPLATSTR("starting the connection has been canceled."));
|
||||
}
|
||||
else
|
||||
{
|
||||
connection->m_logger.log(trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("connection could not be started due to: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
|
||||
connection->m_transport = nullptr;
|
||||
connection->change_state(connection_state::disconnected);
|
||||
connection->m_start_completed_event.set();
|
||||
start_tce.set_exception(std::current_exception());
|
||||
_ASSERTE(false);
|
||||
}
|
||||
|
||||
return pplx::task_from_result();
|
||||
});
|
||||
}, m_disconnect_cts.get_token())
|
||||
.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();
|
||||
connection->m_start_completed_event.set();
|
||||
start_tce.set();
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
auto task_canceled_exception = dynamic_cast<const pplx::task_canceled*>(&e);
|
||||
if (task_canceled_exception)
|
||||
{
|
||||
connection->m_logger.log(trace_level::info,
|
||||
_XPLATSTR("starting the connection has been canceled."));
|
||||
}
|
||||
else
|
||||
{
|
||||
connection->m_logger.log(trace_level::errors,
|
||||
utility::string_t(_XPLATSTR("connection could not be started due to: "))
|
||||
.append(utility::conversions::to_string_t(e.what())));
|
||||
}
|
||||
|
||||
connection->m_transport = nullptr;
|
||||
connection->change_state(connection_state::disconnected);
|
||||
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()
|
||||
pplx::task<std::shared_ptr<transport>> connection_impl::start_transport(const web::uri& url)
|
||||
{
|
||||
auto connection = shared_from_this();
|
||||
|
||||
|
|
@ -247,18 +290,15 @@ namespace signalr
|
|||
}
|
||||
});
|
||||
|
||||
return connection->send_connect_request(transport, connect_request_tce)
|
||||
return connection->send_connect_request(transport, url, connect_request_tce)
|
||||
.then([transport](){ return pplx::task_from_result(transport); });
|
||||
}
|
||||
|
||||
pplx::task<void> connection_impl::send_connect_request(const std::shared_ptr<transport>& transport, const pplx::task_completion_event<void>& connect_request_tce)
|
||||
pplx::task<void> connection_impl::send_connect_request(const std::shared_ptr<transport>& transport, const web::uri& url, const pplx::task_completion_event<void>& connect_request_tce)
|
||||
{
|
||||
auto logger = m_logger;
|
||||
auto query_string = m_query_string;
|
||||
if (!query_string.empty())
|
||||
query_string.append(_XPLATSTR("&"));
|
||||
query_string.append(_XPLATSTR("id=")).append(m_connection_id);
|
||||
auto connect_url = url_builder::build_connect(m_base_url, transport->get_transport_type(), query_string);
|
||||
auto query_string = _XPLATSTR("id=" + m_connection_id);
|
||||
auto connect_url = url_builder::build_connect(url, transport->get_transport_type(), query_string);
|
||||
|
||||
transport->connect(connect_url)
|
||||
.then([transport, connect_request_tce, logger](pplx::task<void> connect_task)
|
||||
|
|
|
|||
|
|
@ -25,11 +25,10 @@ namespace signalr
|
|||
class connection_impl : public std::enable_shared_from_this<connection_impl>
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<connection_impl> create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer);
|
||||
static std::shared_ptr<connection_impl> create(const utility::string_t& url, trace_level trace_level, const std::shared_ptr<log_writer>& log_writer);
|
||||
|
||||
static std::shared_ptr<connection_impl> create(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);
|
||||
static std::shared_ptr<connection_impl> create(const utility::string_t& url, 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);
|
||||
|
||||
connection_impl(const connection_impl&) = delete;
|
||||
|
||||
|
|
@ -50,7 +49,6 @@ namespace signalr
|
|||
|
||||
private:
|
||||
web::uri m_base_url;
|
||||
utility::string_t m_query_string;
|
||||
std::atomic<connection_state> m_connection_state;
|
||||
logger m_logger;
|
||||
std::shared_ptr<transport> m_transport;
|
||||
|
|
@ -69,12 +67,13 @@ namespace signalr
|
|||
utility::string_t m_message_id;
|
||||
utility::string_t m_groups_token;
|
||||
|
||||
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,
|
||||
connection_impl(const utility::string_t& url, 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();
|
||||
pplx::task<std::shared_ptr<transport>> start_transport(const web::uri& url);
|
||||
pplx::task<void> send_connect_request(const std::shared_ptr<transport>& transport,
|
||||
const pplx::task_completion_event<void>& connect_request_tce);
|
||||
const web::uri& url, const pplx::task_completion_event<void>& connect_request_tce);
|
||||
pplx::task<void> start_negotiate(const web::uri& url, int redirect_count);
|
||||
|
||||
void process_response(const utility::string_t& response);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@
|
|||
#define SIGNALR_VERSION _XPLATSTR("0.1.0-alpha0")
|
||||
#define PROTOCOL _XPLATSTR("1.4")
|
||||
#define USER_AGENT _XPLATSTR("SignalR.Client.Cpp/") SIGNALR_VERSION
|
||||
#define MAX_NEGOTIATE_REDIRECTS 100
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
namespace signalr
|
||||
{
|
||||
hub_connection::hub_connection(const utility::string_t& url, const utility::string_t& query_string,
|
||||
hub_connection::hub_connection(const utility::string_t& url,
|
||||
trace_level trace_level, std::shared_ptr<log_writer> log_writer)
|
||||
: m_pImpl(hub_connection_impl::create(url, query_string, trace_level, std::move(log_writer)))
|
||||
: m_pImpl(hub_connection_impl::create(url, trace_level, std::move(log_writer)))
|
||||
{}
|
||||
|
||||
// Do NOT remove this destructor. Letting the compiler generate and inline the default dtor may lead to
|
||||
|
|
|
|||
|
|
@ -20,18 +20,18 @@ namespace signalr
|
|||
const std::function<void(const std::exception_ptr e)>& set_exception);
|
||||
}
|
||||
|
||||
std::shared_ptr<hub_connection_impl> hub_connection_impl::create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer)
|
||||
std::shared_ptr<hub_connection_impl> hub_connection_impl::create(const utility::string_t& url, trace_level trace_level,
|
||||
const std::shared_ptr<log_writer>& log_writer)
|
||||
{
|
||||
return hub_connection_impl::create(url, query_string, trace_level, log_writer,
|
||||
return hub_connection_impl::create(url, trace_level, log_writer,
|
||||
std::make_unique<web_request_factory>(), std::make_unique<transport_factory>());
|
||||
}
|
||||
|
||||
std::shared_ptr<hub_connection_impl> hub_connection_impl::create(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::shared_ptr<hub_connection_impl> hub_connection_impl::create(const utility::string_t& url, 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)
|
||||
{
|
||||
auto connection = std::shared_ptr<hub_connection_impl>(new hub_connection_impl(url, query_string, trace_level,
|
||||
auto connection = std::shared_ptr<hub_connection_impl>(new hub_connection_impl(url, trace_level,
|
||||
log_writer ? log_writer : std::make_shared<trace_log_writer>(), std::move(web_request_factory), std::move(transport_factory)));
|
||||
|
||||
connection->initialize();
|
||||
|
|
@ -39,10 +39,10 @@ namespace signalr
|
|||
return connection;
|
||||
}
|
||||
|
||||
hub_connection_impl::hub_connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level,
|
||||
hub_connection_impl::hub_connection_impl(const utility::string_t& url, 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)
|
||||
: m_connection(connection_impl::create(url, query_string, trace_level, log_writer,
|
||||
: m_connection(connection_impl::create(url, 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([]() noexcept {}), m_handshakeReceived(false)
|
||||
|
|
@ -106,6 +106,7 @@ namespace signalr
|
|||
_XPLATSTR("the connection can only be started if it is in the disconnected state"));
|
||||
}
|
||||
|
||||
m_connection->set_client_config(m_signalr_client_config);
|
||||
m_handshakeTask = pplx::task_completion_event<void>();
|
||||
m_handshakeReceived = false;
|
||||
auto weak_connection = weak_from_this();
|
||||
|
|
@ -138,14 +139,17 @@ namespace signalr
|
|||
previous_task.get();
|
||||
return previous_task;
|
||||
}
|
||||
catch (std::exception)
|
||||
catch (std::exception e)
|
||||
{
|
||||
auto connection = weak_connection.lock();
|
||||
if (connection)
|
||||
{
|
||||
connection->m_connection->stop();
|
||||
return connection->m_connection->stop()
|
||||
.then([e]() {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
throw;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -355,6 +359,7 @@ namespace signalr
|
|||
|
||||
void hub_connection_impl::set_client_config(const signalr_client_config& config)
|
||||
{
|
||||
m_signalr_client_config = config;
|
||||
m_connection->set_client_config(config);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ namespace signalr
|
|||
class hub_connection_impl : public std::enable_shared_from_this<hub_connection_impl>
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<hub_connection_impl> create(const utility::string_t& url, const utility::string_t& query_string,
|
||||
trace_level trace_level, const std::shared_ptr<log_writer>& log_writer);
|
||||
static std::shared_ptr<hub_connection_impl> create(const utility::string_t& url, trace_level trace_level,
|
||||
const std::shared_ptr<log_writer>& log_writer);
|
||||
|
||||
static std::shared_ptr<hub_connection_impl> create(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);
|
||||
static std::shared_ptr<hub_connection_impl> create(const utility::string_t& url, 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);
|
||||
|
||||
hub_connection_impl(const hub_connection_impl&) = delete;
|
||||
hub_connection_impl& operator=(const hub_connection_impl&) = delete;
|
||||
|
|
@ -46,9 +46,8 @@ namespace signalr
|
|||
void set_disconnected(const std::function<void()>& disconnected);
|
||||
|
||||
private:
|
||||
hub_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);
|
||||
hub_connection_impl(const utility::string_t& url, 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);
|
||||
|
||||
std::shared_ptr<connection_impl> m_connection;
|
||||
logger m_logger;
|
||||
|
|
@ -57,6 +56,7 @@ namespace signalr
|
|||
bool m_handshakeReceived;
|
||||
pplx::task_completion_event<void> m_handshakeTask;
|
||||
std::function<void()> m_disconnected;
|
||||
signalr_client_config m_signalr_client_config;
|
||||
|
||||
void initialize();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,18 @@
|
|||
|
||||
namespace signalr
|
||||
{
|
||||
struct available_transport
|
||||
{
|
||||
utility::string_t transport;
|
||||
std::vector<utility::string_t> transfer_formats;
|
||||
};
|
||||
|
||||
struct negotiation_response
|
||||
{
|
||||
utility::string_t connection_id;
|
||||
web::json::value availableTransports;
|
||||
utility::string_t connectionId;
|
||||
std::vector<available_transport> availableTransports;
|
||||
utility::string_t url;
|
||||
utility::string_t accessToken;
|
||||
utility::string_t error;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,19 +12,58 @@ namespace signalr
|
|||
namespace request_sender
|
||||
{
|
||||
pplx::task<negotiation_response> negotiate(web_request_factory& request_factory, const web::uri& base_url,
|
||||
const utility::string_t& query_string, const signalr_client_config& signalr_client_config)
|
||||
const signalr_client_config& signalr_client_config)
|
||||
{
|
||||
auto negotiate_url = url_builder::build_negotiate(base_url, query_string);
|
||||
auto negotiate_url = url_builder::build_negotiate(base_url);
|
||||
|
||||
return http_sender::post(request_factory, negotiate_url, signalr_client_config)
|
||||
.then([](utility::string_t body)
|
||||
{
|
||||
auto negotiation_response_json = web::json::value::parse(body);
|
||||
negotiation_response response
|
||||
|
||||
negotiation_response response;
|
||||
|
||||
if (negotiation_response_json.has_field(_XPLATSTR("error")))
|
||||
{
|
||||
negotiation_response_json[_XPLATSTR("connectionId")].as_string(),
|
||||
negotiation_response_json[_XPLATSTR("availableTransports")],
|
||||
};
|
||||
response.error = negotiation_response_json[_XPLATSTR("error")].as_string();
|
||||
return std::move(response);
|
||||
}
|
||||
|
||||
if (negotiation_response_json.has_field(_XPLATSTR("connectionId")))
|
||||
{
|
||||
response.connectionId = negotiation_response_json[_XPLATSTR("connectionId")].as_string();
|
||||
}
|
||||
|
||||
if (negotiation_response_json.has_field(_XPLATSTR("availableTransports")))
|
||||
{
|
||||
for (auto transportData : negotiation_response_json[_XPLATSTR("availableTransports")].as_array())
|
||||
{
|
||||
available_transport transport;
|
||||
transport.transport = transportData[_XPLATSTR("transport")].as_string();
|
||||
|
||||
for (auto format : transportData[_XPLATSTR("transferFormats")].as_array())
|
||||
{
|
||||
transport.transfer_formats.push_back(format.as_string());
|
||||
}
|
||||
|
||||
response.availableTransports.push_back(transport);
|
||||
}
|
||||
}
|
||||
|
||||
if (negotiation_response_json.has_field(_XPLATSTR("url")))
|
||||
{
|
||||
response.url = negotiation_response_json[_XPLATSTR("url")].as_string();
|
||||
|
||||
if (negotiation_response_json.has_field(_XPLATSTR("accessToken")))
|
||||
{
|
||||
response.accessToken = negotiation_response_json[_XPLATSTR("accessToken")].as_string();
|
||||
}
|
||||
}
|
||||
|
||||
if (negotiation_response_json.has_field(_XPLATSTR("ProtocolVersion")))
|
||||
{
|
||||
throw signalr_exception(_XPLATSTR("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."));
|
||||
}
|
||||
|
||||
return std::move(response);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ namespace signalr
|
|||
namespace request_sender
|
||||
{
|
||||
pplx::task<negotiation_response> negotiate(web_request_factory& request_factory, const web::uri &base_url,
|
||||
const utility::string_t& query_string, const signalr_client_config& signalr_client_config = signalr::signalr_client_config{});
|
||||
const signalr_client_config& signalr_client_config = signalr::signalr_client_config{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,23 +76,6 @@ namespace signalr
|
|||
return builder;
|
||||
}
|
||||
|
||||
web::uri_builder build_uri(const web::uri& base_url, const utility::string_t& command, transport_type transport,
|
||||
const utility::string_t& connection_data, const utility::string_t& query_string,
|
||||
const utility::string_t& last_message_id = _XPLATSTR(""), const utility::string_t& groups_token = _XPLATSTR(""))
|
||||
{
|
||||
_ASSERTE(last_message_id.length() == 0 && groups_token.length() == 0);
|
||||
|
||||
web::uri_builder builder(base_url);
|
||||
builder.append_path(command);
|
||||
append_transport(builder, transport);
|
||||
builder.append_query(_XPLATSTR("clientProtocol"), PROTOCOL);
|
||||
//append_connection_token(builder, connection_token);
|
||||
append_connection_data(builder, connection_data);
|
||||
append_message_id(builder, last_message_id);
|
||||
append_groups_token(builder, groups_token);
|
||||
return builder.append_query(query_string);
|
||||
}
|
||||
|
||||
web::uri_builder build_uri(const web::uri& base_url, const utility::string_t& command, const utility::string_t& query_string)
|
||||
{
|
||||
web::uri_builder builder(base_url);
|
||||
|
|
@ -100,9 +83,15 @@ namespace signalr
|
|||
return builder.append_query(query_string);
|
||||
}
|
||||
|
||||
web::uri build_negotiate(const web::uri& base_url, const utility::string_t& query_string)
|
||||
web::uri_builder build_uri(const web::uri& base_url, const utility::string_t& command)
|
||||
{
|
||||
return build_uri(base_url, _XPLATSTR("negotiate"), query_string).to_uri();
|
||||
web::uri_builder builder(base_url);
|
||||
return builder.append_path(command);
|
||||
}
|
||||
|
||||
web::uri build_negotiate(const web::uri& base_url)
|
||||
{
|
||||
return build_uri(base_url, _XPLATSTR("negotiate")).to_uri();
|
||||
}
|
||||
|
||||
web::uri build_connect(const web::uri& base_url, transport_type transport, const utility::string_t& query_string)
|
||||
|
|
@ -117,11 +106,5 @@ namespace signalr
|
|||
{
|
||||
return build_uri(base_url, _XPLATSTR(""), query_string).to_uri();
|
||||
}
|
||||
|
||||
web::uri build_abort(const web::uri &base_url, transport_type transport,
|
||||
const utility::string_t& connection_data, const utility::string_t &query_string)
|
||||
{
|
||||
return build_uri(base_url, _XPLATSTR("abort"), transport, connection_data, query_string).to_uri();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ namespace signalr
|
|||
{
|
||||
namespace url_builder
|
||||
{
|
||||
web::uri build_negotiate(const web::uri& base_url, const utility::string_t& query_string);
|
||||
web::uri build_negotiate(const web::uri& base_url);
|
||||
web::uri build_connect(const web::uri& base_url, transport_type transport, const utility::string_t& query_string);
|
||||
web::uri build_start(const web::uri& base_url, const utility::string_t& query_string);
|
||||
web::uri build_abort(const web::uri &base_url, transport_type transport,
|
||||
const utility::string_t& connection_data, const utility::string_t& query_string);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ TEST(hub_connection_tests, connection_status_start_stop_start)
|
|||
|
||||
TEST(hub_connection_tests, send_message)
|
||||
{
|
||||
auto hub_conn = std::make_shared<signalr::hub_connection>(url + U("custom"), U(""), signalr::trace_level::all, nullptr);
|
||||
auto hub_conn = std::make_shared<signalr::hub_connection>(url + U("custom"), signalr::trace_level::all, nullptr);
|
||||
auto message = std::make_shared<utility::string_t>();
|
||||
auto received_event = std::make_shared<signalr::event>();
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,14 @@ using namespace signalr;
|
|||
static std::shared_ptr<connection_impl> create_connection(std::shared_ptr<websocket_client> websocket_client = create_test_websocket_client(),
|
||||
std::shared_ptr<log_writer> log_writer = std::make_shared<trace_log_writer>(), trace_level trace_level = trace_level::all)
|
||||
{
|
||||
return connection_impl::create(create_uri(), _XPLATSTR(""), trace_level, log_writer, create_test_web_request_factory(),
|
||||
return connection_impl::create(create_uri(), trace_level, log_writer, create_test_web_request_factory(),
|
||||
std::make_unique<test_transport_factory>(websocket_client));
|
||||
}
|
||||
|
||||
TEST(connection_impl_connection_state, initial_connection_state_is_disconnected)
|
||||
{
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::none, std::make_shared<trace_log_writer>());
|
||||
connection_impl::create(create_uri(), trace_level::none, std::make_shared<trace_log_writer>());
|
||||
|
||||
ASSERT_EQ(connection_state::disconnected, connection->get_connection_state());
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ TEST(connection_impl_start, connection_state_is_disconnected_when_connection_can
|
|||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::none, std::make_shared<trace_log_writer>(),
|
||||
connection_impl::create(create_uri(), trace_level::none, std::make_shared<trace_log_writer>(),
|
||||
std::move(web_request_factory), std::make_unique<transport_factory>());
|
||||
|
||||
try
|
||||
|
|
@ -111,6 +111,60 @@ TEST(connection_impl_start, connection_state_is_disconnected_when_connection_can
|
|||
ASSERT_EQ(connection->get_connection_state(), connection_state::disconnected);
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_sets_id_query_string)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
utility::string_t query_string;
|
||||
|
||||
auto websocket_client = create_test_websocket_client(
|
||||
/* receive function */ []() { return pplx::task_from_exception<std::string>(std::runtime_error("should not be invoked")); },
|
||||
/* send function */ [](const utility::string_t) { return pplx::task_from_exception<void>(std::runtime_error("should not be invoked")); },
|
||||
/* connect function */[&query_string](const web::uri& url)
|
||||
{
|
||||
query_string = url.query();
|
||||
return pplx::task_from_exception<void>(web::websockets::client::websocket_exception(_XPLATSTR("connecting failed")));
|
||||
});
|
||||
|
||||
auto connection = connection_impl::create(create_uri(_XPLATSTR("")), trace_level::errors, writer, create_test_web_request_factory(), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
ASSERT_EQ(_XPLATSTR("id=f7707523-307d-4cba-9abf-3eef701241e8"), query_string);
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_appends_id_query_string)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
utility::string_t query_string;
|
||||
|
||||
auto websocket_client = create_test_websocket_client(
|
||||
/* receive function */ []() { return pplx::task_from_exception<std::string>(std::runtime_error("should not be invoked")); },
|
||||
/* send function */ [](const utility::string_t) { return pplx::task_from_exception<void>(std::runtime_error("should not be invoked")); },
|
||||
/* connect function */[&query_string](const web::uri& url)
|
||||
{
|
||||
query_string = url.query();
|
||||
return pplx::task_from_exception<void>(web::websockets::client::websocket_exception(_XPLATSTR("connecting failed")));
|
||||
});
|
||||
|
||||
auto connection = connection_impl::create(create_uri(_XPLATSTR("a=b&c=d")), trace_level::errors, writer, create_test_web_request_factory(), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
ASSERT_EQ(_XPLATSTR("a=b&c=d&id=f7707523-307d-4cba-9abf-3eef701241e8"), query_string);
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_logs_exceptions)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
|
@ -121,7 +175,7 @@ TEST(connection_impl_start, start_logs_exceptions)
|
|||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::errors, writer,
|
||||
connection_impl::create(create_uri(), trace_level::errors, writer,
|
||||
std::move(web_request_factory), std::make_unique<transport_factory>());
|
||||
|
||||
try
|
||||
|
|
@ -138,6 +192,7 @@ TEST(connection_impl_start, start_logs_exceptions)
|
|||
ASSERT_EQ(_XPLATSTR("[error ] connection could not be started due to: web exception - 404 Bad request\n"), entry);
|
||||
}
|
||||
|
||||
|
||||
TEST(connection_impl_start, start_propagates_exceptions_from_negotiate)
|
||||
{
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri &) -> std::unique_ptr<web_request>
|
||||
|
|
@ -146,7 +201,7 @@ TEST(connection_impl_start, start_propagates_exceptions_from_negotiate)
|
|||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::none, std::make_shared<trace_log_writer>(),
|
||||
connection_impl::create(create_uri(), trace_level::none, std::make_shared<trace_log_writer>(),
|
||||
std::move(web_request_factory), std::make_unique<transport_factory>());
|
||||
|
||||
try
|
||||
|
|
@ -205,7 +260,7 @@ TEST(connection_impl_start, DISABLED_start_fails_if_no_available_transports)
|
|||
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::errors, std::make_shared<trace_log_writer>(),
|
||||
connection_impl::create(create_uri(), trace_level::errors, std::make_shared<trace_log_writer>(),
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
|
|
@ -271,7 +326,7 @@ TEST(connection_impl_start, start_fails_if_negotiate_request_fails)
|
|||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::messages, writer,
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
|
|
@ -285,16 +340,15 @@ TEST(connection_impl_start, start_fails_if_negotiate_request_fails)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_fails_if_connect_request_times_out)
|
||||
TEST(connection_impl_start, start_fails_if_negotiate_response_has_error)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri& url)
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
auto response_body =
|
||||
url.path() == _XPLATSTR("/negotiate")
|
||||
? _XPLATSTR("{ \"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [] }")
|
||||
? _XPLATSTR("{ \"error\": \"bad negotiate\" }")
|
||||
: _XPLATSTR("");
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
|
|
@ -308,7 +362,379 @@ TEST(connection_impl_start, start_fails_if_connect_request_times_out)
|
|||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::messages, writer,
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
ASSERT_TRUE(false); // exception not thrown
|
||||
}
|
||||
catch (const signalr_exception & e)
|
||||
{
|
||||
ASSERT_STREQ("bad negotiate", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_fails_if_negotiate_response_does_not_have_websockets)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
auto response_body =
|
||||
url.path() == _XPLATSTR("/negotiate")
|
||||
? _XPLATSTR("{ \"availableTransports\": [ { \"transport\": \"ServerSentEvents\", \"transferFormats\": [ \"Text\" ] } ] }")
|
||||
: _XPLATSTR("");
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
pplx::task_completion_event<void> tce;
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
websocket_client->set_connect_function([tce](const web::uri&) mutable
|
||||
{
|
||||
return pplx::task<void>(tce);
|
||||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
ASSERT_TRUE(false); // exception not thrown
|
||||
}
|
||||
catch (const signalr_exception & e)
|
||||
{
|
||||
ASSERT_STREQ("The server does not support WebSockets which is currently the only transport supported by this client.", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_fails_if_negotiate_response_does_not_have_transports)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
auto response_body =
|
||||
url.path() == _XPLATSTR("/negotiate")
|
||||
? _XPLATSTR("{ \"availableTransports\": [ ] }")
|
||||
: _XPLATSTR("");
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
pplx::task_completion_event<void> tce;
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
websocket_client->set_connect_function([tce](const web::uri&) mutable
|
||||
{
|
||||
return pplx::task<void>(tce);
|
||||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
ASSERT_TRUE(false); // exception not thrown
|
||||
}
|
||||
catch (const signalr_exception & e)
|
||||
{
|
||||
ASSERT_STREQ("The server does not support WebSockets which is currently the only transport supported by this client.", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_fails_if_negotiate_response_is_invalid)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
auto response_body =
|
||||
url.path() == _XPLATSTR("/negotiate")
|
||||
? _XPLATSTR("{ \"availableTransports\": [ ")
|
||||
: _XPLATSTR("");
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
pplx::task_completion_event<void> tce;
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
websocket_client->set_connect_function([tce](const web::uri&) mutable
|
||||
{
|
||||
return pplx::task<void>(tce);
|
||||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
ASSERT_TRUE(false); // exception not thrown
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
ASSERT_STREQ("* Line 1, Column 28 Syntax error: Malformed token", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, negotiate_follows_redirect)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
utility::string_t response_body = _XPLATSTR("");
|
||||
if (url.path() == _XPLATSTR("/negotiate"))
|
||||
{
|
||||
if (url.host() == _XPLATSTR("redirected"))
|
||||
{
|
||||
response_body = _XPLATSTR("{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }");
|
||||
}
|
||||
else
|
||||
{
|
||||
response_body = _XPLATSTR("{ \"url\": \"http://redirected\" }");
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
|
||||
utility::string_t connectUrl;
|
||||
websocket_client->set_connect_function([&connectUrl](const web::uri& url)
|
||||
{
|
||||
connectUrl = url.to_string();
|
||||
return pplx::task_from_result();
|
||||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
connection->start().get();
|
||||
|
||||
ASSERT_EQ(_XPLATSTR("ws://redirected/?id=f7707523-307d-4cba-9abf-3eef701241e8"), connectUrl);
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, negotiate_redirect_uses_accessToken)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
utility::string_t accessToken;
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([&accessToken](const web::uri & url)
|
||||
{
|
||||
utility::string_t response_body = _XPLATSTR("");
|
||||
if (url.path() == _XPLATSTR("/negotiate"))
|
||||
{
|
||||
if (url.host() == _XPLATSTR("redirected"))
|
||||
{
|
||||
response_body = _XPLATSTR("{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }");
|
||||
}
|
||||
else
|
||||
{
|
||||
response_body = _XPLATSTR("{ \"url\": \"http://redirected\", \"accessToken\": \"secret\" }");
|
||||
}
|
||||
}
|
||||
|
||||
auto request = new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body);
|
||||
request->on_get_response = [&accessToken](web_request_stub& stub)
|
||||
{
|
||||
accessToken = stub.m_signalr_client_config.get_http_headers()[_XPLATSTR("Authorization")];
|
||||
};
|
||||
return std::unique_ptr<web_request>(request);
|
||||
});
|
||||
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
|
||||
utility::string_t connectUrl;
|
||||
websocket_client->set_connect_function([&connectUrl](const web::uri& url)
|
||||
{
|
||||
connectUrl = url.to_string();
|
||||
return pplx::task_from_result();
|
||||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
connection->start().get();
|
||||
|
||||
ASSERT_EQ(_XPLATSTR("ws://redirected/?id=f7707523-307d-4cba-9abf-3eef701241e8"), connectUrl);
|
||||
ASSERT_EQ(_XPLATSTR("Bearer secret"), accessToken);
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, negotiate_fails_after_too_many_redirects)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
utility::string_t response_body = _XPLATSTR("");
|
||||
if (url.path() == _XPLATSTR("/negotiate"))
|
||||
{
|
||||
// infinite redirect
|
||||
response_body = _XPLATSTR("{ \"url\": \"http://redirected\" }");
|
||||
}
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
}
|
||||
catch (signalr_exception e)
|
||||
{
|
||||
ASSERT_STREQ("Negotiate redirection limit exceeded.", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, negotiate_fails_if_ProtocolVersion_in_response)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
utility::string_t response_body = _XPLATSTR("");
|
||||
if (url.path() == _XPLATSTR("/negotiate"))
|
||||
{
|
||||
response_body = _XPLATSTR("{\"ProtocolVersion\" : \"\" }");
|
||||
}
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
}
|
||||
catch (signalr_exception e)
|
||||
{
|
||||
ASSERT_STREQ("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, negotiate_redirect_does_not_overwrite_url)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
int redirectCount = 0;
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([&redirectCount](const web::uri & url)
|
||||
{
|
||||
utility::string_t response_body = _XPLATSTR("");
|
||||
if (url.path() == _XPLATSTR("/negotiate"))
|
||||
{
|
||||
if (url.host() == _XPLATSTR("redirected"))
|
||||
{
|
||||
response_body = _XPLATSTR("{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }");
|
||||
}
|
||||
else
|
||||
{
|
||||
response_body = _XPLATSTR("{ \"url\": \"http://redirected\" }");
|
||||
redirectCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
connection->start().get();
|
||||
ASSERT_EQ(1, redirectCount);
|
||||
connection->stop().get();
|
||||
connection->start().get();
|
||||
ASSERT_EQ(2, redirectCount);
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, negotiate_redirect_uses_own_query_string)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
utility::string_t query_string;
|
||||
|
||||
auto websocket_client = create_test_websocket_client(
|
||||
/* receive function */ []() { return pplx::task_from_exception<std::string>(std::runtime_error("should not be invoked")); },
|
||||
/* send function */ [](const utility::string_t) { return pplx::task_from_exception<void>(std::runtime_error("should not be invoked")); },
|
||||
/* connect function */[&query_string](const web::uri& url)
|
||||
{
|
||||
query_string = url.query();
|
||||
return pplx::task_from_exception<void>(web::websockets::client::websocket_exception(_XPLATSTR("connecting failed")));
|
||||
});
|
||||
|
||||
auto web_request_factory = std::make_unique<test_web_request_factory>([](const web::uri & url)
|
||||
{
|
||||
utility::string_t response_body = _XPLATSTR("");
|
||||
if (url.path() == _XPLATSTR("/negotiate"))
|
||||
{
|
||||
if (url.host() == _XPLATSTR("redirected"))
|
||||
{
|
||||
response_body = _XPLATSTR("{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }");
|
||||
}
|
||||
else
|
||||
{
|
||||
response_body = _XPLATSTR("{ \"url\": \"http://redirected?customQuery=1\" }");
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
auto connection = connection_impl::create(create_uri(_XPLATSTR("a=b&c=d")), trace_level::errors, writer, std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
{
|
||||
connection->start().get();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
ASSERT_EQ(_XPLATSTR("customQuery=1&id=f7707523-307d-4cba-9abf-3eef701241e8"), query_string);
|
||||
}
|
||||
|
||||
TEST(connection_impl_start, start_fails_if_connect_request_times_out)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
|
||||
|
||||
auto web_request_factory = create_test_web_request_factory();
|
||||
|
||||
pplx::task_completion_event<void> tce;
|
||||
auto websocket_client = std::make_shared<test_websocket_client>();
|
||||
websocket_client->set_connect_function([tce](const web::uri&) mutable
|
||||
{
|
||||
return pplx::task<void>(tce);
|
||||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), trace_level::messages, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
try
|
||||
|
|
@ -373,7 +799,7 @@ TEST(connection_impl_send, message_sent)
|
|||
TEST(connection_impl_send, send_throws_if_connection_not_connected)
|
||||
{
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::none, std::make_shared<trace_log_writer>());
|
||||
connection_impl::create(create_uri(), trace_level::none, std::make_shared<trace_log_writer>());
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -674,7 +1100,7 @@ TEST(connection_impl_set_configuration, set_disconnected_callback_can_be_set_onl
|
|||
TEST(connection_impl_stop, stopping_disconnected_connection_is_no_op)
|
||||
{
|
||||
std::shared_ptr<log_writer> writer{ std::make_shared<memory_log_writer>() };
|
||||
auto connection = connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::all, writer);
|
||||
auto connection = connection_impl::create(create_uri(), trace_level::all, writer);
|
||||
connection->stop().get();
|
||||
|
||||
ASSERT_EQ(connection_state::disconnected, connection->get_connection_state());
|
||||
|
|
@ -885,7 +1311,7 @@ TEST(connection_impl_stop, ongoing_start_request_canceled_if_connection_stopped_
|
|||
});
|
||||
|
||||
auto writer = std::shared_ptr<log_writer>{std::make_shared<memory_log_writer>()};
|
||||
auto connection = connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::all, writer,
|
||||
auto connection = connection_impl::create(create_uri(), trace_level::all, writer,
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
auto start_task = connection->start();
|
||||
|
|
@ -1003,8 +1429,8 @@ TEST(connection_impl_config, custom_headers_set_in_requests)
|
|||
{
|
||||
auto response_body =
|
||||
url.path() == _XPLATSTR("/negotiate")
|
||||
? _XPLATSTR("{ \"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [] }")
|
||||
? _XPLATSTR("{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }")
|
||||
: _XPLATSTR("");
|
||||
|
||||
auto request = new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body);
|
||||
|
|
@ -1022,7 +1448,7 @@ TEST(connection_impl_config, custom_headers_set_in_requests)
|
|||
/* receive function */ []() { return pplx::task_from_result(std::string("{ }\x1e")); });
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::state_changes,
|
||||
connection_impl::create(create_uri(), trace_level::state_changes,
|
||||
writer, std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
signalr::signalr_client_config signalr_client_config{};
|
||||
|
|
@ -1149,8 +1575,8 @@ TEST(connection_id, connection_id_reset_when_starting_connection)
|
|||
if (!fail_http_requests) {
|
||||
auto response_body =
|
||||
url.path() == _XPLATSTR("/negotiate")
|
||||
? _XPLATSTR("{ \"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [] }")
|
||||
? _XPLATSTR("{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }")
|
||||
: _XPLATSTR("");
|
||||
|
||||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
|
|
@ -1160,7 +1586,7 @@ TEST(connection_id, connection_id_reset_when_starting_connection)
|
|||
});
|
||||
|
||||
auto connection =
|
||||
connection_impl::create(create_uri(), _XPLATSTR(""), trace_level::none, std::make_shared<trace_log_writer>(),
|
||||
connection_impl::create(create_uri(), trace_level::none, std::make_shared<trace_log_writer>(),
|
||||
std::move(web_request_factory), std::make_unique<test_transport_factory>(websocket_client));
|
||||
|
||||
connection->start()
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ using namespace signalr;
|
|||
std::shared_ptr<hub_connection_impl> create_hub_connection(std::shared_ptr<websocket_client> websocket_client = create_test_websocket_client(),
|
||||
std::shared_ptr<log_writer> log_writer = std::make_shared<trace_log_writer>(), trace_level trace_level = trace_level::all)
|
||||
{
|
||||
return hub_connection_impl::create(create_uri(), _XPLATSTR(""), trace_level, log_writer,
|
||||
return hub_connection_impl::create(create_uri(), trace_level, log_writer,
|
||||
create_test_web_request_factory(), std::make_unique<test_transport_factory>(websocket_client));
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ TEST(url, negotiate_appended_to_url)
|
|||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)404, _XPLATSTR("Bad request"), _XPLATSTR("")));
|
||||
});
|
||||
|
||||
auto hub_connection = hub_connection_impl::create(base_url, _XPLATSTR(""), trace_level::none,
|
||||
auto hub_connection = hub_connection_impl::create(base_url, trace_level::none,
|
||||
std::make_shared<trace_log_writer>(), std::move(web_request_factory),
|
||||
std::make_unique<test_transport_factory>(create_test_websocket_client()));
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ TEST(request_sender_negotiate, request_created_with_correct_url)
|
|||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
request_sender::negotiate(request_factory, web::uri{ _XPLATSTR("http://fake/signalr") }, _XPLATSTR("")).get();
|
||||
request_sender::negotiate(request_factory, web::uri{ _XPLATSTR("http://fake/signalr") }).get();
|
||||
|
||||
ASSERT_EQ(web::uri(_XPLATSTR("http://fake/signalr/negotiate")), requested_url);
|
||||
}
|
||||
|
|
@ -40,8 +40,8 @@ TEST(request_sender_negotiate, negotiation_request_sent_and_response_serialized)
|
|||
return std::unique_ptr<web_request>(new web_request_stub((unsigned short)200, _XPLATSTR("OK"), response_body));
|
||||
});
|
||||
|
||||
auto response = request_sender::negotiate(request_factory, web::uri{ _XPLATSTR("http://fake/signalr") }, _XPLATSTR("")).get();
|
||||
auto response = request_sender::negotiate(request_factory, web::uri{ _XPLATSTR("http://fake/signalr") }).get();
|
||||
|
||||
ASSERT_EQ(_XPLATSTR("f7707523-307d-4cba-9abf-3eef701241e8"), response.connection_id);
|
||||
ASSERT_EQ(_XPLATSTR("f7707523-307d-4cba-9abf-3eef701241e8"), response.connectionId);
|
||||
// TODO: response.availableTransports
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ std::unique_ptr<web_request_factory> create_test_web_request_factory()
|
|||
auto response_body =
|
||||
url.path() == _XPLATSTR("/negotiate")
|
||||
? _XPLATSTR("{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", ")
|
||||
_XPLATSTR("\"availableTransports\" : [] }")
|
||||
_XPLATSTR("\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }")
|
||||
: url.path() == _XPLATSTR("/start") || url.path() == _XPLATSTR("/signalr/start")
|
||||
? _XPLATSTR("{\"Response\":\"started\" }")
|
||||
: _XPLATSTR("");
|
||||
|
|
@ -58,6 +58,18 @@ utility::string_t create_uri()
|
|||
.append(utility::conversions::to_string_t(unit_test->current_test_info()->name()));
|
||||
}
|
||||
|
||||
utility::string_t create_uri(const utility::string_t& query_string)
|
||||
{
|
||||
auto unit_test = ::testing::UnitTest::GetInstance();
|
||||
|
||||
// unit test will be null if this function is not called in a test
|
||||
_ASSERTE(unit_test);
|
||||
|
||||
return utility::string_t(_XPLATSTR("http://"))
|
||||
.append(utility::conversions::to_string_t(unit_test->current_test_info()->name()))
|
||||
.append(_XPLATSTR("?" + query_string));
|
||||
}
|
||||
|
||||
std::vector<utility::string_t> filter_vector(const std::vector<utility::string_t>& source, const utility::string_t& string)
|
||||
{
|
||||
std::vector<utility::string_t> filtered_entries;
|
||||
|
|
|
|||
|
|
@ -17,5 +17,6 @@ std::shared_ptr<signalr::websocket_client> create_test_websocket_client(
|
|||
|
||||
std::unique_ptr<signalr::web_request_factory> create_test_web_request_factory();
|
||||
utility::string_t create_uri();
|
||||
utility::string_t create_uri(const utility::string_t& query_string);
|
||||
std::vector<utility::string_t> filter_vector(const std::vector<utility::string_t>& source, const utility::string_t& string);
|
||||
utility::string_t dump_vector(const std::vector<utility::string_t>& source);
|
||||
utility::string_t dump_vector(const std::vector<utility::string_t>& source);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pplx::task<void> test_websocket_client::send(const utility::string_t &msg)
|
|||
|
||||
pplx::task<std::string> test_websocket_client::receive()
|
||||
{
|
||||
return m_receive_function();
|
||||
return pplx::create_task([this]() { return m_receive_function(); });
|
||||
}
|
||||
|
||||
pplx::task<void> test_websocket_client::close()
|
||||
|
|
@ -50,4 +50,4 @@ void test_websocket_client::set_receive_function(std::function<pplx::task<std::s
|
|||
void test_websocket_client::set_close_function(std::function<pplx::task<void>()> close_function)
|
||||
{
|
||||
m_close_function = close_function;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ TEST(url_builder_negotiate, url_correct_if_query_string_empty)
|
|||
{
|
||||
ASSERT_EQ(
|
||||
web::uri(_XPLATSTR("http://fake/negotiate")),
|
||||
url_builder::build_negotiate(web::uri{ _XPLATSTR("http://fake/") }, _XPLATSTR("")));
|
||||
url_builder::build_negotiate(web::uri{ _XPLATSTR("http://fake/") }));
|
||||
}
|
||||
|
||||
TEST(url_builder_negotiate, url_correct_if_query_string_not_empty)
|
||||
{
|
||||
ASSERT_EQ(
|
||||
web::uri(_XPLATSTR("http://fake/negotiate?q1=1&q2=2")),
|
||||
url_builder::build_negotiate(web::uri{ _XPLATSTR("http://fake/") }, _XPLATSTR("q1=1&q2=2")));
|
||||
url_builder::build_negotiate(web::uri{ _XPLATSTR("http://fake/?q1=1&q2=2") }));
|
||||
}
|
||||
|
||||
TEST(url_builder_connect_webSockets, url_correct_if_query_string_not_empty)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ using namespace signalr;
|
|||
TEST(websocket_transport_connect, connect_connects_and_starts_receive_loop)
|
||||
{
|
||||
auto connect_called = false;
|
||||
auto receive_called = std::make_shared<bool>(false);
|
||||
auto receive_called = std::make_shared<event>();
|
||||
auto client = std::make_shared<test_websocket_client>();
|
||||
|
||||
client->set_connect_function([&connect_called](const web::uri &) -> pplx::task<void>
|
||||
|
|
@ -24,7 +24,7 @@ TEST(websocket_transport_connect, connect_connects_and_starts_receive_loop)
|
|||
|
||||
client->set_receive_function([receive_called]()->pplx::task<std::string>
|
||||
{
|
||||
*receive_called = true;
|
||||
receive_called->set();
|
||||
return pplx::task_from_result(std::string(""));
|
||||
});
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ TEST(websocket_transport_connect, connect_connects_and_starts_receive_loop)
|
|||
ws_transport->connect(_XPLATSTR("ws://fakeuri.org/connect?param=42")).get();
|
||||
|
||||
ASSERT_TRUE(connect_called);
|
||||
ASSERT_TRUE(*receive_called);
|
||||
ASSERT_FALSE(receive_called->wait(5000));
|
||||
|
||||
auto log_entries = std::dynamic_pointer_cast<memory_log_writer>(writer)->get_log_entries();
|
||||
ASSERT_FALSE(log_entries.empty());
|
||||
|
|
|
|||
Loading…
Reference in New Issue