/*** * ==++== * * 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 #include #include #include #include #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; // 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& data() const { return m_data; } void set_data(std::vector 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 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 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& 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 msg_handler); WEBSOCKET_UTILITY_API std::function get_next_message_handler(); // Handler for initial HTTP request. typedef std::function 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> 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