spectrum2/3rdparty/cpprestsdk/tests/functional/websockets/utilities/test_websocket_server.h
2015-11-19 15:19:14 +01:00

160 lines
5.8 KiB
C++

/***
* ==++==
*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ==--==
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* test_websocket_server.h -- Defines a test server to handle incoming and outgoing messages.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include <map>
#include <sstream>
#include <iostream>
#include <mutex>
#include <condition_variable>
#ifndef WEBSOCKET_UTILITY_API
#ifdef WEBSOCKETTESTUTILITY_EXPORTS
#define WEBSOCKET_UTILITY_API __declspec(dllexport)
#else
#define WEBSOCKET_UTILITY_API __declspec(dllimport)
#endif
#endif
#if !defined(_M_ARM) || defined(__cplusplus_winrt)
namespace tests { namespace functional { namespace websocket { namespace utilities {
class _test_websocket_server;
// The different types of a websocket message.
enum test_websocket_message_type
{
WEB_SOCKET_BINARY_MESSAGE_TYPE,
WEB_SOCKET_BINARY_FRAGMENT_TYPE,
WEB_SOCKET_UTF8_MESSAGE_TYPE,
WEB_SOCKET_UTF8_FRAGMENT_TYPE,
WEB_SOCKET_CLOSE_TYPE
};
// Interface containing details about the HTTP handshake request received by the test server.
class test_http_request_interface
{
public:
virtual ~test_http_request_interface() {}
virtual const std::string& username() = 0;
virtual const std::string& password() = 0;
virtual const std::string& get_header_val(const std::string& header_name) = 0;
};
typedef std::unique_ptr<test_http_request_interface> test_http_request;
// Class that contains details about the HTTP handshake response to be sent by the test server
class test_http_response
{
public:
void set_realm(std::string realm) { m_realm = std::move(realm); }
void set_status_code(unsigned short code) { m_status_code = code; }
const std::string& realm() const { return m_realm; }
unsigned short status_code() const { return m_status_code; }
private:
std::string m_realm;
unsigned short m_status_code;
};
// Represents a websocket message at the test server.
// Contains a vector that can contain text/binary data
// and a type variable to denote the message type.
class test_websocket_msg
{
public:
const std::vector<unsigned char>& data() const { return m_data; }
void set_data(std::vector<unsigned char> data) { m_data = std::move(data); }
test_websocket_message_type msg_type() const { return m_msg_type; }
void set_msg_type(test_websocket_message_type type) { m_msg_type = type; }
private:
std::vector<unsigned char> m_data;
test_websocket_message_type m_msg_type;
};
class websocket_asserts
{
public:
static void assert_message_equals(test_websocket_msg& msg, const std::string& expected_data, test_websocket_message_type expected_flag)
{
std::vector<unsigned char> temp_vec(expected_data.begin(), expected_data.end());
assert_message_equals(msg, temp_vec, expected_flag);
}
static void assert_message_equals(test_websocket_msg& msg, const std::vector<unsigned char>& expected_data, test_websocket_message_type expected_flag)
{
VERIFY_ARE_EQUAL(msg.msg_type(), expected_flag);
auto& data = msg.data();
VERIFY_ARE_EQUAL(data.size(), expected_data.size());
VERIFY_IS_TRUE(std::equal(expected_data.begin(), expected_data.end(), data.begin()));
}
private:
websocket_asserts() {}
~websocket_asserts() CPPREST_NOEXCEPT {}
};
// Test websocket server.
class test_websocket_server
{
public:
WEBSOCKET_UTILITY_API test_websocket_server();
// Tests can add a handler to handle (verify) the next message received by the server.
// If the test plans to send n messages, n handlers must be registered.
// The server will call the handler in order, for each incoming message.
WEBSOCKET_UTILITY_API void next_message(std::function<void __cdecl (test_websocket_msg)> msg_handler);
WEBSOCKET_UTILITY_API std::function<void(test_websocket_msg)> get_next_message_handler();
// Handler for initial HTTP request.
typedef std::function<test_http_response __cdecl (test_http_request)> http_handler;
WEBSOCKET_UTILITY_API void set_http_handler(http_handler handler) { m_http_handler = handler; }
WEBSOCKET_UTILITY_API http_handler get_http_handler() { return m_http_handler; }
// Tests can use this API to send a message from the server to the client.
WEBSOCKET_UTILITY_API void send_msg(const test_websocket_msg& msg);
WEBSOCKET_UTILITY_API std::shared_ptr<_test_websocket_server> get_impl();
private:
#if !defined(_MSC_VER) || _MSC_VER >= 1800
test_websocket_server(const test_websocket_server&) = delete;
test_websocket_server& operator=(const test_websocket_server&) = delete;
test_websocket_server(test_websocket_server&&) = delete;
test_websocket_server& operator=(test_websocket_server&&) = delete;
#endif
// Queue to maintain the request handlers.
// Note: This queue is not thread-safe. Use m_handler_queue_lock to synchronize.
std::mutex m_handler_queue_lock;
std::queue<std::function<void(test_websocket_msg)>> m_handler_queue;
// Handler to address the HTTP handshake request. To be used in scenarios where tests may wish to fail the HTTP request
// and not proceed with the websocket connection.
http_handler m_http_handler;
std::shared_ptr<_test_websocket_server> m_p_impl;
};
}}}}
#endif