Enabling building and running tests on Linux

This commit is contained in:
Pawel Kadluczka 2015-08-08 09:28:31 -07:00 коммит произвёл Pawel Kadluczka
Родитель 1ad436914a
Коммит 5dfa11e08f
21 изменённых файлов: 189 добавлений и 64 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -17,4 +17,5 @@ ipch/
artifacts/
*.aps
src/signalrclientdll/version.h
/.vs/
/.vs/
build.*

19
CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,19 @@
cmake_minimum_required (VERSION 2.8.11)
project (signalrclient)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -L -lcpprest")
set(CPPREST_INCLUDE_DIR "" CACHE FILEPATH "Path to casablanca include dir")
include_directories (
include
"${CPPREST_INCLUDE_DIR}")
find_library(CPPREST_SO NAMES "cpprest" PATHS ${CPPREST_LIB_DIR} REQUIRED)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
add_subdirectory(src/signalrclient)
add_subdirectory(test)

Просмотреть файл

@ -45,12 +45,6 @@ namespace signalr
return invoke_json(method_name, web::json::value().array(), on_progress);
}
template<>
pplx::task<void> invoke<void>(const utility::string_t& method_name, const on_progress_handler& on_progress)
{
return invoke_void(method_name, web::json::value().array(), on_progress);
}
template<typename T>
pplx::task<T> invoke(const utility::string_t& method_name, const web::json::value& arguments,
const on_progress_handler& on_progress = [](const web::json::value&){})
@ -59,13 +53,6 @@ namespace signalr
return invoke_json(method_name, arguments, on_progress);
}
template<>
pplx::task<void> invoke<void>(const utility::string_t& method_name, const web::json::value& arguments,
const on_progress_handler& on_progress)
{
return invoke_void(method_name, arguments, on_progress);
}
private:
std::shared_ptr<internal_hub_proxy> m_pImpl;
@ -74,4 +61,17 @@ namespace signalr
SIGNALRCLIENT_API pplx::task<void> __cdecl invoke_void(const utility::string_t& method_name, const web::json::value& arguments,
const on_progress_handler& on_progress);
};
template<>
inline pplx::task<void> hub_proxy::invoke<void>(const utility::string_t& method_name, const on_progress_handler& on_progress)
{
return invoke_void(method_name, web::json::value().array(), on_progress);
}
template<>
inline pplx::task<void> hub_proxy::invoke<void>(const utility::string_t& method_name, const web::json::value& arguments,
const on_progress_handler& on_progress)
{
return invoke_void(method_name, arguments, on_progress);
}
}

Просмотреть файл

@ -0,0 +1,27 @@
set (SOURCES
callback_manager.cpp
connection.cpp
connection_impl.cpp
default_websocket_client.cpp
http_sender.cpp
hub_connection.cpp
hub_connection_impl.cpp
hub_proxy.cpp
internal_hub_proxy.cpp
logger.cpp
request_sender.cpp
stdafx.cpp
trace_log_writer.cpp
transport.cpp
transport_factory.cpp
url_builder.cpp
web_request.cpp
web_request_factory.cpp
websocket_transport.cpp
)
add_library (signalrclient SHARED ${SOURCES})
target_link_libraries(signalrclient ${CPPREST_SO})

Просмотреть файл

@ -26,7 +26,7 @@ namespace signalr
void clear(const web::json::value& arguments);
private:
std::atomic<int> m_id = 0;
std::atomic<int> m_id { 0 };
std::unordered_map<utility::string_t, std::function<void(const web::json::value&)>> m_callbacks;
std::mutex m_map_lock;
const web::json::value m_dtor_clear_arguments;

Просмотреть файл

@ -10,6 +10,7 @@
#include "request_sender.h"
#include "url_builder.h"
#include "trace_log_writer.h"
#include "make_unique.h"
namespace signalr
{
@ -372,7 +373,7 @@ namespace signalr
auto transport = m_transport;
auto connection_state = get_connection_state();
if (connection_state != connection_state::connected || !transport)
if (connection_state != signalr::connection_state::connected || !transport)
{
return pplx::task_from_exception<void>(std::runtime_error(
std::string{ "cannot send data when the connection is not in the connected state. current connection state: " }
@ -779,11 +780,11 @@ namespace signalr
void connection_impl::ensure_disconnected(const std::string& error_message)
{
auto connection_state = get_connection_state();
if (connection_state != connection_state::disconnected)
auto state = get_connection_state();
if (state != connection_state::disconnected)
{
throw std::runtime_error(error_message + std::string{"current connection state: "}
.append(utility::conversions::to_utf8string(translate_connection_state(connection_state))));
.append(utility::conversions::to_utf8string(translate_connection_state(state))));
}
}
@ -851,4 +852,4 @@ namespace signalr
const_cast<signalr::logger &>(logger).log(level, entry);
}
}
}
}

Просмотреть файл

@ -3,6 +3,8 @@
#pragma once
#include <assert.h>
#include <condition_variable>
#include <mutex>
namespace signalr
@ -47,7 +49,7 @@ namespace signalr
{
std::chrono::milliseconds period(timeout);
auto status = m_condition.wait_for(lock, period, [this]() { return m_signaled; });
_ASSERTE(status == 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;
}
@ -58,4 +60,4 @@ namespace signalr
return wait(event::timeout_infinite);
}
};
}
}

Просмотреть файл

@ -5,6 +5,7 @@
#include "hub_connection_impl.h"
#include "signalrclient/hub_exception.h"
#include "trace_log_writer.h"
#include "make_unique.h"
namespace signalr
{

Просмотреть файл

@ -39,15 +39,15 @@ namespace signalr
{
switch (trace_level)
{
case trace_level::messages:
case signalr::trace_level::messages:
return _XPLATSTR("message");
case trace_level::state_changes:
case signalr::trace_level::state_changes:
return _XPLATSTR("state change");
case trace_level::events:
case signalr::trace_level::events:
return _XPLATSTR("event");
case trace_level::errors:
case signalr::trace_level::errors:
return _XPLATSTR("error");
case trace_level::info:
case signalr::trace_level::info:
return _XPLATSTR("info");
default:
_ASSERTE(false);

Просмотреть файл

@ -0,0 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#pragma once
#if defined (__GNUC__)
#include <memory>
namespace std
{
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
#endif

Просмотреть файл

@ -12,13 +12,13 @@ namespace signalr
std::function<void(const utility::string_t&)> process_response_callback,
std::function<void(const std::exception&)> error_callback)
{
if (transport_type == transport_type::websockets)
if (transport_type == signalr::transport_type::websockets)
{
return websocket_transport::create([headers](){ return std::make_shared<default_websocket_client>(headers); },
logger, process_response_callback, error_callback);
}
throw std::exception("not implemented");
throw std::runtime_error("not implemented");
}
transport_factory::~transport_factory()

Просмотреть файл

@ -3,6 +3,7 @@
#include "stdafx.h"
#include "web_request_factory.h"
#include "make_unique.h"
namespace signalr
{

5
test/CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,5 @@
add_subdirectory (gtest-1.7.0)
enable_testing()
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
add_subdirectory (signalrclienttests)

Просмотреть файл

@ -0,0 +1,34 @@
set (SOURCES
callback_manager_tests.cpp
case_insensitive_comparison_utils_tests.cpp
connection_impl_tests.cpp
http_sender_tests.cpp
hub_connection_impl_tests.cpp
hub_exception_tests.cpp
internal_hub_proxy_tests.cpp
logger_tests.cpp
memory_log_writer.cpp
request_sender_tests.cpp
signalrclienttests.cpp
stdafx.cpp
test_transport_factory.cpp
test_utils.cpp
test_web_request_factory.cpp
test_websocket_client.cpp
url_builder_tests.cpp
web_request_stub.cpp
web_request_tests.cpp
websocket_transport_tests.cpp
)
include_directories(
../../src/signalrclient)
find_package(Boost COMPONENTS system REQUIRED)
find_package(OpenSSL REQUIRED)
add_executable (signalrclienttests ${SOURCES})
target_link_libraries(signalrclienttests gtest gtest_main signalrclient ${CPPREST_SO} ${Boost_SYSTEM_LIBRARY} ${OPENSSL_LIBRARIES})
add_test(signalrclienttests signalrclienttests)

Просмотреть файл

@ -217,7 +217,9 @@ TEST(connection_impl_start, start_fails_if_TryWebsockets_false_and_no_fallback_t
}
}
TEST(connection_impl_start, start_fails_if_transport_fails_when_receiveing_messages)
#if defined(_WIN32) // https://github.com/aspnet/SignalR-Client-Cpp/issues/131
TEST(connection_impl_start, start_fails_if_transport_fails_when_receiving_messages)
{
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
@ -240,12 +242,14 @@ TEST(connection_impl_start, start_fails_if_transport_fails_when_receiveing_messa
}
auto log_entries = std::dynamic_pointer_cast<memory_log_writer>(writer)->get_log_entries();
ASSERT_TRUE(log_entries.size() > 1);
ASSERT_TRUE(log_entries.size() > 1) << dump_vector(log_entries);
auto entry = remove_date_from_log_entry(log_entries[1]);
ASSERT_EQ(_XPLATSTR("[error ] connection could not be started due to: receive error\n"), entry);
ASSERT_EQ(_XPLATSTR("[error ] connection could not be started due to: receive error\n"), entry) << dump_vector(log_entries);
}
#endif
TEST(connection_impl_start, start_fails_if_start_request_fails)
{
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
@ -823,7 +827,7 @@ TEST(connection_impl_stop, can_start_and_stop_connection_multiple_times)
// to happen and if it does not the test will fail
for (int wait_time_ms = 5; wait_time_ms < 100 && memory_writer->get_log_entries().size() < 8; wait_time_ms <<= 1)
{
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = memory_writer->get_log_entries();
@ -844,7 +848,11 @@ TEST(connection_impl_stop, dtor_stops_the_connection)
{
auto websocket_client = create_test_websocket_client(
/* receive function */ []() { pplx::wait(1); return pplx::task_from_result(std::string("{ \"C\":\"x\", \"S\":1, \"M\":[] }")); });
/* receive function */ []()
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return pplx::task_from_result(std::string("{ \"C\":\"x\", \"S\":1, \"M\":[] }"));
});
auto connection = create_connection(websocket_client, writer, trace_level::state_changes);
connection->start().get();
@ -857,7 +865,7 @@ TEST(connection_impl_stop, dtor_stops_the_connection)
// to happen and if it does not the test will fail
for (int wait_time_ms = 5; wait_time_ms < 100 && memory_writer->get_log_entries().size() < 4; wait_time_ms <<= 1)
{
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = memory_writer->get_log_entries();
@ -946,7 +954,7 @@ TEST(connection_impl_stop, ongoing_start_request_cancelled_if_connection_stopped
}).get();
auto log_entries = std::dynamic_pointer_cast<memory_log_writer>(writer)->get_log_entries();
ASSERT_EQ(5, log_entries.size());
ASSERT_EQ(5, log_entries.size()) << dump_vector(log_entries);
ASSERT_EQ(_XPLATSTR("[state change] disconnected -> connecting\n"), remove_date_from_log_entry(log_entries[0]));
ASSERT_EQ(_XPLATSTR("[info ] stopping connection\n"), remove_date_from_log_entry(log_entries[1]));
ASSERT_EQ(_XPLATSTR("[info ] acquired lock in shutdown()\n"), remove_date_from_log_entry(log_entries[2]));
@ -1375,7 +1383,7 @@ TEST(connection_impl_reconnect, reconnect_cancelled_if_connection_dropped_during
auto memory_writer = std::dynamic_pointer_cast<memory_log_writer>(writer);
for (int wait_time_ms = 5; wait_time_ms < 100 && memory_writer->get_log_entries().size() < 6; wait_time_ms <<= 1)
{
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = memory_writer->get_log_entries();
@ -1456,7 +1464,7 @@ TEST(connection_impl_reconnect, reconnect_cancelled_when_connection_being_stoppe
break;
}
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
ASSERT_EQ(1,
@ -1500,7 +1508,7 @@ TEST(connection_impl_reconnect, reconnect_cancelled_if_connection_goes_out_of_sc
std::shared_ptr<log_writer> writer(std::make_shared<memory_log_writer>());
{
auto connection = create_connection(websocket_client, writer, trace_level::state_changes);
auto connection = create_connection(websocket_client, writer, trace_level::all);
connection->set_reconnect_delay(100);
event reconnecting_event{};
connection->set_reconnecting([&reconnecting_event](){ reconnecting_event.set(); });
@ -1513,18 +1521,27 @@ TEST(connection_impl_reconnect, reconnect_cancelled_if_connection_goes_out_of_sc
// used by tasks as a shared_ptr. As a result the dtor is being called on the thread which released the last reference.
// Therefore we need to wait block until the dtor has actually completed. Time out would most likely indicate a bug.
auto memory_writer = std::dynamic_pointer_cast<memory_log_writer>(writer);
for (int wait_time_ms = 5; wait_time_ms < 100 && memory_writer->get_log_entries().size() < 5; wait_time_ms <<= 1)
for (int wait_time_ms = 5; wait_time_ms < 10000; wait_time_ms <<= 1)
{
pplx::wait(wait_time_ms);
if (filter_vector(std::dynamic_pointer_cast<memory_log_writer>(writer)->get_log_entries(),
_XPLATSTR("[state change] disconnecting -> disconnected")).size() > 0)
{
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = memory_writer->get_log_entries();
ASSERT_EQ(5, log_entries.size());
ASSERT_EQ(_XPLATSTR("[state change] disconnected -> connecting\n"), remove_date_from_log_entry(log_entries[0]));
ASSERT_EQ(_XPLATSTR("[state change] connecting -> connected\n"), remove_date_from_log_entry(log_entries[1]));
ASSERT_EQ(_XPLATSTR("[state change] connected -> reconnecting\n"), remove_date_from_log_entry(log_entries[2]));
ASSERT_EQ(_XPLATSTR("[state change] reconnecting -> disconnecting\n"), remove_date_from_log_entry(log_entries[3]));
ASSERT_EQ(_XPLATSTR("[state change] disconnecting -> disconnected\n"), remove_date_from_log_entry(log_entries[4]));
auto state_changes = filter_vector(log_entries, _XPLATSTR("[state change]"));
ASSERT_EQ(5, state_changes.size()) << dump_vector(log_entries);
ASSERT_EQ(_XPLATSTR("[state change] disconnected -> connecting\n"), remove_date_from_log_entry(state_changes[0]));
ASSERT_EQ(_XPLATSTR("[state change] connecting -> connected\n"), remove_date_from_log_entry(state_changes[1]));
ASSERT_EQ(_XPLATSTR("[state change] connected -> reconnecting\n"), remove_date_from_log_entry(state_changes[2]));
ASSERT_EQ(_XPLATSTR("[state change] reconnecting -> disconnecting\n"), remove_date_from_log_entry(state_changes[3]));
ASSERT_EQ(_XPLATSTR("[state change] disconnecting -> disconnected\n"), remove_date_from_log_entry(state_changes[4]));
}
TEST(connection_impl_reconnect, std_exception_for_reconnected_reconnecting_callback_caught_and_logged)
@ -1566,7 +1583,7 @@ TEST(connection_impl_reconnect, std_exception_for_reconnected_reconnecting_callb
auto memory_writer = std::dynamic_pointer_cast<memory_log_writer>(writer);
for (int wait_time_ms = 5; wait_time_ms < 100 && memory_writer->get_log_entries().size() < 3; wait_time_ms <<= 1)
{
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = memory_writer->get_log_entries();
@ -1613,7 +1630,7 @@ TEST(connection_impl_reconnect, exception_for_reconnected_reconnecting_callback_
auto memory_writer = std::dynamic_pointer_cast<memory_log_writer>(writer);
for (int wait_time_ms = 5; wait_time_ms < 100 && memory_writer->get_log_entries().size() < 3; wait_time_ms <<= 1)
{
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = memory_writer->get_log_entries();
@ -1781,7 +1798,7 @@ TEST(connection_impl_reconnect, current_reconnect_cancelled_if_another_reconnect
break;
}
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = std::dynamic_pointer_cast<memory_log_writer>(writer)->get_log_entries();
@ -1801,4 +1818,4 @@ TEST(connection_impl_reconnect, current_reconnect_cancelled_if_another_reconnect
ASSERT_EQ(_XPLATSTR("[state change] connecting -> connected\n"), remove_date_from_log_entry(state_changes[6]));
ASSERT_EQ(_XPLATSTR("[state change] connected -> reconnecting\n"), remove_date_from_log_entry(state_changes[7]));
ASSERT_EQ(_XPLATSTR("[state change] reconnecting -> connected\n"), remove_date_from_log_entry(state_changes[8]));
}
}

Просмотреть файл

@ -227,7 +227,7 @@ TEST(stop, connection_stopped_when_going_out_of_scope)
// to happen and if it does not the test will fail. There is nothing we can block on.
for (int wait_time_ms = 5; wait_time_ms < 100 && memory_writer->get_log_entries().size() < 4; wait_time_ms <<= 1)
{
pplx::wait(wait_time_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
}
auto log_entries = memory_writer->get_log_entries();
@ -1200,8 +1200,6 @@ TEST(reconnect, pending_invocations_finished_and_custom_reconnecting_callback_in
ASSERT_FALSE(reconnecting_invoked_event->wait(5000));
}
#include "windows.h"
TEST(reconnect, reconnecting_reconnected_callbacks_invoked)
{
int call_number = -1;

Просмотреть файл

@ -12,7 +12,7 @@ using namespace signalr;
class memory_log_writer : public log_writer
{
public:
void _cdecl write(const utility::string_t &entry) override;
void __cdecl write(const utility::string_t &entry) override;
std::vector<utility::string_t> get_log_entries();
private:

Просмотреть файл

@ -10,6 +10,5 @@ int main(int argc, char* argv[])
#endif
{
::testing::InitGoogleTest(&argc, argv);
RUN_ALL_TESTS();
return 0;
return RUN_ALL_TESTS();
}

Просмотреть файл

@ -9,4 +9,6 @@
#endif
#include "gtest/gtest.h"
#include "../../src/signalrclient/event.h"
#include "../../src/signalrclient/event.h"
#include "../../src/signalrclient/make_unique.h"
#include <thread>

Просмотреть файл

@ -14,10 +14,10 @@ std::shared_ptr<transport> test_transport_factory::create_transport(transport_ty
std::function<void(const utility::string_t&)> process_message_callback,
std::function<void(const std::exception&)> error_callback)
{
if (transport_type == transport_type::websockets)
if (transport_type == signalr::transport_type::websockets)
{
return websocket_transport::create([&](){ return m_websocket_client; }, logger, process_message_callback, error_callback);
}
throw std::exception("not supported");
throw std::runtime_error("not supported");
}

Просмотреть файл

@ -298,7 +298,7 @@ TEST(websocket_transport_disconnect, exceptions_from_outstanding_receive_task_ob
return pplx::create_task([receive_event]()
{
receive_event->wait();
return pplx::task_from_exception<std::string>(std::exception("exception from receive"));
return pplx::task_from_exception<std::string>(std::runtime_error("exception from receive"));
});
});
@ -335,7 +335,7 @@ TEST(websocket_transport_receive_loop, receive_loop_logs_if_receive_task_cancell
TEST(websocket_transport_receive_loop, receive_loop_logs_std_exception)
{
receive_loop_logs_exception_runner(
std::exception("exception"),
std::runtime_error("exception"),
_XPLATSTR("[error ] [websocket transport] error receiving response from websocket: exception\n"),
trace_level::errors);
}
@ -364,7 +364,7 @@ void receive_loop_logs_exception_runner(const T& e, const utility::string_t& exp
}).get();
// this is race'y but there is nothing we can block on
pplx::wait(10);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
auto log_entries = std::dynamic_pointer_cast<memory_log_writer>(writer)->get_log_entries();
@ -397,7 +397,7 @@ TEST(websocket_transport_receive_loop, process_response_callback_called_when_mes
process_response_event->wait(1000);
ASSERT_EQ(_XPLATSTR("msg"), *msg);
ASSERT_EQ(utility::string_t(_XPLATSTR("msg")), *msg);
}
TEST(websocket_transport_receive_loop, error_callback_called_when_exception_thrown)