Разработка сервера для мокирования асинхронных протоколов

Мокирование как процесс задания содержания и формата ответа на сетевой запрос к серверу. Асинхронные протоколы - технология, позволяющая коммуницировать с помощью обмена сообщениями без необходимости ожидания полного ответа от сервиса-собеседника.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 28.11.2019
Размер файла 668,2 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru

Размещено на http://www.allbest.ru

Введение

Актуальность работы.

На текущий момент при разработке программных систем часто используются клиент-серверный и микросервисный подходы к архитектуре таких систем. В упомянутых подходах есть сервисы-потребители и сервисы-провайдеры. Сервис-потребитель обращается к сервису-провайдеру по сети для получения данных или выполнения какого-то действия. В подобных условиях разработчикам сервиса-потребителя может быть полезным использовать мок-сервер в качестве замены сервиса-провайдера. Особенно уместным использование сервера для мокирования может быть в следующих сценариях. Например, сервис-провайдер еще не разработан или не поддерживает работу с данным сервисом-потребителем. Тогда разработчики могут договориться и сконфигурировать мок-сервер, чтобы он отвечал на запросы сервиса-клиента, как будто он и есть сервис-провайдер. Разработчики смогут дорабатывать свои приложения без ожидания доработок других сервисов. Также с помощью сервера для мокирования можно сильно ускорить создание прототипа приложения, поскольку часть доработок будет идти параллельно, а часть можно отбросить и заменить на конфигурацию мок-сервера. Помимо уже упомянутых ситуаций, мок-сервер может использоваться при тестировании сервиса-потребителя. Тогда не потребуется создание условий (таких, как создание пользователя с нужными ролями или заполнение базы данных) для сервиса-провайдера, чтобы получить от него нужный ответ. Достаточно сконфигурировать мок-сервер, что сделать потенциально проще и быстрее.

Так как одним из наиболее распространенных протоколов взаимодействия сервисов является HTTP, есть несколько популярных реализаций мок-серверов для данного протокола. Среди них Mountebank [5], MockServer [6], WireMock [7]. Данные реализации дают возможность отвечать на заданных портах согласно описанной конфигурации. Однако упомянутые решения работают только с протоколами HTTP(S) и TCP. Существует еще набор асинхронных протоколов, для которых есть потребность в подобном мок-сервере. В результате поиска подобного решения для протоколов WebSocket и Server-Sent Events был сделан вывод, что текущие решения обладают сильными недостатками, которые необходимо преодолеть для удовлетворения потребностей пользователей.

Цель и задачи работы.

Цель моей работы - разработать сервер для мокирования протоколов WebSocket и Server-Sent Events. Для ее достижения необходимо выполнить следующие задачи:

1. Изучить имеющиеся аналоги серверов для мокирования;

2. Изучить особенности протоколов WebSocket и Server-Sent Events;

3. Реализовать сервер для мокирования WebSocket и Server-Sent Events;

4. Подготовить техническую документацию;

5. Выложить исходный код приложения и техническую документацию на GitHub под открытой лицензией.

Мокирование - задание содержания и формата ответа на сетевой запрос к серверу. В объектно-ориентированном программировании мокирование - создание объектов-заглушек вместо настоящих объектов путем имитации их актуальных свойств [4]. Объект-заглушка на вызов метода с определенными аргументами возвращает заданный пользователем ответ.

Сервер - программа, обрабатывающая запросы от других программ по сети.

WebSocket - дуплексный протокол для взаимодействия двух программ по сети.

Server-Sent Events - симплексный протокол взаимодействия двух программ по сети, в котором только одна сторона посылает сообщения.

1. Описание асинхронных протоколов и существующих аналогов решения

В данной главе описаны основные особенности асинхронных протоколов WebSocket и Server-Sent Events, а также решения, позволяющие получить сервер для мокирования данных протоколов, и их недостатки.

Описание асинхронных протоколов

WebSocket.

WebSocket - дуплексный протокол для двух взаимодействующих сервисов, основанный на TCP. Данный протокол задумывался в качестве замены существующих вариантов двусторонней коммуникации, которые использовали HTTP в качестве транспортного протокола. Среди них, например, long polling [2]. Long polling работает следующим образом. Клиент в цикле посылает запросы на сервер. Сервер отдает ответ только по истечении определенного интервала времени или когда происходит определенное событие. Клиент при получении ответа сразу же посылает повторный запрос на сервер. Такой подход имеет следующие недостатки: лишняя передача заголовков в запросах, необходимость установления HTTP соединения, необходимость правильного выбора таймаута для запроса [2]. Протокол WebSocket не имеет перечисленных проблем.

Далее будут описаны базовые концепции протокола WebSocket. В качестве источника используется RFC 6455 [1]. Взаимодействие участников коммуникации осуществляется в 3 этапа: установление соединения, передача сообщений, завершение коммуникации.

Установление соединения осуществляется инициатором путем отправки HTTP запроса определенного формата. Наглядно пример такого запроса можно увидеть на рис. 1. Данный запрос должен иметь метод GET, а также определенные заголовки, про состав и назначение которых можно подробнее прочитать в стандарте [1].

Рисунок 1. Пример запроса для установления WebSocket соединения

При успешном установлении соединения сервер выдает ответ, формат которого можно увидеть на рис. 2.

Рисунок 2. Пример ответа для установления WebSocket соединения

После успешного установления соединения стороны могут начинать обмениваться сообщениями. Сообщение состоит из так называемых фреймов, которые используют TCP фреймы для передачи по сети. За счет того, что полезная информация передается по TCP, при передаче информации не происходит передачи лишних заголовков, Cookie, как было бы в случае использования HTTP в качестве транспорта для двустороннего взаимодействия. В протоколе также описан механизм проверки «жизнеспособности» второй стороны с помощью механизма Ping-Pong.

Для завершения соединения отсылается особый Close фрейм, получив который сторона прекращает отправку и получение любых других фреймов.

Server-Sent Events.

Server-Sent Events - симплексный протокол, отдающий фрагментированный HTTP ответ. Работает он следующим образом. Клиент посылает обычный HTTP запрос на сервер. Сервер возвращает ответ, в заголовках Transfer-Encoding: chunked, Content-Type: text/event-stream и не закрывает соединение сразу, передавая тело ответа по сети частями. Сообщения от сервера приходят в теле ответа текстовом формате в кодировке UTF-8. Разделитель между сообщениями - два символа переноса строки, идущие подряд. Сообщение обязательно имеет данные и опционально - поля id, event. Свойства сообщения разделяются символом перевода строки. Имя свойства от значения отделяется двоеточием. Пример ответа можно увидеть на рис. 3.

Рисунок 3. Пример Server-Sent Event ответа сервера

Сообщения могут быть обработаны до закрытия соединения сервера, поэтому клиент может реактивно реагировать на приходящие события, не дожидаясь завершения HTTP ответа. В основном данный протокол используется для получения уведомлений от сервера.

Описание существующих аналогов решения.

На текущий момент существует несколько распространенных серверов для мокирования. Наиболее популярные - Mountebank [5], MockServer [6], WireMock [7], работают с мокированием HTTP взаимодействия. В данных приложениях отсутствует явная поддержка WebSocket [8, 9]. Однако в обсуждении продукта Mountebank есть предложение, как поддержку можно реализовать самому [9]. Для этого требуется использовать утилиту Websockify, которая занимается установлением WebSocket соединения и его прерыванием и проксирует фреймы передачи сообщений в Mountebank. Это возможно, поскольку Mountebank умеет работать с мокированием TCP. Таким образом, для решения потребуется иметь работающий Mountebank сервер и утилита Websockify. В Mountebank потребуется задать поведение сервера - указать правила для ответа на фреймы, которые приходят от второй стороны WebSocket соединения. У приведенного решения есть ряд проблем. Во-первых, WebSocket сервер может инициировать отправку сообщений в отсутствие сообщений от клиента, что в данной схеме реализовать невозможно (сообщения будут отправляться только в ответ на сообщения клиента). Причиной данной проблемы является то, что Mountebank умеет мокировать только ответы, совершенные в ответ на запрос клиента. Во-вторых, такой вариант тяжело поддерживать, поскольку требуется работать с протоколом на низком уровне TCP фреймов. Для реализации сценария, когда надо по-разному отвечать на разный вид сообщений в WebSocket, описать imposter для Mountebank будет нетривиально. Вариантов реализации сервера для мокирования WebSocket с помощью других существующих решений не было выявлено.

Так как протокол Server-Sent Events является частью спецификации HTTP с определенным набором заголовков и форматом тела ответа, упомянутые мок-сервера для HTTP, способны работать с данным протоколом. Однако есть одна проблема. Все решения отдают тело ответа на запрос полностью, а не частями. То есть, пользователь может сконфигурировать мок-сервер так, чтобы тот на определенный запрос отвечал в формате Server-Sent Events. Но ответ на реальный запрос к мок-серверу придет сразу (демонстрация на рис. 4), что может быть недопустимо в некоторых случаях. Например, если браузер отображает уведомления, которые получил в ответе на запрос, то в случае с таким поведением все уведомления будут отображены в браузере сразу (рис. 4), а не по одному с определенным временным интервалом (рис. 5), как, возможно, хотелось бы разработчику, чтобы протестировать функциональность отображения уведомлений.

Рисунок 4. Схема фактического Server-Sent Events взаимодействия с мок-сервером

мокирование сервер асинхронный

Рисунок 5. Схема желаемого Server-Sent Events взаимодействия с мок-сервером

Таким образом, протоколы WebSocket и Server-Sent Events позволяют асинхронно обмениваться сообщениями между сторонами коммуникации. Современные реализованные утилиты позволяют мокировать данные протоколы лишь со значительными неудобствами и оговорками.

Асинхронные протоколы позволяют сервисам коммуницировать с помощью обмена сообщениями без необходимости ожидания полного ответа от сервиса-собеседника. Протокол Websocket предназначен для дуплексного взаимодействия между сторонами. Протокол Server-Sent Events дает возможность отсылать сообщения только одной стороне взаимодействия.

Серверы для мокирования помогают разработчикам и тестировщикам быстрее разрабатывать прототипы сервисов и тестировать компоненты. В ходе исследования открытых решений для мокирования асинхронных протоколов WebSocket и Server-Sent Events было выявлено, что текущие решения не поддерживают асинхронную природу упомянутых протоколов. Разработанное решение позволяет получить сервер для мокирования асинхронных протоколов WebSocket и Server-Sent Events.

2. Архитектура решения

API сервера.

Для управления мок-сервером требуется предоставить интерфейс (API, программный интерфейс приложения). В качестве основного архитектурного стиля для API был выбран REST. Данный выбор был сделан, поскольку REST широко распространен, прост в понимании и не привязан к определенной технологии или языку программирования. REST (Representational State Transfer) - архитектурный стиль для создания распределенных систем [3]. Согласно ему нужно придерживаться определенного подхода к сетевому интерфейсу систем. В качестве транспортного протокола используется HTTP. Основной единицей является ресурс. У ресурса существует идентификатор - URL, унифицированное имя ресурса, например, http://example.com/user/128. Для осуществления операций с ресурсами нужно осмысленно использовать HTTP глаголы. Для операций чтения - GET, создания новых ресурсов - POST, удаления - DELETE. REST был выбран в качестве основы Согласно упомянутым идеям был разработан следующий интерфейс для разрабатываемого сервера для мокирования асинхронных протоколов. Для создания мока на определенном порту используется запрос POST /mock, в теле которого передается JSON объект-конфигурация поведения мока. Для получения текущей конфигурации используется запрос GET /mock/{port}, где вместо {port} требуется указать числовой идентификатор порта запрашиваемого мока. В теле ответа сервер вернет JSON конфигурацию мока на запрошенном порту, если таковой имеется. Чтобы удалить мок на определенном порту используется запрос DELETE /mock/{port}. В результате запроса мок на заданном порту будет удален, а прежняя конфигурация будет в теле ответа сервера на запрос.

Для облегчения работы с сетевым интерфейсом приложения была описана OpenAPI схема приложения [10]. Ее можно найти в файле swagger.yaml в исходных кодах проекта. OpenAPI схема позволяет описать интерфейс приложения и использовать ее как документацию. Также в сервер был встроен дистрибутив Swagger UI, который упрощает демонстрацию интерфейса приложения с OpenAPI схемой и позволяет наглядно предоставить описанную OpenAPI схему в браузере с возможностью взаимодействия с интерфейсом [11]. Пример отображения Swagger UI интерфейса можно увидеть на рис. 6.

Рисунок 6. Интерфейс Swagger UI, демонстрирующий REST интерфейс приложения

С данным интерфейсом складывается примерно следующая схема работы с сервером. Пользователь описывает мок и создает его на сервере запросом POST /mock. Далее пользователь может проверить мок на заданном порту с помощью запроса GET /mock/{port}. После этого пользователь взаимодействует с созданным моком и при необходимости удаляет свежесозданный мок. Пример схем взаимодействия можно увидеть на рис. 7 и 8.

Рисунок 7. Схема взаимодействия пользователя с сервером для мокирования SSE

Рисунок 8. Схема взаимодействия пользователя с сервером для мокирования WebSocket

Особенности используемых библиотек.

Для работы с запросами к серверу была выбрана библиотека Akka HTTP [12]. Это библиотека для создания HTTP интерфейсов на Scala, которая использует Akka и, соответственно интегрирована для работы с Akka Streams [13]. Данная библиотека позволяет создавать и интерфейсы на основе протоколов WebSocket и Server-Sent Events, что и необходимо для проекта. Библиотека Akka Streams предоставляет абстракции для работы с графами вычислений. В ней существует три основных типа строительных блоков графа. Первый называется Source - блок, у которого есть только один выход, и которые служат источником событий в графе. Еще один тип блоков - Flow. У данного блога есть один вход и один выход. Flow является основным и предназначен для преобразования данных в графе и выполнения действий над сообщениями. Последний основной тип элементов графа - Sink. У него есть только один вход, и служит он для потребления результата вычислений графа. Для примера рассмотрим граф из документации к Akka Streams на рис. 9. Он состоит из четырех блоков. Первый - Source, запускает события в граф из массива чисел 1, 2, 3. Каждое число по очереди попадает во Flow под названием map, в котором производится изменение числа - прибавляется единица. Далее числа проходят через еще один map, в котором умножаются на 2. После этого каждый элемент попадает в Sink ignore, который просто игнорирует все приходящие в него события.

Рисунок 9. Пример графа вычислений Akka Stream

Абстракция графов вычислений, предоставляемая библиотекой удобна для работы с асинхронными потоковыми протоколами, поскольку у данных видов одинаковое представление. Например, WebSocket взаимодействие естественно ложится на граф, похожий на иллюстрацию на рис. 10.

Рисунок 10. Изображение графа взаимодействия WebSocket

В WebSocket есть события от клиента соединения, которые надо обрабатывать (Flow), возможно, производя события в ответ, при этом также могут быть свои Source-источники событий. В итоге получается граф с событиями между двумя пользователями.

Для протокола Server-Sent Events граф получается гораздо проще, поскольку в нем взаимодействие однонаправленное. Демонстрацию можно увидеть на рис. 11.

Рисунок 11. Изображение графа взаимодействия Server-Sent Events

Для протокола Server-Sent Events требуется предоставить только Source источник событий, которые будут отправлены клиенту по сети.

Одной из особенностей использованных фреймворков для формирования API решения является подход библиотеки Akka HTTP к описанию REST интерфейса приложения. Для одинаковых функций библиотеки вместо переопределения методов используется паттерн магнит. Основная идея данного паттерна заключается в определении метода с параметром, типизированным интерфейсом, в свою очередь параметризованным типом результата метода. Для демонстрации возьмем пример из статьи про данный паттерн одного из авторов библиотеки Akka HTTP [14]. Подобная конструкция работает как привычная перегрузка метода, однако лишена некоторых ее таких недостатков, как коллизия переопределенных методов в результате стирания типов в обобщенных типах, дублирования кода в похожих переопределениях. Объект, передаваемый в метод будет неявно преобразован в реализацию интерфейса параметра метода из неявных методов, определенных в объекте-компаньоне, и передан непосредственно в метод.

Данный подход к методам библиотеки позволяет красиво и емко описывать сетевой интерфейс приложения. В примере далее можно увидеть описание REST интерфейса управления моками сервера.

val adminRoute: Route = pathPrefix("mock") {

(post & entity(as[MockConfiguration])) { stub =>

onSuccess(endpointManager.addMock(stub)) {

complete(StatusCodes.Created, s"Created a mock on port ${stub.port}")

}

} ~

pathPrefix(IntNumber) { port =>

get {

complete(endpointManager.getMock(port))

} ~

delete {

complete(endpointManager.deleteMock(port))

}

}

}

Пример работы с решением.

Далее будет описан пример работы с сервером для мокирования асинхронных протоколов для наглядного понимания его сущности.

Запустим сервер. Для мока будем использовать следующую конфигурацию поведения:

{

"port": 5000,

"stubs": [

{

"predicates": [],

"responses": [

{

"events": [

{

"data": "Hello World!",

"delay": "1 second"

}

],

"type": "sse"

}

]

}

]

}

В данной конфигурации сервер посылает одно Server-Sent Events событие с текстом “Hello World!” с задержкой в одну секунду в ответ на запрос на порт сервера 5000. Для того, чтобы добавить данный мок, надо отправить следующий запрос к серверу, например, с помощью консольной утилиты curl [15], для этого в консоли введем:

curl -X POST "http://localhost:2525/mock" -H "accept: */*" -H "Content-Type: application/json" -d "{\"port\":5000,\"stubs\":[{\"predicates\":[],\"responses\":[{\"events\":[{\"data\":\"Hello World!\",\"delay\":\"1 second\"}],\"type\":\"sse\"}]}]}"

Убедимся, что сервер корректно добавил мок, и отсылает сообщение “Hello World!” с задержкой в одну секунду также с помощью утилиты curl:

curl localhost:5000

Утилита примерно через секунду печатает в консоль следующий вывод:

data:"Hello World!"

Данный текст в теле ответа является корректным Server-Sent Events сообщением с текстом “Hello World!”, что и было задано конфигурацией мока.

Для сетевого интерфейса сервера для управления моками был выбран REST подход. С его использованием был разработан интерфейс с методами добавления моков, удаления и получения мока по порту, на котором он был установлен. Также была разработана OpenAPI схема, которая используется в Swagger UI - утилите, позволяющая наглядно отобразить REST интерфейс приложения в любом современном браузере.

Для реализации сервера были выбраны библиотеки Akka Http и Akka Streams, поскольку они предоставляют удобные абстракции для работы с сетевым взаимодействием и асинхронными протоколами. Также в данной главе были описаны основные особенности выбранных библиотек.

Также в данной главе был разобран пример работы с сервером для мокирования асинхронных протоколов, демонстрирующий базовую функциональность решения.

3. Технические детали реализации

Компоненты реализации.

Реализация содержит четыре основных компоненты. Компонента controller содержит классы и утилиты, работающие с сетевым интерфейсом сервера, логику обработки сетевых запросов на основании абстракций других компонент. В данной компоненте также присутствует логика предоставления интерфейса Swagger UI и Open API схемы.

Компонента manager содержит абстракции для управления поведения сервера на портах - добавление мока, удаление, получение мока по порту.

Компонента configuration содержит классы и утилиты для работы с конфигурациями поведения сервера. Центральная абстракция - MockConfiguration является базовым интерфейсом, реализации которого будут непосредственно являться описанием для задания поведения сервера. Компонента json содержит реализации классов для сериализации и десериализации JSON объектов в объекты MockConfiguration. Компонента route содержит реализации абстракций, которые по данному инстансу MockConfiguration создают route объект, являющийся объектом фреймворка Akka Http для обработки сетевых запросов. То есть, в Routable содержатся реализации объектов, преобразующих описание поведения сервера непосредственно в имплементацию данного поведения. Диаграмму компонентов можно увидеть на рис. 12.

Представленное разделение компоненты configuration необходимо для разделения независимой логики парсинга JSON описания поведения сервера и непосредственной реализации данного поведения. В первом случае используются абстракции библиотеки Circe. В singleton объекте JsonUtils объявлены implicit реализации соответствующих абстракций Encoder и Decoder для всех типов конфигураций поведения сервера. При необходимости их использования достаточно импортировать внутреннее содержимое объекта JsonUtils, и implicit реализации будут использованы для сериализации и десериализации объектов поведения сервера. Механизм Routable не является частью использованных фреймворков. Routable является интерфейсом, реализация которого должна уметь преобразовывать тип в абстракцию Route. Также singletone объект Routable содержит реализации данного интерфейса для всех реализаций MockConfiguration, что позволяет работать с любой конфигурацией поведения сервера.

Рисунок 12. Диаграмма компонентов реализации

Основные абстракции реализации.

Далее будут описаны основные классы, используемые для реализации сервера для мокирования асинхронных протоколов.

AdminMockController.

Данный класс отвечает за обработку HTTP запросов, управляющих работой сервера - добавление моков, удаление, получение мока по порту.

В параметрах конструктора принимает реализацию MockEndpointManager и порт, который приложение будет слушать для обработки входящих запросов по управлению сервером.

Данный класс имеет методы start и stop для соответственно старта сервера и его завершения. При завершении сервера происходит также остановка всех моков с их портов.

При получении метода POST на путь /mock происходит десериализация объекта MockConfiguration из тела запроса и вызов метода addMock реализации MockEndpointManager. При GET и DELETE запросах на путь /mock/{port}, где {port} - числовой идентификатор порта сервера, происходит вызов методов getMock и deleteMock реализации MockEndpointManager соответственно.

MockEndpointManager.

Данный интерфейс нужен для управления моками серверов на портах приложения. Он имеет следующие методы: addMock для добавления мока, deleteMock для удаления мока, getMock для получения мока по номеру порта, deleteMocks для удаления всех моков, которые были добавлены данным менеджером моков.

У данного интерфейса имеется одна реализация MockEndpointManagerImpl, которая реализует данный интерфейс. Данный класс использует реализацию конкурентной мутируемой хеш-таблицы TrieMap для хранения соответствия порта и мока. Изначально данная хеш-таблица пустая. Таким образом, при любом взаимодействии с объектом класса проверяется, занят или не занят ли данный порт в зависимости от семантики вызываемого метода.

При вызове метода addMock полученный mock преобразуется в Route с помощью реализации Routable[MockConfiguration], которая представлена в Routable объекте. Так как Route является абстракцией фреймворка Akka Http для обработки HTTP запросов, он и используется для установки мока на порту.

Также в хранилище портов соответствия мокам добавляется новая запись с соответствующим моком и результата так называемого связывания порта и мока для последующей возможности удаления мока.

Далее можно увидеть реализацию добавления мока:

val route = mock.toRoute(Routable.mockRoutable)

for {

binding <- Http().bindAndHandle(handler = loggerDirective(route), port = mock.port, interface = "0.0.0.0")

_ = portBindings += mock.port -> (binding, mock)

_ = logger.info(s"Successfully bound on port ${mock.port}")

} yield ()

При вызове метода deleteMock из хеш-таблицы моков достается мок по порту, и происходит отвязывание сервера от порта:

for {

bindingOpt <- Future.successful(portBindings.remove(port))

(binding, mock) = bindingOpt.getOrElse(throw NoEndpointStartedOnPort(port))

_ <- binding.unbind()

_ = logger.info(s"Endpoint on $port successfully stopped")

} yield mock

При вызове метода getMock, мок берется из хранилища моков, и возвращается вызывающему коду. Если мок на данном порту отсутствует, выбрасывается соответствубщая ошибка.

override def getMock(port: Int): Future[MockConfiguration] = for {

bindingOpt <- Future.successful(portBindings.get(port))

(_, mock) = bindingOpt.getOrElse(throw NoEndpointStartedOnPort(port))

} yield mock

Метод deleteMocks извлекает все моки, хранящиеся в данном объекте, и производит их отвязывание от портов:

override def deleteMocks: Future[Seq[MockConfiguration]] = {

val bindings = portBindings.values.toSeq

val unbindingsFuture = bindings.map { case (binding, configuration) =>

binding.unbind()

.map(_ => configuration)

}

Future.sequence(unbindingsFuture)

.andThen { case Success(_) => portBindings.clear() }

}

MockConfiguration.

Данный интерфейс является базовым для всех конфигураций моков, которые реализованы в решении. В данном интерфейсе имеется только одно поле - целочисленное поле port, которое означает порт, на котором мок будет существовать.

StubConfiguration.

Данный класс является реализацией интерфейса MockConfiguration и состоит из множества ответов типа Stub, которые описывают поведение ответов сервера. Данная конфигурация возвращает первый ответ, всем предикатам которого удовлетворяет входящий запрос.

ResponseStub.

Данный класс является реализацией интерфейса Stub, содержащий множество ответов и предикатов. Ответы - описания ответов, которые сервер отправляет на входящие запросы. Предикаты - описания правил, определяющих применимость данных ответов на запрос. Если множество ответов имеет размер больше одного, то при последовательных запросах, удовлетворяющих предикатам, ответы будут возвращаться циклично по порядку их описания в конфигурации. Так, если конфигурация содержит два ответа, то первый пришедший запрос получит первый ответ, второй пришедший запрос - второй, третий пришедший запрос - опять первый.

HttpPredicate

Данный интерфейс позволяет необходим для определения применимости ответа входящему запросу в ResponseStub. Диаграмма классов предикатов для Http запросов можно увидеть на рис. 13.

Рисунок 13. Диаграмма классов предикатов HttpPredicate

От базового HttpPredicate наследуются два интерфейса LeafHttpPredicate и CompoundHttpPredicate. LeafHttpPredicate является элементарным предикатом, который содержит некоторое ожидание RequestExpectation и проверяет соответствие входящего запроса этому ожиданию. Реализации данного интерфейса: Equals, StartsWith, Contains - соответственно проверяют, что содержимое входящего равняется, начинается или содержит ожидание.

CompoundHttpPredicate содержит множество других HttpPredicate и либо применяет логическую операцию И (And) и ИЛИ (Or).

Ожидания к входящему запросу реализованы интерфейсом RequestExpectation. Данный интерфейс реализуют классы BodyExpectation, PathExpectation, MethodExpectation, QueryExpectation. BodyExpectation содержит ожидание к содержимому тела входящего запроса. PathExpectation содержит одидание к пути входящего запроса. MethodExpectation - к методу, а Query - к параметрам запроса.

Response

Данный интерфейс является базовым для определения ответа сервера на запрос. Интерфейс EventsSequenceLikeResponse наследуется от Response и представляет ответ, состоящий из сообщений, отправляемых асинхронно, с возможной задержкой. Диаграмму классов, связанных с Response можно увидеть на рис. 14.

Рисунок 14. Диаграмма классов конфигурации ответов

SseEventsResponse

Данный класс реализует интерфейс EventsSequenceLikeResponse и является конфигурацией ответов по протоколу Server-Sent Events. Он содержит последовательность событий протокола Server-Sent Events и опциональный таймаут - время, по истечении которого соединение закрывается автоматически.

WebSocketEventsResponse

Данный класс реализует интерфейс EventsSequenceLikeResponse и является конфигурацией ответов по протоколу Websocket. Он содержит последовательность событий протокола Websocket, последовательность реакций на приходящие запросы и опциональный таймаут - время, по истечении которого соединение закрывается автоматически.

WsReaction

Данный класс содержит описание одной реакции на сообщение пользователя в протоколе WebSocket. Данный класс состоит из множества предикатов и последовательности событий. При удовлетворении всех предикатов реакции, в ответ будет отправлена данная последовательность событий.

WsEventPredicate

Данный интерфейс по семантике и реализации очень похож на HttpPredicate, однако имеет более простую структуру за счет не такого большого количества параметров WebSocket сообщения в сравнении с HTTP запросом. Диаграмму классов WsEventPredicate можно увидеть на рис. 15.

Рисунок 15. Диаграмма классов реакций на Websocket сообщения от клиента

JsonMessagePredicate наследуется от интерфейса WsEventPredicate и предоставляет реализацию предиката на основе функции сравнения двух строк. Наследникам данного интерфейса: WsEquals, WsContains, WsStartsWith - достаточно переопределить comparator и описать логику предиката сравнения входящей строки и ожидаемой.

Интерфейс CompoundWsPredicate наследуется от WsEventPredicate и содержит множество предикатов, аггрегируя их логической функцией И (And) или ИЛИ (Or).

Routable

Данный интерфейс параметризуется типом, преобразование которого к типу Route будет производиться. То есть, объект с типом Routable[Any] будет иметь метод toRoute, преобразующий объект типа Any в объект Route. Объект RoutableSyntax добавляет любому типу метод toRoute, если в скоупе вызывающего кода будет существовать соответствующая реализация интерфейса Routable. Например, метод toRoute можно будет использовать у объекта типа Any, если в той же области видимости будет определен implicit val routableAnyImpl: Routable[Any].

В объекте Routable содержатся реализации Routable интерфейса для всех конфигураций моков, с которыми работает сервер для мокирования асинхронных протоколов. Для StubConfiguration все элементы конфигураций преобразуются к Route и конкатенируются между собой с помощью метода fold, определенного над Scala коллекциями, осуществляя операцию конкатенации попарно над всеми элементами коллекции:

configuration.stubs.map(_.toRoute).fold(reject)(_ ~ _)

Для Routable[Response] требуется создать Route, который будет отдавать асинхронно последовательность событий и обрабатывать входящие события в случае WebSocket. Разберем случай с Websocket, поскольку он требует обработки входящих сообщений от клиента. Сначала происходит преобразование событий от сервера в Source.

val source = DelayedSource.createMessageLike(response.events)

.map(_.toWs)

Далее происходит преобразование описания обработчика входящих событий от клиента в Flow:

val incomingMessagesHandler = WsReaction.toFlow(response.reactions)

И осуществляется преобразование в граф потока событий для WebSocket соединения:

handleWebSocketMessages(incomingMessagesHandler.merge(source))

Схему получившегося графа можно увидеть на рис. 16:

Рисунок 16. Схема реализации графа для обработки WebSocket соединения

DelayedSource

Данный класс является вспомогательным и позволяет создать граф событий, в котором данные события приходят с определенной задержкой с соблюдением их последовательности. В итоге необходимо получить Source[Event], где Event - тип исходящих сообщений графа. Для решения данной проблемы было решено использовать итеративный подход. Необходимо хранить аккумулятор, состоящий из результирующего Source и суммарной задержки на данный момент. При добавлении очередного события, создается новый Source из одного элемента с суммарной задержкой из аккумулятора и задержкой для текущего события. Далее этот Source конкатенируется с Source из аккумулятора, что позволяет иметь нужную итоговую последовательность событий с задержкой. В итоге извлекаем получившийся Source из аккумулятора. Код алгоритма выглядит следующим образом:

case class Accumulator(delay: FiniteDuration, source: Source[T, NotUsed])

events.foldLeft(Accumulator(0.millis, Source.empty[T])) { case (accumulator, (element, delay)) =>

val newDelay = accumulator.delay + delay

val newElementSource = Source.single(element).delay(newDelay, DelayOverflowStrategy.backpressure)

Accumulator(newDelay, accumulator.source.concat(newElementSource))

}.source

Схематично результирующий граф изображен на рис. 17.

Рисунок 17. Схема итогового графа событий с задержкой

В данной главе были описаны основные компоненты реализации и базовые классы. Также были продемонстрированы особенности реализованных алгоритмов и архитектура определенных важных моментов имплементации.

Заключение

Сервера для мокирования являются дополнительным инструментом разработчика и тестировщика при создании программных систем. Они позволяют увеличить скорость разработки прототипов, помогают при тестировании тяжело воспроизводимых сценариев и дают больше независимости различным командам разработчиков.

В рамках данной выпускной квалификационной работы был создан сервер для мокирования асинхронных протоколов WebSocket и Server-Sent Events. Необходимость в данной разработке продиктована отсутствием поддержки асинхронной природы этих протоколов в существующих решениях. При реализации были использованы библиотеки Akka Http и Akka Streams.

В процессе выполнения выпускной квалификационной работы были решены следующие задачи:

1. Изучены имеющиеся аналоги серверов для мокирования. Были рассмотрены наиболее популярные решения Mountebank, MockServer, WireMock. Также в 1 главе были описаны возможные решения для мокирования WebSocket и Server-Sent Events и их недостатки.

2. Изучены особенности протоколов WebSocket и Server-Sent Events. Были прочитаны стандарты данный протоколов и описаны основные особенности в 1 главе.

3. Реализован сервер для мокирования WebSocket и Server-Sent Events. Было разработано решение для мокирования упомянутых протоколов.

4. Подготовлена техническая документация. Была разработана документация по ГОСТ.

5. Выложен исходный код приложения и техническая документация на GitHub под открытой лицензией. Исходный код решения был выложен в личном репозитории на GitHub под лицензией Apache-2.0 [16].

В качестве развития созданного решения планируется размещение документации к функциональности сервера с примерами использования в сети интернет. Это поможет снизить порог вхождения в использование сервера и упростить его использование. Также планируется внедрить использование сервера в другие проекты на работе, собрать недостающую функциональность и доработать решение с учетом полученных замечаний.

Литература

1. Fette I. The WebSocket Protocol [Электронный ресурс] / I. Fette, A. Melnikov. Режим доступа: https://tools.ietf.org/html/rfc6455, свободный. (дата обращения: 20.11.2018).

2. Loreto S. Known Issues and Best Practices for the Use of Long Polling and Streaming in Bidirectional HTTP [Электронный ресурс] / S. Loreto, P. Saint-Andre, S. Salsano, G. Wilkins. Режим доступа: https://tools.ietf.org/rfc/rfc6202.txt. (дата обращения: 12.04.2019).

3. Patni S. Pro RESTful APIs / S. Patni. - Apress. - Berkeley, CA.

4. Spadini D. To Mock or Not to Mock? An Empirical Study on Mocking Practices / D. Spadini, M. Aniche, M. Bruntink, A. Bacchelli // IEEE International Working Conference on Mining Software Repositories. - 2017. 402-412 с.

5. Mountebank - over the wire test doubles [Электронный ресурс]: mbtest. Режим доступа: http://www.mbtest.org, свободный. (дата обращения: 19.11.2018).

6. MockServer [Электронный ресурс]: MockServer. Режим доступа: http://www.mock-server.com, свободный. (дата обращения: 19.11.2018).

7. WireMock [Электронный ресурс]: Wiremock.org. Режим доступа: http://wiremock.org, свободный. (дата обращения: 27.01.2019).

8. Support WebSockets mocking [Электронный ресурс]: Github. Режим доступа: https://github.com/jamesdbloom/mockserver/issues/360, свободный. (дата обращения: 12.04.2019).

9. WebSocket Support - Группы Google [Электронный ресурс]: Google.com. Режим доступа: https://groups.google.com/forum/#!topic/mountebank-discuss/t19u-sc8b6E, свободный. (дата обращения: 15.01.2019).

10. About Swagger Specification | Documentation | Swagger | Swagger [Электронный ресурс]: Swagger. Режим доступа: https://swagger.io/docs/specification/about, свободный. (дата обращения: 16.04.2019).

11. Swagger UI | API Development Tools | Swagger [Электронный ресурс]: Swagger. Режим доступа: https://swagger.io/tools/swagger-ui, свободный. (дата обращения: 16.04.2019).

12. Akka HTTP [Электронный ресурс]: Akka. Режим доступа: https://doc.akka.io/docs/akka-http/current/, свободный. (дата обращения: 20.11.2018).

13. Streams * Akka Documentation [Электронный ресурс]: Akka. Режим доступа: https://doc.akka.io/docs/akka/current/stream/index.html, свободный. (дата обращения: 20.11.2018).

14. The Magnet Pattern [Электронный ресурс]: Spray. Режим доступа: http://spray.io/blog/2012-12-13-the-magnet-pattern/, свободный. (дата обращения: 18.04.2019).

15. curl [Электронный ресурс]: curl. Режим доступа: https://curl.haxx.se/, свободный. (дата обращения: 07.05.2019).

16. Apache License, Version 2.0 [Электронный ресурс]: Apache. Режим доступа: https://www.apache.org/licenses/LICENSE-2.0, свободный. (дата обращения: 14.05.2019).

Размещено на Allbest.ru

...

Подобные документы

  • Изучение истории развития, назначения, архитектуры и протоколов сетевой беспроводной технологии интернет Wi-Fi. Характеристика системы для быстрого обмена сообщениями и информацией Jabber. Анализ методов работы с ней, взаимодействия клиента и сервера.

    реферат [756,0 K], добавлен 27.05.2012

  • Понятие и общие характеристики протоколов NetWare: основы технологии, доступ к среде, сетевой и транспортный уровень. Инсталляция сетевых протоколов и продуктов, принципы и этапы. Порядок и цели установки свойств сервера для рабочих станций Windows.

    курсовая работа [2,3 M], добавлен 19.12.2013

  • Общая характеристика протокола ICMP, его назначение и формат сообщений. Анализ применимости протокола ICMP при переходе с набора протоколов IP v4 на набор IP v6. Свойства и принцип работы, сферы применения протоколов обмена маршрутной информацией.

    курсовая работа [210,8 K], добавлен 24.08.2009

  • Электронная почта – средство обмена информацией; администрирование почтового сервера. Протоколы принудительной доставки почты. Создание и настройка виртуального сервера, параметры его конфигурации. Управление входящими сообщениями и почтовыми ящиками.

    презентация [296,8 K], добавлен 10.11.2013

  • Разработка программы для тестирования студентов в интегрированной среде разработки Lazarus. Создание формы, отображение графического изображения, выхода, ответа, завершения теста. Процесс выбора ответа студентом. Исходный вид программы тестирования.

    курсовая работа [388,4 K], добавлен 23.12.2014

  • Файловая и сетевая системы операционной системы Windows. Характеристика модели "клиент-сервер". Функциональные требования и архитектура программы, которая должна обеспечивать передачу файлов от клиента к серверу, сервера к клиенту, обмен сообщениями.

    курсовая работа [1,4 M], добавлен 24.04.2013

  • ASP – внутренняя технология, позволяющая подключать программы к web-страницам и обеспечивать чтение и запись в базе данных. Код разработанной ASP-страницы и его описание. Внешний вид полученного ответа на запуск ASP-страницы. HTML-код файла отчета.

    лабораторная работа [219,1 K], добавлен 05.04.2015

  • Описание принципов функционирования протоколов, используемых во всемирной сети. Характеристика структуры и особенностей работы Интернета. Преимущества использования электронной почты, IP-телефонии, средств мгновенного обмена сообщениями (ICQ, Skype).

    реферат [1,2 M], добавлен 23.04.2011

  • Функции технологии Ajax разработки Web-приложений: выполнение HTTP-запросов в клиентской части и анализ ответа XML-сервера. Создание данных объекта XMLHttpRequest для разных браузеров. Обработка с помощью сервлета. Функциональность задач в Ajax.

    лабораторная работа [54,8 K], добавлен 06.06.2009

  • Разработка программы FTP-клиент, которая может подключаться к серверу в активном и пассивном режимах, используя имя пользователя и пароль; скачивать, загружать и удалять файлы с сервера. Протоколы прикладного и транспортного уровней. Описание интерфейса.

    курсовая работа [149,2 K], добавлен 07.07.2013

  • Понятие "Интернет" и его роль в современном мире. Понятие протоколов сетевого взаимодействия. Схема потока данных сквозь стек протоколов от приложения-клиента на одном компьютере к приложению-серверу на другом. Основные элементы технологии WWW.

    презентация [248,0 K], добавлен 19.09.2016

  • Подключение к серверу баз данных, основные функции. Использование PHP в сочетании с сервером Apache. Закрытие соединения, осуществляемое с помощью функции mysql_close. Обработка ошибок подключения к серверу. Создание таблицы, выполнение SQL-запроса.

    презентация [130,8 K], добавлен 21.06.2014

  • Способы аутентификации пользователей: через протокол SSH, по публичному ключу и паролю. Характеристика сервера телефонии Asterisk, архитектура протокола XMPP. Разработка скрипта, автоматизирующего процесс анализа попыток взлома сервера из внешней сети.

    курсовая работа [341,8 K], добавлен 26.02.2013

  • Циклы обмена информацией в режиме прямого доступа к памяти. Управляющие сигналы, формируемые процессором и определяющие моменты времени. Запросы на обмен информацией по прерываниям. Мультиплексирование шин адреса и данных. Протоколы обмена информацией.

    лекция [29,0 K], добавлен 02.04.2015

  • Модели и протоколы передачи данных. Эталонная модель OSI. Стандартизация в области телекоммуникаций. Стеки протоколов и стандартизация локальных сетей. Понятие открытой системы. Internet и стек протоколов TCP/IP. Взаимодействие открытых систем.

    дипломная работа [98,9 K], добавлен 23.06.2012

  • Характеристика разновидностей программной реализации чатов. Разработка программы клиент-серверного чата с возможность общения в локальной сети нескольких человек одновременно. Протокол взаимодействия клиента и сервера. Порядок работы с программой.

    курсовая работа [530,7 K], добавлен 25.04.2015

  • Просмотр сведений о сетевых подключениях компьютера с помощью ОС Windows. Установление параметров сетевых протоколов (команда ipconfig), отчет об использовании. Разрешение имен NetBios. Проверка IP-адресов, трассировка маршрутов, команды сети NET.

    лабораторная работа [1,6 M], добавлен 11.09.2013

  • Обоснование необходимости создания сети, разработка ее архитектуры. Выбор активного и пассивного оборудования, сетевой карты, сервера и рабочей станции. Проектирование кабельных систем, выбор программного обеспеченья для сервера и рабочей станции.

    курсовая работа [1,3 M], добавлен 09.09.2013

  • Технология автоматизированного обмена электронными сообщениями в стандартизированных форматах между бизнес-партнерами. Стандарты, технология работы, гарантии достоверности и конфиденциальности ЕDI. Электронные средства платежа. Начало и процесс перевода.

    реферат [2,7 M], добавлен 06.10.2013

  • Типовые угрозы и уязвимости для сервера резервного копирования сетевой файловой системы. Организационные меры по защите сервера: средства криптографической защиты и контроля целостности; антивирусное программное обеспечение; встроенные средства защиты ОС.

    курсовая работа [489,6 K], добавлен 28.08.2012

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.