Added project
This commit is contained in:
62
README.md
62
README.md
@@ -1,4 +1,62 @@
|
|||||||
# Linkchecker
|
# Linkchecker
|
||||||
|
|
||||||
Тестовое задание. Разработать REST-сервис, проверяющий работоспособность любой последовательности узлов. Каждый узел имеет уникальное имя,
|
## Оригинальный текст задания
|
||||||
вероятность, с которой откажет при обращении к нему, и счетчик успешно выполненных запросов.
|
|
||||||
|
Разработать REST-сервис, проверяющий работоспособность любой последовательности узлов.
|
||||||
|
Каждый узел имеет уникальное имя, вероятность, с которой откажет при обращении к нему, и счетчик успешно выполненных запросов.
|
||||||
|
|
||||||
|
Сервис должен реализовывать два POST-метода:
|
||||||
|
|
||||||
|
1. setNodes устанавливает граф из узлов, описанных выше. Формат входных данных - JSON.
|
||||||
|
Программа должна исключать циклические связи узлов.
|
||||||
|
2. checkRoute принимает набор вершин (или их идентификаторов) в формате JSON
|
||||||
|
и проходит по этим вершинам, проверяя на каждом пройденном узле, не отказал ли он.
|
||||||
|
Если путь существует в графе и ни один из узлов пути не отказал, следует увеличить счетчик
|
||||||
|
в каждом из узлов пути. В противном случае отображать ошибку в ответе POST-метода (произвольный формат).
|
||||||
|
3. Узлы и связи должны храниться в базе данных.
|
||||||
|
|
||||||
|
## Изменённый вариант задания
|
||||||
|
|
||||||
|
После введённых корректировок, итоговый вид тестового задания выглядит следующим образом:
|
||||||
|
|
||||||
|
Разработать REST-сервис, проверяющий работоспособность любой последовательности узлов.
|
||||||
|
|
||||||
|
1. Каждый узел имеет уникальное имя и счетчик успешно выполненных запросов,
|
||||||
|
так же для хранения в базе данных есть уникальный идентификатор, который
|
||||||
|
присваивается автоматически при записи в БД. Был исключен элемент вероятность отказа узла.
|
||||||
|
Этот параметр перестал быть нужным, так как вероятность отказа узла стала случайным фактором,
|
||||||
|
возникающая автоматически, во время проверки последовательности узлов.
|
||||||
|
1. Граф в программе неориентированный, т.е. вершины графа связаны друг с другом рёбрами,
|
||||||
|
не имеющими направления. В базе данных, хранение графа осуществляется в двух таблицах.
|
||||||
|
В одной таблице осуществляется хранение набора узлов графа, в другой набор рёбер графа.
|
||||||
|
Более подробно смотрите запись в wiki [Описание данных](./../wikis/Описание%20данных)
|
||||||
|
1. Программа позволяет делать следующее:
|
||||||
|
1. Работать с графом обобщённо:
|
||||||
|
1. Создавать новый граф (при этом информация о прежнем графе будет удалена с БД)
|
||||||
|
1. Извлекать информацию о графе в заданном формате
|
||||||
|
1. Удалять целиком весь граф
|
||||||
|
1. Проверять работоспособность заданной последовательности узлов
|
||||||
|
(по условию задачи) выполнив соответствующий запрос.
|
||||||
|
1. Работать с узлами и ребрами по отдельности, т.е. добавлять, удалять,
|
||||||
|
искать информацию по заданным параметрам. Ручное изменение какой-либо информации о узле и ребре не предусмотрена,
|
||||||
|
т.е. возможно либо добавления узла или ребра в БД или удаление из БД)
|
||||||
|
|
||||||
|
Так как по условию задания, граф должен исключить все виды циклов
|
||||||
|
(т.е. граф должен быть ациклическим), то при любом запросе информации о графе целиком
|
||||||
|
или при проверки набора заданных узлов будет, происходить автоматический поиск
|
||||||
|
и удаление циклов из графа. Удаление циклов происходит при помощи удаления набора рёбер,
|
||||||
|
создающие циклы, поэтому в случае обнаружения циклов в графе, набор рёбер графа будет
|
||||||
|
изменён и данные изменения попадут в БД.
|
||||||
|
|
||||||
|
Автоматический поиск и удаление циклов не срабатывает, если происходит работа только
|
||||||
|
с набором данных рёбер графа в отдельности, т.е. можно добавлять в базу рёбра,
|
||||||
|
образующие циклы.
|
||||||
|
|
||||||
|
**Используемый стек** : **Spring Boot**, **Spring Data**, **ORM (Hibernate)**,
|
||||||
|
[**JGraphT**](https://jgrapht.org/) (для работы с графом),
|
||||||
|
**GSON** (используется вместо используемого по умолчанию Jackson для работы с json),
|
||||||
|
**Thymeleaf** и **Bootstrap** (используется для формирования стартовой информационной страницы),
|
||||||
|
**Mockito** (идёт вместе с Spring Boot),
|
||||||
|
**Powermock** (подключается отдельной библиотекой, используется в дополнении к mockito для тестов)
|
||||||
|
|
||||||
|
**Хранилище данных** : PostgeSQL (для production), H2 (для тестов)
|
||||||
15
TestRESTful/Edges/addEdge.http
Normal file
15
TestRESTful/Edges/addEdge.http
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
POST http://localhost:8080/rest/v1/graph/edges/create
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
{"nodeOne": "v6", "nodeTwo": "v7"}
|
||||||
|
|
||||||
|
###
|
||||||
15
TestRESTful/Edges/addEdges.http
Normal file
15
TestRESTful/Edges/addEdges.http
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
POST http://localhost:8080/rest/v1/graph/edges/create/byBatch
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
[{"nodeOne": "v2", "nodeTwo": "v6"}, {"nodeOne": "v6", "nodeTwo": "v7"}, {"nodeOne": "v7", "nodeTwo": "v8"}]
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/Edges/deleteAllEdges.http
Normal file
13
TestRESTful/Edges/deleteAllEdges.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/edges
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/Edges/deleteEdgeById.http
Normal file
13
TestRESTful/Edges/deleteEdgeById.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/edges/byId/5005
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/Edges/deleteEdgeByName.http
Normal file
13
TestRESTful/Edges/deleteEdgeByName.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/edges/byName/v1
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/Edges/deleteEdgeByNames.http
Normal file
13
TestRESTful/Edges/deleteEdgeByNames.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/edges/byName?nodeOne=v3&nodeTwo=v4
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/Edges/getEdgeById.http
Normal file
12
TestRESTful/Edges/getEdgeById.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/edges/byId/5050
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/Edges/getEdgeByNames.http
Normal file
12
TestRESTful/Edges/getEdgeByNames.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/edges/byName?nodeOne=v1&nodeTwo=v2
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/Edges/getEdges.http
Normal file
12
TestRESTful/Edges/getEdges.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/edges
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/Edges/getEdgesByName.http
Normal file
12
TestRESTful/Edges/getEdgesByName.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/edges/byName/v1
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
15
TestRESTful/Nodes/addNode.http
Normal file
15
TestRESTful/Nodes/addNode.http
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
POST http://localhost:8080/rest/v1/graph/nodes/create
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
{"name":"v6"}
|
||||||
|
|
||||||
|
###
|
||||||
15
TestRESTful/Nodes/addNodes.http
Normal file
15
TestRESTful/Nodes/addNodes.http
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
POST http://localhost:8080/rest/v1/graph/nodes/create/byBatch
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
[{"name":"6"}, {"name":"v7"}, {"name":"v8"}]
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/Nodes/deleteAllNodes.http
Normal file
13
TestRESTful/Nodes/deleteAllNodes.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/nodes
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/Nodes/deleteNodeById.http
Normal file
13
TestRESTful/Nodes/deleteNodeById.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/nodes/byId/5010
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/Nodes/deleteNodeByName.http
Normal file
13
TestRESTful/Nodes/deleteNodeByName.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/nodes/byName/6
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
15
TestRESTful/Nodes/deleteNodeByObject.http
Normal file
15
TestRESTful/Nodes/deleteNodeByObject.http
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph/nodes/byObj
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
{"id": 5003, "name": "v4"}
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/Nodes/getNodeById.http
Normal file
12
TestRESTful/Nodes/getNodeById.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/nodes/byId/5000
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/Nodes/getNodeByName.http
Normal file
12
TestRESTful/Nodes/getNodeByName.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/nodes/byName/v1
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/Nodes/getNodes.http
Normal file
12
TestRESTful/Nodes/getNodes.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/nodes
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
41
TestRESTful/addGraph_1.http
Normal file
41
TestRESTful/addGraph_1.http
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
POST http://localhost:8080/rest/v1/graph/create
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{"name":"v1"},
|
||||||
|
{"name":"v2"},
|
||||||
|
{"name":"v3"},
|
||||||
|
{"name":"v4"},
|
||||||
|
{"name":"v5"},
|
||||||
|
{"name":"v6"},
|
||||||
|
{"name":"v7"},
|
||||||
|
{"name":"v8"},
|
||||||
|
{"name":"v9"},
|
||||||
|
{"name":"v10"}
|
||||||
|
],
|
||||||
|
"edges":[
|
||||||
|
{"nodeOne":"v1","nodeTwo":"v2"},
|
||||||
|
{"nodeOne":"v1","nodeTwo":"v3"},
|
||||||
|
{"nodeOne":"v1","nodeTwo":"v4"},
|
||||||
|
{"nodeOne":"v1","nodeTwo":"v5"},
|
||||||
|
{"nodeOne":"v2","nodeTwo":"v3"},
|
||||||
|
{"nodeOne":"v2","nodeTwo":"v4"},
|
||||||
|
{"nodeOne":"v2","nodeTwo":"v5"},
|
||||||
|
{"nodeOne":"v3","nodeTwo":"v4"},
|
||||||
|
{"nodeOne":"v3","nodeTwo":"v5"},
|
||||||
|
{"nodeOne":"v4","nodeTwo":"v5"},
|
||||||
|
{"nodeOne":"v6","nodeTwo":"v7"},
|
||||||
|
{"nodeOne":"v7","nodeTwo":"v8"},
|
||||||
|
{"nodeOne":"v8","nodeTwo":"v9"},
|
||||||
|
{"nodeOne":"v8","nodeTwo":"v10"},
|
||||||
|
{"nodeOne":"v9","nodeTwo":"v10"},
|
||||||
|
{"nodeOne":"v10","nodeTwo":"v7"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
<> 2019-04-05T122503.200.json
|
||||||
|
<> 2019-04-05T122347.405.html
|
||||||
|
|
||||||
|
###
|
||||||
27
TestRESTful/addGraph_2.http
Normal file
27
TestRESTful/addGraph_2.http
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
POST http://localhost:8080/rest/v1/graph/create
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
{
|
||||||
|
"nodes":[
|
||||||
|
{"name":"v1"},
|
||||||
|
{"name":"v2"},
|
||||||
|
{"name":"v3"},
|
||||||
|
{"name":"v4"},
|
||||||
|
{"name":"v5"}
|
||||||
|
],
|
||||||
|
"edges":[
|
||||||
|
{"nodeOne":"v1","nodeTwo":"v2"},
|
||||||
|
{"nodeOne":"v2","nodeTwo":"v3"},
|
||||||
|
{"nodeOne":"v3","nodeTwo":"v4"},
|
||||||
|
{"nodeOne":"v3","nodeTwo":"v5"},
|
||||||
|
{"nodeOne":"v5","nodeTwo":"v4"},
|
||||||
|
{"nodeOne":"v5","nodeTwo":"v2"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
<> 2019-04-04T124349.200.json
|
||||||
|
<> 2019-04-03T023130.200.json
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
16
TestRESTful/checkRoute.http
Normal file
16
TestRESTful/checkRoute.http
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
POST http://localhost:8080/rest/v1/graph/checkroute
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
|
||||||
|
["v1", "v2", "v3"]
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/getGraph.http
Normal file
12
TestRESTful/getGraph.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/123
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/graphViz.http
Normal file
12
TestRESTful/graphViz.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
GET http://localhost:8080/rest/v1/graph/export
|
||||||
|
Content-Type: text/html
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
13
TestRESTful/options.http
Normal file
13
TestRESTful/options.http
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
|
||||||
|
# paste cURL into the file and request will be converted to HTTP Request format.
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
OPTIONS http://localhost:8080/rest/v1/graph
|
||||||
|
Accept: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
12
TestRESTful/removeGraph.http
Normal file
12
TestRESTful/removeGraph.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||||
|
#
|
||||||
|
# Following HTTP Request Live Templates are available:
|
||||||
|
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||||
|
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||||
|
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||||
|
|
||||||
|
DELETE http://localhost:8080/rest/v1/graph
|
||||||
|
Content-Type: application/json
|
||||||
|
Cache-Control: no-cache
|
||||||
|
|
||||||
|
###
|
||||||
108
linkchecker_linux.sh
Executable file
108
linkchecker_linux.sh
Executable file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
EXECUTABLE_FILE=linkchecker.jar
|
||||||
|
PROPERTIES_FILE=application-production.properties
|
||||||
|
|
||||||
|
HELP="Usage: linkchecker_linux [KEY]
|
||||||
|
|
||||||
|
Script without key is run program in DEMO mode. Also vailable next switches:
|
||||||
|
|
||||||
|
--debug - running program in DEMO mode with extended debug information.
|
||||||
|
|
||||||
|
--production - running program in PRODUCTION mode. For running in this mode needed additional
|
||||||
|
file application-production.properties with PostgreSQL dataset information. Also for this mode
|
||||||
|
available addition key --debug for runnning program with extended debug information.
|
||||||
|
|
||||||
|
--help - display this is message
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
linkchecker_linux - run program in DEMO mode
|
||||||
|
|
||||||
|
linkchecker_linux --debug - run program in DEMO mode with extended debug information.
|
||||||
|
|
||||||
|
linkchecker_linux --production - run program in PRODUCTION mode.
|
||||||
|
|
||||||
|
linkchecker_linux --production --debug - run program in PRODUCTION mode with extended debug information.
|
||||||
|
|
||||||
|
For more information see https://gitlab.com/Aleksandrov/linkchecker/wikis/
|
||||||
|
"
|
||||||
|
|
||||||
|
PROPERTIES_FILE_NOT_FOUND="
|
||||||
|
WARNING!
|
||||||
|
|
||||||
|
You try run program in PRODUCTION mode. For this mode need PostgreSQL but file
|
||||||
|
$PROPERTIES_FILE with dataset information is not found. Please fill next information and run program again!
|
||||||
|
|
||||||
|
"
|
||||||
|
|
||||||
|
if [ -f "$EXECUTABLE_FILE" ]; then
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Running program in DEMO mode"
|
||||||
|
java -jar linkchecker.jar
|
||||||
|
else
|
||||||
|
case "$1" in
|
||||||
|
--help)
|
||||||
|
echo "$HELP"
|
||||||
|
;;
|
||||||
|
--debug)
|
||||||
|
echo "Running program in DEMO mode with extended debug information"
|
||||||
|
java -jar linkchecker.jar --spring.profiles.active=demo,debug
|
||||||
|
;;
|
||||||
|
--production)
|
||||||
|
if [ -f "$PROPERTIES_FILE" ]; then
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "Running program in PRODUCTION mode"
|
||||||
|
java -jar linkchecker.jar --spring.profiles.active=production
|
||||||
|
else
|
||||||
|
if [ "$2" = "--debug" ]; then
|
||||||
|
echo "Running program in PRODUCTION mode with extended debug information"
|
||||||
|
java -jar linkchecker.jar --spring.profiles.active=production,debug
|
||||||
|
else
|
||||||
|
echo "linkchecker: unknown option $2"
|
||||||
|
echo "Try 'linkchecker --help' for more information."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "$PROPERTIES_FILE_NOT_FOUND"
|
||||||
|
printf 'PostgreSQL database host name or IP address (default localhost): '
|
||||||
|
read -r LINKCHECKER_PGSQL_DB_HOST
|
||||||
|
if [ -z "$LINKCHECKER_PGSQL_DB_HOST" ]; then
|
||||||
|
LINKCHECKER_PGSQL_DB_HOST="jdbc:postgresql://localhost"
|
||||||
|
else
|
||||||
|
LINKCHECKER_PGSQL_DB_HOST="jdbc:postgresql://$LINKCHECKER_PGSQL_DB_HOST"
|
||||||
|
fi
|
||||||
|
printf 'PostgreSQL database port (default 5432): '
|
||||||
|
read -r LINKCHECKER_PGSQL_DB_PORT
|
||||||
|
if [ -z "$LINKCHECKER_PGSQL_DB_PORT" ]; then
|
||||||
|
LINKCHECKER_PGSQL_DB_PORT=5432
|
||||||
|
fi
|
||||||
|
printf 'PostgreSQL database name (default linkchecker): '
|
||||||
|
read -r LINKCHECKER_PGSQL_DB_NAME
|
||||||
|
if [ -z "$LINKCHECKER_PGSQL_DB_NAME" ]; then
|
||||||
|
LINKCHECKER_PGSQL_DB_NAME="linkchecker"
|
||||||
|
fi
|
||||||
|
printf 'PostgreSQL database user name: '
|
||||||
|
read -r LINKCHECKER_PGSQL_DB_USER
|
||||||
|
printf 'PostgreSQL database password: '
|
||||||
|
read -r -s LINKCHECKER_PGSQL_DB_PASSWORD
|
||||||
|
echo
|
||||||
|
touch "$PROPERTIES_FILE"
|
||||||
|
{
|
||||||
|
echo "LINKCHECKER_PGSQL_DB_HOST=$LINKCHECKER_PGSQL_DB_HOST"
|
||||||
|
echo "LINKCHECKER_PGSQL_DB_PORT=$LINKCHECKER_PGSQL_DB_PORT"
|
||||||
|
echo "LINKCHECKER_PGSQL_DB_NAME=$LINKCHECKER_PGSQL_DB_NAME"
|
||||||
|
echo "LINKCHECKER_PGSQL_DB_USER=$LINKCHECKER_PGSQL_DB_USER"
|
||||||
|
echo "LINKCHECKER_PGSQL_DB_PASSWORD=$LINKCHECKER_PGSQL_DB_PASSWORD"
|
||||||
|
} > "$PROPERTIES_FILE"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "linkchecker_linux: unknown option $1"
|
||||||
|
echo "Try 'linkchecker_linux --help' for more information."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Executable file linkchecker.jar is not found!"
|
||||||
|
fi
|
||||||
136
linkchecker_win.bat
Normal file
136
linkchecker_win.bat
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
set EXECUTABLE_FILE=linkchecker.jar
|
||||||
|
set PROPERTIES_FILE=application-production.properties
|
||||||
|
|
||||||
|
if not exist %EXECUTABLE_FILE% (
|
||||||
|
echo Executable file linkchecker.jar is not found!
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
|
||||||
|
if ""=="%1" (
|
||||||
|
echo Running program in DEMO mode
|
||||||
|
java -jar %EXECUTABLE_FILE%
|
||||||
|
) else (
|
||||||
|
if "--help"=="%1" goto :Help
|
||||||
|
if "--debug"=="%1" (
|
||||||
|
echo Running program in DEMO mode with extended debug information
|
||||||
|
java -jar linkchecker.jar --spring.profiles.active=demo,debug
|
||||||
|
) else (
|
||||||
|
if "--production"=="%1" (
|
||||||
|
if exist %PROPERTIES_FILE% (
|
||||||
|
if ""=="%2" (
|
||||||
|
echo Running program in PRODUCTION mode
|
||||||
|
java -jar linkchecker.jar --spring.profiles.active=production
|
||||||
|
) else (
|
||||||
|
if "--debug"=="%2" (
|
||||||
|
echo Running program in PRODUCTION mode with extended debug information
|
||||||
|
java -jar linkchecker.jar --spring.profiles.active=production,debug
|
||||||
|
) else goto :KEY_NOT_FOUND %2
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
goto :PROPERTIES_FILE_NOT_FOUND
|
||||||
|
)
|
||||||
|
) else goto :KEY_NOT_FOUND %1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
exit /B
|
||||||
|
|
||||||
|
:Help
|
||||||
|
echo Usage: linkchecker_win [KEY]
|
||||||
|
echo.
|
||||||
|
echo Script without key is run program in DEMO mode. Also vailable next switches:
|
||||||
|
echo.
|
||||||
|
echo --debug - running program in DEMO mode with extended debug information.
|
||||||
|
echo.
|
||||||
|
echo --production - running program in PRODUCTION mode. For running in this mode needed additional file application-production.properties with PostgreSQL dataset information. Also for this mode available addition key --debug for runnning program with extended debug information.
|
||||||
|
echo.
|
||||||
|
echo --help - display this is message
|
||||||
|
echo.
|
||||||
|
echo Examples:
|
||||||
|
echo.
|
||||||
|
echo linkchecker_win - run program in DEMO mode
|
||||||
|
echo.
|
||||||
|
echo linkchecker_win --debug - run program in DEMO mode with extended debug information.
|
||||||
|
echo.
|
||||||
|
echo linkchecker_win --production - run program in PRODUCTION mode.
|
||||||
|
echo.
|
||||||
|
echo linkchecker_win --production --debug - run program in PRODUCTION mode with extended debug information.
|
||||||
|
echo.
|
||||||
|
echo For more information see https://gitlab.com/Aleksandrov/linkchecker/wikis/
|
||||||
|
exit /b
|
||||||
|
|
||||||
|
:KEY_NOT_FOUND
|
||||||
|
echo linkchecker_win: unknown option %~1
|
||||||
|
echo Try 'linkchecker_win --help' for more information.
|
||||||
|
exit /b
|
||||||
|
|
||||||
|
:PROPERTIES_FILE_NOT_FOUND
|
||||||
|
setlocal
|
||||||
|
echo WARNING!
|
||||||
|
echo.
|
||||||
|
echo You try run program in PRODUCTION mode. For this mode need PostgreSQL but file %PROPERTIES_FILE% with dataset information is not found. Please fill next information and run program again!
|
||||||
|
echo.
|
||||||
|
set /p PRMT="PostgreSQL database host name or IP address (default localhost): "
|
||||||
|
if ""=="%PRMT%" (
|
||||||
|
set LINKCHECKER_PGSQL_DB_HOST=jdbc:postgresql://localhost
|
||||||
|
) else (
|
||||||
|
set LINKCHECKER_PGSQL_DB_HOST=jdbc:postgresql://%PRMT%
|
||||||
|
)
|
||||||
|
set /p PRMT1="PostgreSQL database port (default 5432): "
|
||||||
|
if ""=="%PRMT1%" set LINKCHECKER_PGSQL_DB_PORT=5432
|
||||||
|
set /p PRMT2="PostgreSQL database name (default linkchecker): "
|
||||||
|
if ""=="%PRMT2%" set LINKCHECKER_PGSQL_DB_NAME=linkchecker
|
||||||
|
set /p LINKCHECKER_PGSQL_DB_USER="PostgreSQL database user name: "
|
||||||
|
call :getPassword LINKCHECKER_PGSQL_DB_PASSWORD "PostgreSQL database password: "
|
||||||
|
echo.
|
||||||
|
echo LINKCHECKER_PGSQL_DB_HOST=%LINKCHECKER_PGSQL_DB_HOST%>%PROPERTIES_FILE%
|
||||||
|
echo LINKCHECKER_PGSQL_DB_PORT=%LINKCHECKER_PGSQL_DB_PORT%>>%PROPERTIES_FILE%
|
||||||
|
echo LINKCHECKER_PGSQL_DB_NAME=%LINKCHECKER_PGSQL_DB_NAME%>>%PROPERTIES_FILE%
|
||||||
|
echo LINKCHECKER_PGSQL_DB_USER=%LINKCHECKER_PGSQL_DB_USER%>>%PROPERTIES_FILE%
|
||||||
|
echo LINKCHECKER_PGSQL_DB_PASSWORD=%LINKCHECKER_PGSQL_DB_PASSWORD%>>%PROPERTIES_FILE%
|
||||||
|
endlocal
|
||||||
|
exit /b
|
||||||
|
|
||||||
|
::------------------------------------------------------------------------------
|
||||||
|
:: Masks user input and returns the input as a variable.
|
||||||
|
:: Password-masking code based on http://www.dostips.com/forum/viewtopic.php?p=33538#p33538
|
||||||
|
::
|
||||||
|
:: Arguments: %1 - the variable to store the password in
|
||||||
|
:: %2 - the prompt to display when receiving input
|
||||||
|
::------------------------------------------------------------------------------
|
||||||
|
:getPassword
|
||||||
|
set "_password="
|
||||||
|
|
||||||
|
:: We need a backspace to handle character removal
|
||||||
|
for /f %%a in ('"prompt;$H&for %%b in (0) do rem"') do set "BS=%%a"
|
||||||
|
|
||||||
|
:: Prompt the user
|
||||||
|
set /p "=%~2" <nul
|
||||||
|
|
||||||
|
:keyLoop
|
||||||
|
:: Retrieve a keypress
|
||||||
|
set "key="
|
||||||
|
for /f "delims=" %%a in ('xcopy /l /w "%~f0" "%~f0" 2^>nul') do if not defined key set "key=%%a"
|
||||||
|
set "key=%key:~-1%"
|
||||||
|
|
||||||
|
:: If No keypress (enter), then exit
|
||||||
|
:: If backspace, remove character from password and console
|
||||||
|
:: Otherwise, add a character to password and go ask for next one
|
||||||
|
if defined key (
|
||||||
|
if "%key%"=="%BS%" (
|
||||||
|
if defined _password (
|
||||||
|
set "_password=%_password:~0,-1%"
|
||||||
|
set /p "=!BS! !BS!"<nul
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
set "_password=%_password%%key%"
|
||||||
|
set /p "="<nul
|
||||||
|
)
|
||||||
|
goto :keyLoop
|
||||||
|
)
|
||||||
|
echo/
|
||||||
|
|
||||||
|
:: Return password to caller
|
||||||
|
set "%~1=%_password%"
|
||||||
|
goto :eof
|
||||||
286
mvnw
vendored
Executable file
286
mvnw
vendored
Executable file
@@ -0,0 +1,286 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you 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
|
||||||
|
#
|
||||||
|
# https://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.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Maven2 Start Up Batch script
|
||||||
|
#
|
||||||
|
# Required ENV vars:
|
||||||
|
# ------------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# M2_HOME - location of maven2's installed home dir
|
||||||
|
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||||
|
# e.g. to debug Maven itself, use
|
||||||
|
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||||
|
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||||
|
|
||||||
|
if [ -f /etc/mavenrc ] ; then
|
||||||
|
. /etc/mavenrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.mavenrc" ] ; then
|
||||||
|
. "$HOME/.mavenrc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OS specific support. $var _must_ be set to either true or false.
|
||||||
|
cygwin=false;
|
||||||
|
darwin=false;
|
||||||
|
mingw=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN*) cygwin=true ;;
|
||||||
|
MINGW*) mingw=true;;
|
||||||
|
Darwin*) darwin=true
|
||||||
|
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||||
|
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
if [ -x "/usr/libexec/java_home" ]; then
|
||||||
|
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||||
|
else
|
||||||
|
export JAVA_HOME="/Library/Java/Home"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ] ; then
|
||||||
|
if [ -r /etc/gentoo-release ] ; then
|
||||||
|
JAVA_HOME=`java-config --jre-home`
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$M2_HOME" ] ; then
|
||||||
|
## resolve links - $0 may be a link to maven's home
|
||||||
|
PRG="$0"
|
||||||
|
|
||||||
|
# need this for relative symlinks
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG="`dirname "$PRG"`/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
saveddir=`pwd`
|
||||||
|
|
||||||
|
M2_HOME=`dirname "$PRG"`/..
|
||||||
|
|
||||||
|
# make it fully qualified
|
||||||
|
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||||
|
|
||||||
|
cd "$saveddir"
|
||||||
|
# echo Using m2 at $M2_HOME
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||||
|
if $cygwin ; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||||
|
if $mingw ; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||||
|
# TODO classpath?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
javaExecutable="`which javac`"
|
||||||
|
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||||
|
# readlink(1) is not available as standard on Solaris 10.
|
||||||
|
readLink=`which readlink`
|
||||||
|
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||||
|
if $darwin ; then
|
||||||
|
javaHome="`dirname \"$javaExecutable\"`"
|
||||||
|
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||||
|
else
|
||||||
|
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||||
|
fi
|
||||||
|
javaHome="`dirname \"$javaExecutable\"`"
|
||||||
|
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||||
|
JAVA_HOME="$javaHome"
|
||||||
|
export JAVA_HOME
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVACMD" ] ; then
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="`which java`"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||||
|
echo " We cannot execute $JAVACMD" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ] ; then
|
||||||
|
echo "Warning: JAVA_HOME environment variable is not set."
|
||||||
|
fi
|
||||||
|
|
||||||
|
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||||
|
|
||||||
|
# traverses directory structure from process work directory to filesystem root
|
||||||
|
# first directory with .mvn subdirectory is considered project base directory
|
||||||
|
find_maven_basedir() {
|
||||||
|
|
||||||
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
echo "Path not specified to find_maven_basedir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
basedir="$1"
|
||||||
|
wdir="$1"
|
||||||
|
while [ "$wdir" != '/' ] ; do
|
||||||
|
if [ -d "$wdir"/.mvn ] ; then
|
||||||
|
basedir=$wdir
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||||
|
if [ -d "${wdir}" ]; then
|
||||||
|
wdir=`cd "$wdir/.."; pwd`
|
||||||
|
fi
|
||||||
|
# end of workaround
|
||||||
|
done
|
||||||
|
echo "${basedir}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# concatenates all lines of a file
|
||||||
|
concat_lines() {
|
||||||
|
if [ -f "$1" ]; then
|
||||||
|
echo "$(tr -s '\n' ' ' < "$1")"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||||
|
if [ -z "$BASE_DIR" ]; then
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
##########################################################################################
|
||||||
|
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||||
|
fi
|
||||||
|
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||||
|
while IFS="=" read key value; do
|
||||||
|
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||||
|
esac
|
||||||
|
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Downloading from: $jarUrl"
|
||||||
|
fi
|
||||||
|
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||||
|
|
||||||
|
if command -v wget > /dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found wget ... using wget"
|
||||||
|
fi
|
||||||
|
wget "$jarUrl" -O "$wrapperJarPath"
|
||||||
|
elif command -v curl > /dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found curl ... using curl"
|
||||||
|
fi
|
||||||
|
curl -o "$wrapperJarPath" "$jarUrl"
|
||||||
|
else
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Falling back to using Java to download"
|
||||||
|
fi
|
||||||
|
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||||
|
if [ -e "$javaClass" ]; then
|
||||||
|
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
# Compiling the Java class
|
||||||
|
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||||
|
fi
|
||||||
|
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
# Running the downloader
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Running MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
##########################################################################################
|
||||||
|
# End of extension
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo $MAVEN_PROJECTBASEDIR
|
||||||
|
fi
|
||||||
|
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||||
|
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||||
|
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
exec "$JAVACMD" \
|
||||||
|
$MAVEN_OPTS \
|
||||||
|
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||||
|
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||||
|
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||||
161
mvnw.cmd
vendored
Normal file
161
mvnw.cmd
vendored
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Maven2 Start Up Batch script
|
||||||
|
@REM
|
||||||
|
@REM Required ENV vars:
|
||||||
|
@REM JAVA_HOME - location of a JDK home dir
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM M2_HOME - location of maven2's installed home dir
|
||||||
|
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||||
|
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||||
|
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||||
|
@REM e.g. to debug Maven itself, use
|
||||||
|
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||||
|
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||||
|
@echo off
|
||||||
|
@REM set title of command window
|
||||||
|
title %0
|
||||||
|
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||||
|
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||||
|
|
||||||
|
@REM set %HOME% to equivalent of $HOME
|
||||||
|
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||||
|
|
||||||
|
@REM Execute a user defined script before this one
|
||||||
|
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||||
|
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||||
|
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||||
|
:skipRcPre
|
||||||
|
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
set ERROR_CODE=0
|
||||||
|
|
||||||
|
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
@REM ==== START VALIDATION ====
|
||||||
|
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME not found in your environment. >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
:OkJHome
|
||||||
|
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||||
|
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
@REM ==== END VALIDATION ====
|
||||||
|
|
||||||
|
:init
|
||||||
|
|
||||||
|
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||||
|
@REM Fallback to current working directory if not found.
|
||||||
|
|
||||||
|
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||||
|
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||||
|
|
||||||
|
set EXEC_DIR=%CD%
|
||||||
|
set WDIR=%EXEC_DIR%
|
||||||
|
:findBaseDir
|
||||||
|
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||||
|
cd ..
|
||||||
|
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||||
|
set WDIR=%CD%
|
||||||
|
goto findBaseDir
|
||||||
|
|
||||||
|
:baseDirFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
goto endDetectBaseDir
|
||||||
|
|
||||||
|
:baseDirNotFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
|
||||||
|
:endDetectBaseDir
|
||||||
|
|
||||||
|
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||||
|
|
||||||
|
@setlocal EnableExtensions EnableDelayedExpansion
|
||||||
|
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||||
|
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||||
|
|
||||||
|
:endReadAdditionalConfig
|
||||||
|
|
||||||
|
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||||
|
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||||
|
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
|
||||||
|
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
|
||||||
|
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||||
|
)
|
||||||
|
|
||||||
|
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
if exist %WRAPPER_JAR% (
|
||||||
|
echo Found %WRAPPER_JAR%
|
||||||
|
) else (
|
||||||
|
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||||
|
echo Downloading from: %DOWNLOAD_URL%
|
||||||
|
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
|
||||||
|
echo Finished downloading %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
@REM End of extension
|
||||||
|
|
||||||
|
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||||
|
if ERRORLEVEL 1 goto error
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:error
|
||||||
|
set ERROR_CODE=1
|
||||||
|
|
||||||
|
:end
|
||||||
|
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||||
|
|
||||||
|
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||||
|
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||||
|
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||||
|
:skipRcPost
|
||||||
|
|
||||||
|
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||||
|
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||||
|
|
||||||
|
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||||
|
|
||||||
|
exit /B %ERROR_CODE%
|
||||||
180
pom.xml
Normal file
180
pom.xml
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.2.0.RELEASE</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>ru.resprojects</groupId>
|
||||||
|
<artifactId>linkchecker</artifactId>
|
||||||
|
<version>0.3.0</version>
|
||||||
|
<name>linkchecker</name>
|
||||||
|
<description>Linkchecker (test project)</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<jgrapht.version>1.3.1</jgrapht.version>
|
||||||
|
<bootstrap.version>4.3.1</bootstrap.version>
|
||||||
|
<gson.version>2.8.6</gson.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<!-- Exclude the default Jackson dependency -->
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-json</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JSON -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>${gson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- DATABASES -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- BOOTSTRAP -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>bootstrap</artifactId>
|
||||||
|
<version>${bootstrap.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--JGraphT-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jgrapht</groupId>
|
||||||
|
<artifactId>jgrapht-core</artifactId>
|
||||||
|
<version>${jgrapht.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jgrapht</groupId>
|
||||||
|
<artifactId>jgrapht-ext</artifactId>
|
||||||
|
<version>${jgrapht.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jgrapht</groupId>
|
||||||
|
<artifactId>jgrapht-io</artifactId>
|
||||||
|
<version>${jgrapht.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Unit TEST -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-api-mockito2</artifactId>
|
||||||
|
<version>2.0.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-module-junit4</artifactId>
|
||||||
|
<version>2.0.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.restdocs</groupId>
|
||||||
|
<artifactId>spring-restdocs-mockmvc</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<includes>
|
||||||
|
<include>**/*Documentation.java</include>
|
||||||
|
<include>**/*Tests.java</include>
|
||||||
|
</includes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.asciidoctor</groupId>
|
||||||
|
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||||
|
<version>1.5.8</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>generate-docs</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>process-asciidoc</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<backend>html</backend>
|
||||||
|
<doctype>book</doctype>
|
||||||
|
<attributes>
|
||||||
|
<snippets>${project.build.directory}/generated-snippets</snippets>
|
||||||
|
</attributes>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-resources</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-resources</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>${project.build.outputDirectory}/static/docs
|
||||||
|
</outputDirectory>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>${project.build.directory}/generated-docs</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
152
src/main/asciidoc/api-guide-v1.adoc
Normal file
152
src/main/asciidoc/api-guide-v1.adoc
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
= Linkchecker API Guide v1
|
||||||
|
Test project;
|
||||||
|
:doctype: book
|
||||||
|
:toc:
|
||||||
|
:sectanchors:
|
||||||
|
:sectlinks:
|
||||||
|
:toclevels: 5
|
||||||
|
:source-highlighter: highlightjs
|
||||||
|
|
||||||
|
[[overview]]
|
||||||
|
= Обзор
|
||||||
|
|
||||||
|
*Linkchecker* - REST-сервис проверяющий работоспособность любой последовательности узлов, хранящихся в неориентированном ациклическом графе.
|
||||||
|
|
||||||
|
API REST-сервиса разбит на следующие категории:
|
||||||
|
|
||||||
|
* *GRAPH API* - набор команд позволяющий работать с графом в целом.
|
||||||
|
* *NODES API* - набор команд позволящий работать отдельно с вершинами графа.
|
||||||
|
* *EDGES API* - набор команд позволящий работать отдельно с рёбрами графа.
|
||||||
|
|
||||||
|
[[overview-common]]
|
||||||
|
== Общая информация
|
||||||
|
|
||||||
|
[[overview-http-verbs]]
|
||||||
|
=== HTTP методы
|
||||||
|
|
||||||
|
API Linkchecker следует стандартным соглашениям HTTP REST и поддерживает HTTP методы, перечисленные ниже.
|
||||||
|
|
||||||
|
|===
|
||||||
|
| Вид запроса | Назначание
|
||||||
|
|
||||||
|
| `GET`
|
||||||
|
| Используется для запроса содержимого указанного ресурса.
|
||||||
|
|
||||||
|
| `POST`
|
||||||
|
| Применяется для передачи пользовательских данных заданному ресурсу (создание нового ресурса или передача данных для обработки на стороне сервера).
|
||||||
|
|
||||||
|
| `DELETE`
|
||||||
|
| Удаляет указанный ресурс.
|
||||||
|
|
||||||
|
| `OPTIONS`
|
||||||
|
| Предоставляет информацию клиенту о доступных для работы HTTP методов.
|
||||||
|
|===
|
||||||
|
|
||||||
|
[[overview-http-status-codes]]
|
||||||
|
=== Коды состояния HTTP
|
||||||
|
|
||||||
|
В API Linkchecker используются следующие коды состояния HTTP.
|
||||||
|
|
||||||
|
|===
|
||||||
|
| Код состояния | Назначение
|
||||||
|
|
||||||
|
| `200 OK`
|
||||||
|
| успешный запрос. Если клиентом были запрошены какие-либо данные, то они находятся в заголовке и/или теле сообщения.
|
||||||
|
|
||||||
|
| `201 Created`
|
||||||
|
| В результате успешного выполнения запроса был создан новый ресурс.
|
||||||
|
|
||||||
|
| `204 No Content`
|
||||||
|
| сервер успешно обработал запрос, но в ответе были переданы только заголовки без тела сообщения.
|
||||||
|
|
||||||
|
| `422 Unprocessable Entity`
|
||||||
|
| сервер успешно принял запрос, может работать с указанным видом данных (например, в теле запроса находится XML-документ, имеющий верный синтаксис), однако имеется какая-то логическая ошибка, из-за которой невозможно произвести операцию над ресурсом
|
||||||
|
|
||||||
|
| `500 Internal Server Error`
|
||||||
|
| любая внутренняя ошибка сервера, которая не входит в рамки остальных ошибок класса.
|
||||||
|
|===
|
||||||
|
|
||||||
|
[[overview-http-errors]]
|
||||||
|
=== Ошибки
|
||||||
|
|
||||||
|
В случае возникновения ошибок во время работы REST-сервиса, клиенту будет возвращен структурированный набор данных в формате JSON
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"url": "request_link",
|
||||||
|
"type": "APP_ERROR[,DATA_NOT_FOUND,DATA_ERROR,VALIDATION_ERROR, WRONG_REQUEST]",
|
||||||
|
"place": "APP[,GRAPH,NODE,EDGE]",
|
||||||
|
"messages": [
|
||||||
|
"Any message 1",
|
||||||
|
"Any message 2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
, где
|
||||||
|
|
||||||
|
* *url* - REST-запрос, при котором возникла ошибка
|
||||||
|
* *type* - тип ошибки
|
||||||
|
** _APP_ERROR_ - общие ошибки сервиса.
|
||||||
|
** _DATA_NOT_FOUND_ - ошибки, возникающие при поиске и извлечении данных.
|
||||||
|
** _DATA_ERROR_ - ошибки, возникающие при обработки данных.
|
||||||
|
** _VALIDATION_ERROR_ - ошибки, связанные с проверкой данных.
|
||||||
|
** _WRONG_REQUEST_ - ошибки, возникающие при некорректном запросе.
|
||||||
|
* *place* - места возникновения ошибок
|
||||||
|
** _APP_ - сервис
|
||||||
|
** _GRAPH_ - граф
|
||||||
|
** _NODE_ - вершины графа
|
||||||
|
** _EDGE_ - рёбра графа
|
||||||
|
* *messages* - сообщения об ошибках
|
||||||
|
|
||||||
|
Виды сообщения об ошибках:
|
||||||
|
|
||||||
|
*Обобщенные сообщения об ошибках*
|
||||||
|
|
||||||
|
* Argument must not be null - на вход вместо объекта был подан null
|
||||||
|
* Collection must not be empty - на вход поступила пустая коллекция данных
|
||||||
|
* Collection must not contain a null item - на вход поступила коллекция, в которой содержится null элемент
|
||||||
|
* Collection must have more than one element - в определённых случаях требуется что бы коллекция состояла как минимум из двух элементов (например при работе с рёбрами графа, где требуется указать две вершины графа, которые нужно связать)
|
||||||
|
* %s with ID = %d is not found - данные с указанным ID не обнаружены, где %s - может быть или NODE или EDGE, %d - номер id'шника.
|
||||||
|
|
||||||
|
*Сообщения об ошибках, возникающие при работе с рёбрами графа*
|
||||||
|
|
||||||
|
* Edge for nodes [%s, %s] is not found - ребро для указанных вершин (нод) не найдено, [%s, %s] - уникальные имена пары вершин.
|
||||||
|
* Edge for nodes ([%s, %s], [%s, %s]) already present in the graph - данное сообщение возникает при попытки добавить в граф уже существующее ребро. Где ([%s, %s], [%s, %s]) - подставляются уникальные имена вершин графа. Так как граф неориентированный, то например v1 и v2 <=> v2 и v1.
|
||||||
|
* Edges for node %s is not found - данное сообщение возникает при попытки извлечь информацию по рёбрам графа для заданной вершины, %s - уникальное имя вершины графа.
|
||||||
|
|
||||||
|
*Сообщения об ошибках, возникающие при работе с вершинами (нодами) графа*
|
||||||
|
|
||||||
|
* Node %s already present in the graph - данное сообщение возникает, при попытки добавить вершину, которая уже присутствует в графе.
|
||||||
|
* Error while update node with id = - сообщение возникает при неудачной попытки обновить данные по вершине графа, где id - номер идентификатора вершины.
|
||||||
|
* Node with NAME = %s is not found - сообщение возникает, при неудачном поиске вершины графа по её уникальному имени.
|
||||||
|
* Node %s is not found - сообщение возникает, при неудачном поиске вершины графа в режиме поиска по заданному объекту.
|
||||||
|
* Nodes %s and %s are not reachable to each other - сообщение возникает если один из узлов (вершин графа) не достижим до другого узла (т.е. имеются промежуточные узлы).
|
||||||
|
* Node %s is fault - сообщение возникает в случае генерации сбоя в узле (в вершине графа), т.е. узел оказался недоступным во время обхода по узлам.
|
||||||
|
|
||||||
|
[[rest-api-usage]]
|
||||||
|
= REST API
|
||||||
|
|
||||||
|
Далее - описание отдельных частей API REST-сервиса.
|
||||||
|
|
||||||
|
[[rest-api-usage-graph]]
|
||||||
|
== GRAPH API
|
||||||
|
|
||||||
|
Набор запросов при работе с графом в целом.
|
||||||
|
|
||||||
|
include::graph.adoc[]
|
||||||
|
|
||||||
|
[[rest-api-usage-nodes]]
|
||||||
|
== NODES API
|
||||||
|
|
||||||
|
Набор запросов при работе с вершинами графа (нодами).
|
||||||
|
|
||||||
|
include::nodes.adoc[]
|
||||||
|
|
||||||
|
[[rest-api-usage-edges]]
|
||||||
|
== EDGES API
|
||||||
|
|
||||||
|
Набор запросов при работе с рёбрами графа.
|
||||||
|
|
||||||
|
include::edges.adoc[]
|
||||||
468
src/main/asciidoc/edges.adoc
Normal file
468
src/main/asciidoc/edges.adoc
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
=== HTTP запросы для поиска рёбер графа
|
||||||
|
==== Получить список всех рёбер графа.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-edges/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-edges/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-edges/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-edges/http-response.adoc[]
|
||||||
|
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-edges/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== HTTP запросы для поиска рёбер графа.
|
||||||
|
===== Поиск ребра графа по его идентификатору.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-edge-by-id/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-edge-by-id/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-edge-by-id/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-edge-by-id/http-response.adoc[]
|
||||||
|
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-edge-by-id/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Поиск рёбер графа в которых встречается уникальное имя вершины графа заданное в качестве параметра поиска
|
||||||
|
|
||||||
|
В поиске используется уникальное имя вершины графа. В отбор попадают все ребра графа в которых встречается
|
||||||
|
уникальное имя вершины графа, заданное в качестве параметра поиска.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-edges-by-node-name/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-edges-by-node-name/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-edges-by-node-name/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-edges-by-node-name/http-response.adoc[]
|
||||||
|
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-edges-by-node-name/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Поиск ребра графа по паре уникальных имен вершин графа, которые связывает искомое ребро
|
||||||
|
|
||||||
|
Поиск ребра ведётся по конкретному набору вершин, которые связывает искомое ребро.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-edge-by-nodes-name/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-edge-by-nodes-name/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-edge-by-nodes-name/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-edge-by-nodes-name/http-response.adoc[]
|
||||||
|
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-edge-by-nodes-name/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок при поиске рёбер графа
|
||||||
|
===== Ошибка поиска ребра графа по идентификатору
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-edge-exception-1/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-edge-exception-1/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-edge-exception-1/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-edge-exception-1/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-edge-exception-1/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка поиска рёбер графа по уникальному имени вершины графа
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-edge-exception-2/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-edge-exception-2/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-edge-exception-2/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-edge-exception-2/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-edge-exception-2/response-fields.adoc[]
|
||||||
|
|
||||||
|
=== HTTP запросы добавления новых рёбер в граф
|
||||||
|
==== Создать и добавить новое ребро в граф
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-edge/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-edge/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-edge/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/create-edge/request-body.adoc[]
|
||||||
|
*Request fields*
|
||||||
|
include::{snippets}/create-edge/request-fields.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-edge/http-response.adoc[]
|
||||||
|
*Response body*
|
||||||
|
include::{snippets}/create-edge/response-body.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-edge/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Создать и добавить новые ребра в граф
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-edges/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-edges/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-edges/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/create-edges/request-body.adoc[]
|
||||||
|
*Request fields*
|
||||||
|
include::{snippets}/create-edges/request-fields.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-edges/http-response.adoc[]
|
||||||
|
*Response body*
|
||||||
|
include::{snippets}/create-edges/response-body.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-edges/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок возникающие при добавлении рёбер в граф
|
||||||
|
===== Ошибка валидации при добавлении ребра в граф
|
||||||
|
|
||||||
|
Попытка создать новый объект ребра графа не указав имена связываемых ребром вершин графа.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-edge-exception-1/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-edge-exception-1/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-edge-exception-1/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-edge-exception-1/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-edge-exception-1/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка при создания ребра, который уже присутствует в графе
|
||||||
|
|
||||||
|
Попытка создать новый объект ребра, который уже присутствует в графе.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-edge-exception-2/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-edge-exception-2/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-edge-exception-2/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-edge-exception-2/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-edge-exception-2/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка создания набора рёбер графа используя пустой список
|
||||||
|
|
||||||
|
Попытка создать и добавить в граф набор рёбер графа используя пустой список.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-edge-exception-3/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-edge-exception-3/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-edge-exception-3/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-edge-exception-3/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-edge-exception-3/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка создания набора вершин рёбер используя список содержащий null-элемент
|
||||||
|
|
||||||
|
Попытка создать и добавить в граф набор рёбер графа используя список содержащий null-элемент.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-edge-exception-4/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-edge-exception-4/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-edge-exception-4/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-edge-exception-4/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-edge-exception-4/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка создания набора рёбер графа используя список содержащий существующее ребро в графе
|
||||||
|
|
||||||
|
Попытка создать и добавить в граф набор рёбер графа используя список содержащий существующее ребро в графе.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-edge-exception-5/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-edge-exception-5/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-edge-exception-5/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-edge-exception-5/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-edge-exception-5/response-fields.adoc[]
|
||||||
|
|
||||||
|
=== HTTP запросы для удаления рёбер графа
|
||||||
|
==== Удалить все рёбра графа
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-all-edges/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-all-edges/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-all-edges/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-all-edges/http-response.adoc[]
|
||||||
|
|
||||||
|
==== HTTP запросы для удаления ребра графа
|
||||||
|
===== Поиск и удаление ребра графа по идентификатору
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-edge-by-id/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-edge-by-id/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-edge-by-id/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-edge-by-id/http-response.adoc[]
|
||||||
|
|
||||||
|
===== Поиск и удаление всех рёбер графа которые содержат указанное в качестве параметра поиска имя вершины графа
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-edges-by-node-name/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-edges-by-node-name/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-edges-by-node-name/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-edges-by-node-name/http-response.adoc[]
|
||||||
|
|
||||||
|
===== Поиск и удаление ребра графа по именам вершин графа, которые искомое ребро соединяет
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-edge-by-nodes-name/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-edge-by-nodes-name/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-edge-by-nodes-name/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-edge-by-nodes-name/http-response.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок возникающие при удалении рёбер графа
|
||||||
|
===== Ошибка при поиске и удалении ребра графа по идентификатору
|
||||||
|
|
||||||
|
Попытка найти и удалить ребро графа используя идентификатор
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-edge-exception-1/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-edge-exception-1/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-edge-exception-1/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-edge-exception-1/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-edge-exception-1/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка при поиске и удалении рёбр графа которые не содержат указанное в качестве параметра поиска имя вершины графа
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-edge-exception-2/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-edge-exception-2/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-edge-exception-2/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-edge-exception-2/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-edge-exception-2/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка при поиске и удалении ребра графа по именам вершин графа
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-edge-exception-3/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-edge-exception-3/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-edge-exception-3/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-edge-exception-3/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-edge-exception-3/response-fields.adoc[]
|
||||||
215
src/main/asciidoc/graph.adoc
Normal file
215
src/main/asciidoc/graph.adoc
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
=== Получить объект графа.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-graph/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-graph/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-graph/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-graph/http-response.adoc[]
|
||||||
|
|
||||||
|
*HTTP response fields*
|
||||||
|
include::{snippets}/get-graph/response-fields.adoc[]
|
||||||
|
|
||||||
|
=== Экспорт графа в формат https://www.graphviz.org/about/[graphviz].
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/export-graph/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/export-graph/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/export-graph/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/export-graph/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Создание нового графа
|
||||||
|
|
||||||
|
При этом прежний граф полностью удаляется из БД.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-graph/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-graph/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-graph/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/create-graph/request-body.adoc[]
|
||||||
|
*Request fields*
|
||||||
|
include::{snippets}/create-graph/request-fields.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-graph/http-response.adoc[]
|
||||||
|
*Response body*
|
||||||
|
include::{snippets}/create-graph/response-body.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-graph/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок
|
||||||
|
===== Ошибка при создании нового графа
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-graph-exception/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-graph-exception/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-graph-exception/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-graph-exception/http-response.adoc[]
|
||||||
|
*Response body*
|
||||||
|
include::{snippets}/create-graph-exception/response-body.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-graph-exception/response-fields.adoc[]
|
||||||
|
|
||||||
|
=== Удалить графа из БД
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-graph/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-graph/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-graph/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-graph/http-response.adoc[]
|
||||||
|
|
||||||
|
=== Проверка работоспособности заданной последовательности узлов.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/checkroute-graph/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/checkroute-graph/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/checkroute-graph/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/checkroute-graph/request-body.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/checkroute-graph/http-response.adoc[]
|
||||||
|
*Response body*
|
||||||
|
include::{snippets}/checkroute-graph/response-body.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок
|
||||||
|
===== Пустая входная коллекция
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-1/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-1/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-1/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/checkroute-graph-exception-1/request-body.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/checkroute-graph-exception-1/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/checkroute-graph-exception-1/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Входная коллекция состоящая из одного элемента
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-2/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-2/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-2/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/checkroute-graph-exception-2/request-body.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/checkroute-graph-exception-2/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/checkroute-graph-exception-2/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Путь между входными узлами не найден
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-3/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-3/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/checkroute-graph-exception-3/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/checkroute-graph-exception-3/request-body.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/checkroute-graph-exception-3/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/checkroute-graph-exception-3/response-fields.adoc[]
|
||||||
473
src/main/asciidoc/nodes.adoc
Normal file
473
src/main/asciidoc/nodes.adoc
Normal file
@@ -0,0 +1,473 @@
|
|||||||
|
=== HTTP запросы для поиска вершин графа
|
||||||
|
==== Получить список всех вершин графа.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-nodes/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-nodes/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-nodes/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-nodes/http-response.adoc[]
|
||||||
|
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-nodes/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== HTTP запросы поиска вершины графа.
|
||||||
|
===== Найти вершину графа по её идентификатору.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-node-by-id/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-node-by-id/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-node-by-id/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-node-by-id/http-response.adoc[]
|
||||||
|
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-node-by-id/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Найти вершину графа по её уникальному имени.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-node-by-name/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-node-by-name/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-node-by-name/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-node-by-name/http-response.adoc[]
|
||||||
|
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-node-by-name/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок при поиске вершин(ы) графа
|
||||||
|
===== Ошибка поиска вершины графа по уникальному имени
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/get-node-by-name-exception/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/get-node-by-name-exception/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/get-node-by-name-exception/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/get-node-by-name-exception/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/get-node-by-name-exception/response-fields.adoc[]
|
||||||
|
|
||||||
|
=== HTTP запросы добавления новых вершин в граф
|
||||||
|
==== Создать и добавить новую вершину в граф
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-node/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-node/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-node/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/create-node/request-body.adoc[]
|
||||||
|
*Request fields*
|
||||||
|
include::{snippets}/create-node/request-fields.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-node/http-response.adoc[]
|
||||||
|
*Response body*
|
||||||
|
include::{snippets}/create-node/response-body.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-node/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Создать и добавить новые вершины в граф
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-nodes/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-nodes/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-nodes/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Request body*
|
||||||
|
include::{snippets}/create-nodes/request-body.adoc[]
|
||||||
|
*Request fields*
|
||||||
|
include::{snippets}/create-nodes/request-fields.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-nodes/http-response.adoc[]
|
||||||
|
*Response body*
|
||||||
|
include::{snippets}/create-nodes/response-body.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-nodes/response-fields.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок возникающие при добавлении вершин в граф
|
||||||
|
===== Ошибка валидации при добавлении вершины в граф
|
||||||
|
|
||||||
|
Попытка создать новый объект вершины графа с пустым уникальным именем.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-node-exception-1/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-node-exception-1/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-node-exception-1/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-node-exception-1/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-node-exception-1/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка создания уже существующей вершины
|
||||||
|
|
||||||
|
Попытка создать новый объект вершины графа с уникальным именем, который уже существует в графе.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-node-exception-2/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-node-exception-2/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-node-exception-2/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-node-exception-2/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-node-exception-2/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка создания набора вершин графа используя пустой список
|
||||||
|
|
||||||
|
Попытка создать и добавить в граф набор вершин графа используя пустой список.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-node-exception-3/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-node-exception-3/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-node-exception-3/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-node-exception-3/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-node-exception-3/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка создания набора вершин графа используя список содержащий null-элемент
|
||||||
|
|
||||||
|
Попытка создать и добавить в граф набор вершин графа используя список содержащий null-элемент.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-node-exception-4/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-node-exception-4/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-node-exception-4/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-node-exception-4/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-node-exception-4/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка создания набора вершин графа используя список содержащий существующую вершину в графе
|
||||||
|
|
||||||
|
Попытка создать и добавить в граф набор вершин графа используя список содержащий существующую вершину в графе.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/create-node-exception-5/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/create-node-exception-5/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/create-node-exception-5/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/create-node-exception-5/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/create-node-exception-5/response-fields.adoc[]
|
||||||
|
|
||||||
|
=== HTTP запросы для удаления вершин графа
|
||||||
|
==== Удалить все вершины графа
|
||||||
|
|
||||||
|
При удалении вершин графа происходит автоматическое удаление рёбер графа. Данный запрос эквивалентен запросу удаления всего графа.
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-all-nodes/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-all-nodes/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-all-nodes/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-all-nodes/http-response.adoc[]
|
||||||
|
|
||||||
|
==== HTTP запросы для удаления вершины графа
|
||||||
|
===== Поиск и удаление вершины графа по идентификатору
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-by-id/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-by-id/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-by-id/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-by-id/http-response.adoc[]
|
||||||
|
|
||||||
|
===== Поиск и удаление вершины графа по имени
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-by-name/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-by-name/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-by-name/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-by-name/http-response.adoc[]
|
||||||
|
|
||||||
|
===== Поиск и удаление вершины графа по объекту
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-by-obj/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-by-obj/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-by-obj/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-by-obj/http-response.adoc[]
|
||||||
|
|
||||||
|
==== Примеры ошибок возникающие при удалении вершин графа
|
||||||
|
===== Ошибка при поиске и удалении вершины графа по идентификатору
|
||||||
|
|
||||||
|
Попытка найти и удалить вершину графа используя идентификатор
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-exception-1/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-exception-1/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-exception-1/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-exception-1/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-node-exception-1/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка при поиске и удалении вершины графа по имени
|
||||||
|
|
||||||
|
Попытка найти и удалить вершину графа используя уникальное имя
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-exception-2/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-exception-2/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-exception-2/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-exception-2/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-node-exception-2/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка при поиске и удалении вершины графа по объекту вершины графа у которого id = null
|
||||||
|
|
||||||
|
Попытка найти и удалить вершину графа используя объект вершины графа у которого id = null
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-exception-3/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-exception-3/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-exception-3/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-exception-3/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-node-exception-3/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка при поиске и удалении вершины графа по объекту несуществующей вершины графа
|
||||||
|
|
||||||
|
Попытка найти и удалить вершину графа используя объект несуществующей вершины графа
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-exception-4/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-exception-4/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-exception-4/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-exception-4/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-node-exception-4/response-fields.adoc[]
|
||||||
|
|
||||||
|
===== Ошибка при поиске и удалении вершины графа по объекту вершины графа у которого указан некорректный id
|
||||||
|
|
||||||
|
Попытка найти и удалить вершину графа используя объект вершины графа у которого указан некорректный id
|
||||||
|
|
||||||
|
*Пример запроса*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*CURL request*
|
||||||
|
include::{snippets}/delete-node-exception-5/curl-request.adoc[]
|
||||||
|
*HTTP request*
|
||||||
|
include::{snippets}/delete-node-exception-5/http-request.adoc[]
|
||||||
|
*HTTPie request*
|
||||||
|
include::{snippets}/delete-node-exception-5/httpie-request.adoc[]
|
||||||
|
|
||||||
|
*Пример ответа*
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
*HTTP response*
|
||||||
|
include::{snippets}/delete-node-exception-5/http-response.adoc[]
|
||||||
|
*Response fields*
|
||||||
|
include::{snippets}/delete-node-exception-5/response-fields.adoc[]
|
||||||
52
src/main/java/ru/resprojects/linkchecker/AppProperties.java
Normal file
52
src/main/java/ru/resprojects/linkchecker/AppProperties.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package ru.resprojects.linkchecker;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class for application error string messages. These messages is loaded
|
||||||
|
* from "appmsg" block in the application.yml file
|
||||||
|
*
|
||||||
|
* Messages is divided on three type:
|
||||||
|
*
|
||||||
|
* AppMsg - error messages is related with application as whole.
|
||||||
|
* NodeMsg - error messages is related with nodes in the graph.
|
||||||
|
* EdgeMsg - error messages is related with edges int the graph.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@EnableConfigurationProperties
|
||||||
|
@ConfigurationProperties(prefix = "appmsg")
|
||||||
|
public class AppProperties {
|
||||||
|
|
||||||
|
private Map<String, String> appMsg = new HashMap<>();
|
||||||
|
private Map<String, String> nodeMsg = new HashMap<>();
|
||||||
|
private Map<String, String> edgeMsg = new HashMap<>();
|
||||||
|
|
||||||
|
public Map<String, String> getAppMsg() {
|
||||||
|
return appMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getNodeMsg() {
|
||||||
|
return nodeMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getEdgeMsg() {
|
||||||
|
return edgeMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppMsg(Map<String, String> appMsg) {
|
||||||
|
this.appMsg = appMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeMsg(Map<String, String> nodeMsg) {
|
||||||
|
this.nodeMsg = nodeMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEdgeMsg(Map<String, String> edgeMsg) {
|
||||||
|
this.edgeMsg = edgeMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/main/java/ru/resprojects/linkchecker/HasId.java
Normal file
20
src/main/java/ru/resprojects/linkchecker/HasId.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package ru.resprojects.linkchecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface indicates that the object has an identifier.
|
||||||
|
*/
|
||||||
|
public interface HasId {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get entity id.
|
||||||
|
* @return entity id.
|
||||||
|
*/
|
||||||
|
Integer getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set entity id.
|
||||||
|
* @param id of entity.
|
||||||
|
*/
|
||||||
|
void setId(Integer id);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package ru.resprojects.linkchecker;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class LinkcheckerApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(LinkcheckerApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
src/main/java/ru/resprojects/linkchecker/dto/BaseDto.java
Normal file
39
src/main/java/ru/resprojects/linkchecker/dto/BaseDto.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package ru.resprojects.linkchecker.dto;
|
||||||
|
|
||||||
|
import ru.resprojects.linkchecker.HasId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for data transfer object.
|
||||||
|
*/
|
||||||
|
abstract public class BaseDto implements HasId {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of transport object.
|
||||||
|
*/
|
||||||
|
protected Integer id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
BaseDto() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id of transport object.
|
||||||
|
*/
|
||||||
|
BaseDto(final Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setId(final Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
281
src/main/java/ru/resprojects/linkchecker/dto/GraphDto.java
Normal file
281
src/main/java/ru/resprojects/linkchecker/dto/GraphDto.java
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
package ru.resprojects.linkchecker.dto;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.util.ValidationUtil.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for transfer object that implements graph.
|
||||||
|
*/
|
||||||
|
public class GraphDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for transfer object that implements graph node.
|
||||||
|
*/
|
||||||
|
public static class NodeGraph extends BaseDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique graph node name.
|
||||||
|
*/
|
||||||
|
@NotBlank(message = VALIDATOR_NODE_NOT_BLANK_NAME_MESSAGE)
|
||||||
|
@Size(min = MIN_NAME_SIZE, max = MAX_NAME_SIZE,
|
||||||
|
message = VALIDATOR_NODE_NAME_RANGE_MESSAGE)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of passes through the graph node.
|
||||||
|
*/
|
||||||
|
private int counter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
public NodeGraph() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param name - unique graph node name.
|
||||||
|
*/
|
||||||
|
public NodeGraph(final String name) {
|
||||||
|
this(null, name, NODE_COUNTER_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id - identity number of graph node.
|
||||||
|
* @param name - unique graph node name.
|
||||||
|
* @param counter - the number of passes through the current node.
|
||||||
|
*/
|
||||||
|
public NodeGraph(final Integer id, final String name, final int counter) {
|
||||||
|
super(id);
|
||||||
|
this.name = name;
|
||||||
|
this.counter = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCounter() {
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCounter(final int counter) {
|
||||||
|
this.counter = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NodeGraph nodeGraph = (NodeGraph) o;
|
||||||
|
return Objects.equals(id, nodeGraph.id)
|
||||||
|
&& counter == nodeGraph.counter
|
||||||
|
&& name.equals(nodeGraph.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, name, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{"
|
||||||
|
+ "\"id\": \"" + id + '"'
|
||||||
|
+ ", \"name\": \"" + name + '"'
|
||||||
|
+ ", \"counter\":" + counter
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for transport object that implements undirected graph edge.
|
||||||
|
*/
|
||||||
|
public static class EdgeGraph extends BaseDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique name of first graph node.
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "nodeOne: " + VALIDATOR_NODE_NOT_BLANK_NAME_MESSAGE)
|
||||||
|
@Size(min = MIN_NAME_SIZE, max = MAX_NAME_SIZE)
|
||||||
|
private String nodeOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique name of second graph node.
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "nodeTwo: " + VALIDATOR_NODE_NOT_BLANK_NAME_MESSAGE)
|
||||||
|
@Size(min = MIN_NAME_SIZE, max = MAX_NAME_SIZE)
|
||||||
|
private String nodeTwo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
public EdgeGraph() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param edge - object of undirected graph edge.
|
||||||
|
*/
|
||||||
|
public EdgeGraph(final EdgeGraph edge) {
|
||||||
|
this(edge.getId(), edge.getNodeOne(), edge.getNodeTwo());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param nodeOne - unique name of first graph node.
|
||||||
|
* @param nodeTwo - unique name of second graph node.
|
||||||
|
*/
|
||||||
|
public EdgeGraph(final String nodeOne, final String nodeTwo) {
|
||||||
|
this(null, nodeOne, nodeTwo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param nodeOne - object of first graph node.
|
||||||
|
* @param nodeTwo - object of second graph node.
|
||||||
|
*/
|
||||||
|
public EdgeGraph(final NodeGraph nodeOne, final NodeGraph nodeTwo) {
|
||||||
|
this(null, nodeOne.getName(), nodeTwo.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id - identity number of graph edge.
|
||||||
|
* @param nodeOne - unique name of first graph node.
|
||||||
|
* @param nodeTwo - unique name of second graph node.
|
||||||
|
*/
|
||||||
|
public EdgeGraph(final Integer id, final String nodeOne, final String nodeTwo) {
|
||||||
|
super(id);
|
||||||
|
this.nodeOne = nodeOne;
|
||||||
|
this.nodeTwo = nodeTwo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id - identity number of graph edge.
|
||||||
|
* @param nodeOne - object of first graph node.
|
||||||
|
* @param nodeTwo - object of second graph node.
|
||||||
|
*/
|
||||||
|
public EdgeGraph(final Integer id, final NodeGraph nodeOne, final NodeGraph nodeTwo) {
|
||||||
|
super(id);
|
||||||
|
this.nodeOne = nodeOne.getName();
|
||||||
|
this.nodeTwo = nodeTwo.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getNodeOne() {
|
||||||
|
return nodeOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setNodeOne(final String nodeOne) {
|
||||||
|
this.nodeOne = nodeOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeTwo() {
|
||||||
|
return nodeTwo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeTwo(final String nodeTwo) {
|
||||||
|
this.nodeTwo = nodeTwo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
EdgeGraph edgeGraph = (EdgeGraph) o;
|
||||||
|
return nodeOne.equals(edgeGraph.nodeOne)
|
||||||
|
&& nodeTwo.equals(edgeGraph.nodeTwo)
|
||||||
|
&& Objects.equals(id, edgeGraph.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, nodeOne, nodeTwo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{"
|
||||||
|
+ "\"id\": \"" + id + '"'
|
||||||
|
+ ", \"nodeOne\": \""
|
||||||
|
+ nodeOne + '"'
|
||||||
|
+ ", \"nodeTwo\": \""
|
||||||
|
+ nodeTwo + '"'
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of graph nodes.
|
||||||
|
*/
|
||||||
|
private Set<@Valid NodeGraph> nodes = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of graph edges.
|
||||||
|
*/
|
||||||
|
private Set<@Valid EdgeGraph> edges = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
public GraphDto() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param nodes - collection of graph nodes {@link NodeGraph}.
|
||||||
|
* @param edges - collection of graph edges {@link EdgeGraph}.
|
||||||
|
*/
|
||||||
|
public GraphDto(final Set<NodeGraph> nodes, final Set<EdgeGraph> edges) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
this.edges = edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<NodeGraph> getNodes() {
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodes(final Set<NodeGraph> nodes) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Set<EdgeGraph> getEdges() {
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEdges(final Set<EdgeGraph> edges) {
|
||||||
|
this.edges = edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return "{"
|
||||||
|
+ "\"nodes\": "
|
||||||
|
+ nodes
|
||||||
|
+ ", \"edges\": "
|
||||||
|
+ edges
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package ru.resprojects.linkchecker.model;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import ru.resprojects.linkchecker.HasId;
|
||||||
|
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.persistence.SequenceGenerator;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for database entity.
|
||||||
|
*/
|
||||||
|
@MappedSuperclass
|
||||||
|
public abstract class AbstractBaseEntity implements HasId, Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -5006383911943128194L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial number for database id sequential.
|
||||||
|
*/
|
||||||
|
private static final int START_SEQ = 5000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identity for database entity.
|
||||||
|
*/
|
||||||
|
@Id
|
||||||
|
@SequenceGenerator(name = "global_seq", sequenceName = "global_seq",
|
||||||
|
allocationSize = 1, initialValue = START_SEQ)
|
||||||
|
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq")
|
||||||
|
protected Integer id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
AbstractBaseEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id - unique database entity identity.
|
||||||
|
*/
|
||||||
|
AbstractBaseEntity(final Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unique database entity identity.
|
||||||
|
* @return unique database entity identity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set unique database entity identity.
|
||||||
|
* @param id of database entity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setId(final Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Entity %s (%s)", getClass().getName(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || !getClass().equals(Hibernate.getClass(o))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AbstractBaseEntity that = (AbstractBaseEntity) o;
|
||||||
|
return id != null && id.equals(that.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id == null ? 0 : id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package ru.resprojects.linkchecker.model;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.util.ValidationUtil.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for named database entity.
|
||||||
|
*/
|
||||||
|
@MappedSuperclass
|
||||||
|
public abstract class AbstractNamedEntity extends AbstractBaseEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 6679903940869239340L;
|
||||||
|
/**
|
||||||
|
* Unique name of database entity.
|
||||||
|
*/
|
||||||
|
@Column(name = "name", nullable = false, unique = true)
|
||||||
|
@NotBlank(message = VALIDATOR_NODE_NOT_BLANK_NAME_MESSAGE)
|
||||||
|
@Size(min = MIN_NAME_SIZE, max = MAX_NAME_SIZE,
|
||||||
|
message = VALIDATOR_NODE_NAME_RANGE_MESSAGE)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
AbstractNamedEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id of database entity.
|
||||||
|
* @param name unique name of database entity.
|
||||||
|
*/
|
||||||
|
AbstractNamedEntity(final Integer id, final String name) {
|
||||||
|
super(id);
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set unique name of database entity.
|
||||||
|
* @param name unique name of database entity.
|
||||||
|
*/
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unique name of database entity.
|
||||||
|
* @return unique name of database entity.
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Entity %s (%s, '%s')",
|
||||||
|
getClass().getName(), getId(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
108
src/main/java/ru/resprojects/linkchecker/model/Edge.java
Normal file
108
src/main/java/ru/resprojects/linkchecker/model/Edge.java
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package ru.resprojects.linkchecker.model;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
import ru.resprojects.linkchecker.util.ValidationUtil;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "edges", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(
|
||||||
|
columnNames = {"nodeone", "nodetwo"},
|
||||||
|
name = "unique_edge"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
public class Edge extends AbstractBaseEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -5267484684381196999L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First object of graph node.
|
||||||
|
*/
|
||||||
|
@OneToOne(fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "nodeone", nullable = false)
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
@NotNull(message = ValidationUtil.VALIDATOR_NOT_NULL_MESSAGE)
|
||||||
|
private Node nodeOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second object of graph node.
|
||||||
|
*/
|
||||||
|
@OneToOne(fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "nodetwo", nullable = false)
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
@NotNull(message = ValidationUtil.VALIDATOR_NOT_NULL_MESSAGE)
|
||||||
|
private Node nodeTwo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
public Edge() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param edge - object of undirected graph edge.
|
||||||
|
*/
|
||||||
|
public Edge(final Edge edge) {
|
||||||
|
this(edge.getId(), edge.getNodeOne(), edge.getNodeTwo());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param nodeOne - first object of graph node.
|
||||||
|
* @param nodeTwo - second object of graph node.
|
||||||
|
*/
|
||||||
|
public Edge(final Node nodeOne, final Node nodeTwo) {
|
||||||
|
this(null, nodeOne, nodeTwo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id - unique identity for database graph edge entity.
|
||||||
|
* @param nodeOne - first object of graph node.
|
||||||
|
* @param nodeTwo - second object of graph node.
|
||||||
|
*/
|
||||||
|
public Edge(final Integer id, final Node nodeOne, final Node nodeTwo) {
|
||||||
|
this.id = id;
|
||||||
|
this.nodeOne = nodeOne;
|
||||||
|
this.nodeTwo = nodeTwo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNodeOne() {
|
||||||
|
return nodeOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeOne(final Node nodeOne) {
|
||||||
|
this.nodeOne = nodeOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNodeTwo() {
|
||||||
|
return nodeTwo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeTwo(final Node nodeTwo) {
|
||||||
|
this.nodeTwo = nodeTwo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Edge{"
|
||||||
|
+ "id=" + getId()
|
||||||
|
+ ", nodeOne="
|
||||||
|
+ nodeOne
|
||||||
|
+ ", nodeTwo="
|
||||||
|
+ nodeTwo
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/main/java/ru/resprojects/linkchecker/model/Node.java
Normal file
82
src/main/java/ru/resprojects/linkchecker/model/Node.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package ru.resprojects.linkchecker.model;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.util.ValidationUtil.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "nodes", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(columnNames = "name", name = "nodes_unique_name_idx")
|
||||||
|
})
|
||||||
|
public class Node extends AbstractNamedEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 5592849608806842551L;
|
||||||
|
|
||||||
|
private static final String DEFAULT_COUNTER_VALUE = "int default " +
|
||||||
|
NODE_COUNTER_DEFAULT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of passes through the node of the graph.
|
||||||
|
*/
|
||||||
|
@Column(name = "counter", columnDefinition = DEFAULT_COUNTER_VALUE)
|
||||||
|
private int counter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default ctor.
|
||||||
|
*/
|
||||||
|
public Node() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param node - node of the graph database entity.
|
||||||
|
*/
|
||||||
|
public Node(final Node node) {
|
||||||
|
this(node.getId(), node.getName(), node.getCounter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param name - unique name of database entity that implement graph node.
|
||||||
|
*/
|
||||||
|
public Node(final String name) {
|
||||||
|
super(null, name);
|
||||||
|
this.counter = NODE_COUNTER_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param id - unique identity for database graph node entity.
|
||||||
|
* @param name - unique name of database entity that implement graph node.
|
||||||
|
* @param counter - number of passes through the node of the graph.
|
||||||
|
*/
|
||||||
|
public Node(final Integer id, final String name, final int counter) {
|
||||||
|
super(id, name);
|
||||||
|
this.counter = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCounter() {
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCounter(final int counter) {
|
||||||
|
this.counter = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Node{"
|
||||||
|
+ "id=" + getId()
|
||||||
|
+ ", name='" + getName() + '\''
|
||||||
|
+ ", counter=" + counter
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package ru.resprojects.linkchecker.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public interface EdgeRepository extends JpaRepository<Edge, Integer> {
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
<S extends Edge> S save(S edge);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
<S extends Edge> List<S> saveAll(Iterable<S> entities);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void deleteById(int id);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void deleteAllInBatch();
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void deleteInBatch(Iterable<Edge> entities);
|
||||||
|
|
||||||
|
Optional<Edge> findEdgeByNodeOneAndNodeTwo(Node nodeOne, Node nodeTwo);
|
||||||
|
|
||||||
|
List<Edge> findEdgesByNodeOneOrNodeTwo(Node nodeOne, Node nodeTwo);
|
||||||
|
|
||||||
|
boolean existsById(int id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package ru.resprojects.linkchecker.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public interface NodeRepository extends JpaRepository<Node, Integer> {
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
<S extends Node> S save(S node);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
<S extends Node> List<S> saveAll(Iterable<S> entities);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void deleteById(Integer id);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void deleteByName(String name);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
void deleteAllInBatch();
|
||||||
|
|
||||||
|
Node getByName(String name);
|
||||||
|
|
||||||
|
boolean existsByName(String name);
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GraphEdgeService - the interface for work with graph edges.
|
||||||
|
*/
|
||||||
|
public interface GraphEdgeService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create edge of the graph. Nodes that linked by the edge, must be
|
||||||
|
* exist in graph, else throw exception.
|
||||||
|
* @param edgeGraph edge {@link EdgeGraph} of the graph.
|
||||||
|
* @return added graph edge.
|
||||||
|
* @throws NotFoundException while creating edge
|
||||||
|
*/
|
||||||
|
EdgeGraph create(final EdgeGraph edgeGraph) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch creation edges of the graph. Nodes that linked by the edge, must be
|
||||||
|
* exist in graph, else throw exception.
|
||||||
|
* @param edgeGraphs set of graph edges {@link EdgeGraph}
|
||||||
|
* @return added graph edges.
|
||||||
|
* @throws NotFoundException while creating edges
|
||||||
|
*/
|
||||||
|
Set<EdgeGraph> create(final Set<EdgeGraph> edgeGraphs) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search edge of the graph by id and delete from graph.
|
||||||
|
* @param id of edge of the graph.
|
||||||
|
* @throws NotFoundException if edge is not found in the graph.
|
||||||
|
*/
|
||||||
|
void delete(final Integer id) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search edges by unique name of the graph node and delete them from graph.
|
||||||
|
* Since the edge describes the connection of two nodes, the search occurs
|
||||||
|
* on the node one or node two.
|
||||||
|
* @param nodeName unique name of the graph node.
|
||||||
|
* @throws NotFoundException if edge is not found in the graph.
|
||||||
|
*/
|
||||||
|
void delete(final String nodeName) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search edge of the graph by node one and node two and if edge contain
|
||||||
|
* both these nodes then delete edge from graph.
|
||||||
|
* @param nodeNameOne unique name of the first graph node.
|
||||||
|
* @param nodeNameTwo unique name of the second graph node.
|
||||||
|
* @throws NotFoundException if edge is not found in the graph.
|
||||||
|
*/
|
||||||
|
void delete(final String nodeNameOne, final String nodeNameTwo) throws NotFoundException;
|
||||||
|
|
||||||
|
void delete(final Set<Edge> edges) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removing all edges from the graph.
|
||||||
|
*/
|
||||||
|
void deleteAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search edge of the graph by node one and node two and if edge contain
|
||||||
|
* both these nodes then return edge else throw exception.
|
||||||
|
* @param nodeNameOne unique name of the first graph node.
|
||||||
|
* @param nodeNameTwo unique name of the second graph node.
|
||||||
|
* @return graph edge {@link EdgeGraph}.
|
||||||
|
* @throws NotFoundException if edge is not found in the graph.
|
||||||
|
*/
|
||||||
|
EdgeGraph get(final String nodeNameOne, final String nodeNameTwo) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search edges by unique name of the graph node and return it.
|
||||||
|
* Since the edge describes the connection of two nodes, the search occurs
|
||||||
|
* on the node one or node two.
|
||||||
|
* @param nodeName unique name of the graph node.
|
||||||
|
* @return set of edges of the graph
|
||||||
|
*/
|
||||||
|
Set<EdgeGraph> get(final String nodeName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get edge of the graph by id.
|
||||||
|
* @param id of edge ot the graph.
|
||||||
|
* @return edge {@link EdgeGraph} of the graph.
|
||||||
|
* @throws NotFoundException if edge is not found in the graph.
|
||||||
|
*/
|
||||||
|
EdgeGraph getById(final Integer id) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all edges from graph.
|
||||||
|
* @return set of edges ot the graph.
|
||||||
|
*/
|
||||||
|
Set<EdgeGraph> getAll();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
import ru.resprojects.linkchecker.repositories.EdgeRepository;
|
||||||
|
import ru.resprojects.linkchecker.repositories.NodeRepository;
|
||||||
|
import ru.resprojects.linkchecker.util.GraphUtil;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.util.ValidationUtil.checkNotFound;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GraphEdgeServiceImpl implements GraphEdgeService {
|
||||||
|
|
||||||
|
private final EdgeRepository edgeRepository;
|
||||||
|
private final NodeRepository nodeRepository;
|
||||||
|
private final AppProperties properties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GraphEdgeServiceImpl(final EdgeRepository edgeRepository,
|
||||||
|
final NodeRepository nodeRepository, final AppProperties properties) {
|
||||||
|
this.edgeRepository = edgeRepository;
|
||||||
|
this.nodeRepository = nodeRepository;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPresent(final Node nodeOne, final Node nodeTwo) {
|
||||||
|
try {
|
||||||
|
get(nodeOne.getName(), nodeTwo.getName());
|
||||||
|
return true;
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EdgeGraph create(final EdgeGraph edgeGraph) throws NotFoundException {
|
||||||
|
if (Objects.isNull(edgeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.EDGE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Node nodeOne = checkNotFound(
|
||||||
|
nodeRepository.getByName(edgeGraph.getNodeOne()),
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), edgeGraph.getNodeOne()),
|
||||||
|
ErrorPlaceType.EDGE
|
||||||
|
);
|
||||||
|
Node nodeTwo = checkNotFound(
|
||||||
|
nodeRepository.getByName(edgeGraph.getNodeTwo()),
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), edgeGraph.getNodeTwo()),
|
||||||
|
ErrorPlaceType.EDGE
|
||||||
|
);
|
||||||
|
if (isPresent(nodeOne, nodeTwo)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.EDGE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
String.format(
|
||||||
|
properties.getEdgeMsg().get("EDGE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
nodeOne.getName(),
|
||||||
|
nodeTwo.getName(),
|
||||||
|
nodeTwo.getName(),
|
||||||
|
nodeOne.getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Edge edge = new Edge(nodeOne, nodeTwo);
|
||||||
|
return GraphUtil.edgeToEdgeGraph(edgeRepository.save(edge));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<EdgeGraph> create(final Set<EdgeGraph> edgeGraphs) throws NotFoundException {
|
||||||
|
if (Objects.isNull(edgeGraphs)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.EDGE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (edgeGraphs.isEmpty()) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.EDGE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_COLLECTION_EMPTY")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Map<EdgeGraph, Map<String, Node>> nodes = new HashMap<>();
|
||||||
|
for (EdgeGraph edgeGraph : edgeGraphs) {
|
||||||
|
if (Objects.isNull(edgeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.EDGE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Node nodeOne = checkNotFound(
|
||||||
|
nodeRepository.getByName(edgeGraph.getNodeOne()),
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), edgeGraph.getNodeOne()),
|
||||||
|
ErrorPlaceType.EDGE
|
||||||
|
);
|
||||||
|
Node nodeTwo = checkNotFound(
|
||||||
|
nodeRepository.getByName(edgeGraph.getNodeTwo()),
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), edgeGraph.getNodeTwo()),
|
||||||
|
ErrorPlaceType.EDGE
|
||||||
|
);
|
||||||
|
if (isPresent(nodeOne, nodeTwo)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.EDGE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
String.format(
|
||||||
|
properties.getEdgeMsg().get("EDGE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
nodeOne.getName(),
|
||||||
|
nodeTwo.getName(),
|
||||||
|
nodeTwo.getName(),
|
||||||
|
nodeOne.getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Map<String, Node> nodeMap = new HashMap<>();
|
||||||
|
nodeMap.put(edgeGraph.getNodeOne(), nodeOne);
|
||||||
|
nodeMap.put(edgeGraph.getNodeTwo(), nodeTwo);
|
||||||
|
nodes.put(edgeGraph, nodeMap);
|
||||||
|
}
|
||||||
|
List<Edge> edges = edgeGraphs.stream()
|
||||||
|
.map(eg -> new Edge(
|
||||||
|
nodes.get(eg).get(eg.getNodeOne()),
|
||||||
|
nodes.get(eg).get(eg.getNodeTwo()))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
return GraphUtil.edgesToEdgeGraphs(edgeRepository.saveAll(edges));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(final Integer id) throws NotFoundException {
|
||||||
|
if (edgeRepository.existsById(id)) {
|
||||||
|
edgeRepository.deleteById(id);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), ErrorPlaceType.EDGE, id), ErrorPlaceType.EDGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(final String nodeName) throws NotFoundException {
|
||||||
|
List<Edge> edges = getEdges(nodeName);
|
||||||
|
if (edges.isEmpty()) {
|
||||||
|
throw new NotFoundException(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_BY_NAME_ERROR"), nodeName), ErrorPlaceType.EDGE);
|
||||||
|
}
|
||||||
|
edgeRepository.deleteInBatch(edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(final String nodeNameOne, final String nodeNameTwo) throws NotFoundException {
|
||||||
|
Edge edge = checkNotFound(getEdge(nodeNameOne, nodeNameTwo),
|
||||||
|
String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_ERROR"), nodeNameOne, nodeNameTwo),
|
||||||
|
ErrorPlaceType.EDGE);
|
||||||
|
edgeRepository.delete(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(Set<Edge> edges) throws NotFoundException {
|
||||||
|
edgeRepository.deleteInBatch(edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAll() {
|
||||||
|
edgeRepository.deleteAllInBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EdgeGraph get(final String nodeNameOne, final String nodeNameTwo) throws NotFoundException {
|
||||||
|
EdgeGraph edgeGraph = GraphUtil.edgeToEdgeGraph(getEdge(nodeNameOne, nodeNameTwo));
|
||||||
|
return checkNotFound(edgeGraph,
|
||||||
|
String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_ERROR"), nodeNameOne, nodeNameTwo),
|
||||||
|
ErrorPlaceType.EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Edge getEdge(final String nodeNameOne, final String nodeNameTwo) {
|
||||||
|
Node nodeOne = nodeRepository.getByName(nodeNameOne);
|
||||||
|
Node nodeTwo = nodeRepository.getByName(nodeNameTwo);
|
||||||
|
return edgeRepository.findEdgeByNodeOneAndNodeTwo(nodeOne, nodeTwo)
|
||||||
|
.orElse(edgeRepository.findEdgeByNodeOneAndNodeTwo(nodeTwo, nodeOne).orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<EdgeGraph> get(final String nodeName) {
|
||||||
|
List<Edge> result = getEdges(nodeName);
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
throw new NotFoundException(String.format(properties.getEdgeMsg()
|
||||||
|
.get("EDGE_MSG_GET_BY_NAME_ERROR"), nodeName), ErrorPlaceType.EDGE);
|
||||||
|
}
|
||||||
|
return GraphUtil.edgesToEdgeGraphs(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Edge> getEdges(final String nodeName) {
|
||||||
|
Node node = nodeRepository.getByName(nodeName);
|
||||||
|
return edgeRepository.findEdgesByNodeOneOrNodeTwo(node, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EdgeGraph getById(final Integer id) throws NotFoundException {
|
||||||
|
EdgeGraph edgeGraph = GraphUtil.edgeToEdgeGraph(edgeRepository.findById(id)
|
||||||
|
.orElse(null));
|
||||||
|
return checkNotFound(edgeGraph, String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"),
|
||||||
|
ErrorPlaceType.EDGE, id), ErrorPlaceType.EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<EdgeGraph> getAll() {
|
||||||
|
return GraphUtil.edgesToEdgeGraphs(edgeRepository.findAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GraphNodeService - the interface for work with graph nodes.
|
||||||
|
*/
|
||||||
|
public interface GraphNodeService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create node of the graph.
|
||||||
|
* @param nodeGraph graph node {@link NodeGraph}
|
||||||
|
* @return added graph node.
|
||||||
|
*/
|
||||||
|
NodeGraph create(final NodeGraph nodeGraph);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch creation nodes of the graph
|
||||||
|
* @param nodeGraphs set of graph nodes {@link NodeGraph}
|
||||||
|
* @return added graph nodes.
|
||||||
|
*/
|
||||||
|
Set<NodeGraph> create(final Set<NodeGraph> nodeGraphs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update node of the graph.
|
||||||
|
* @param nodeGraph graph node {@link NodeGraph}
|
||||||
|
* @throws NotFoundException if node not updated
|
||||||
|
*/
|
||||||
|
void update(final NodeGraph nodeGraph) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search graph node by id and delete from graph.
|
||||||
|
* @param id of node of the graph.
|
||||||
|
* @throws NotFoundException if node not found in the graph.
|
||||||
|
*/
|
||||||
|
void delete(final Integer id) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search graph node by unique name and delete from graph.
|
||||||
|
* @param name unique name of graph node.
|
||||||
|
* @throws NotFoundException if node not found in the graph.
|
||||||
|
*/
|
||||||
|
void delete(final String name) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search graph node by object {@link NodeGraph} and delete from graph.
|
||||||
|
* @param nodeGraph object {@link NodeGraph}.
|
||||||
|
* @throws NotFoundException if node not found in the graph.
|
||||||
|
*/
|
||||||
|
void delete(final NodeGraph nodeGraph) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will be deleted all nodes and edges associated with
|
||||||
|
* these nodes in the graph.
|
||||||
|
*/
|
||||||
|
void deleteAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search and return graph node by unique name.
|
||||||
|
* @param name unique name of graph node.
|
||||||
|
* @return node of the graph.
|
||||||
|
* @throws NotFoundException if node not found in the graph.
|
||||||
|
*/
|
||||||
|
NodeGraph get(final String name) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search and return graph node by id.
|
||||||
|
* @param id of node of the graph.
|
||||||
|
* @return node of the graph.
|
||||||
|
* @throws NotFoundException if node not found in the graph.
|
||||||
|
*/
|
||||||
|
NodeGraph getById(final Integer id) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all graph nodes.
|
||||||
|
* @return set of graph nodes.
|
||||||
|
*/
|
||||||
|
Set<NodeGraph> getAll();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.repositories.NodeRepository;
|
||||||
|
import ru.resprojects.linkchecker.util.GraphUtil;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.util.ValidationUtil.checkNotFound;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GraphNodeServiceImpl implements GraphNodeService {
|
||||||
|
|
||||||
|
private final NodeRepository nodeRepository;
|
||||||
|
private final AppProperties properties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GraphNodeServiceImpl(final NodeRepository nodeRepository, final AppProperties properties) {
|
||||||
|
this.nodeRepository = nodeRepository;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPresent(final NodeGraph nodeGraph) {
|
||||||
|
try {
|
||||||
|
get(nodeGraph.getName());
|
||||||
|
return true;
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeGraph create(final NodeGraph nodeGraph) {
|
||||||
|
if (Objects.isNull(nodeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isPresent(nodeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
nodeGraph.getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return GraphUtil.nodeToNodeGraph(nodeRepository.save(
|
||||||
|
GraphUtil.nodeGraphToNode(nodeGraph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<NodeGraph> create(Set<NodeGraph> nodeGraphs) {
|
||||||
|
if (Objects.isNull(nodeGraphs)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (nodeGraphs.isEmpty()) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_COLLECTION_EMPTY")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nodeGraphs.forEach(nodeGraph -> {
|
||||||
|
if (Objects.isNull(nodeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isPresent(nodeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
nodeGraph.getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return GraphUtil.nodesToNodeGraphs(nodeRepository.saveAll(
|
||||||
|
GraphUtil.nodeGraphsToNodes(nodeGraphs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(final NodeGraph nodeGraph) throws NotFoundException {
|
||||||
|
if (Objects.isNull(nodeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
checkNotFound(nodeRepository.save(
|
||||||
|
GraphUtil.nodeGraphToNode(nodeGraph)),
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_UPDATE_ERROR") + nodeGraph.getId(),
|
||||||
|
ErrorPlaceType.NODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(final Integer id) throws NotFoundException {
|
||||||
|
if (nodeRepository.existsById(id)) {
|
||||||
|
nodeRepository.deleteById(id);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException(String.format(
|
||||||
|
properties.getAppMsg().get("MSG_BY_ID_ERROR"),
|
||||||
|
ErrorPlaceType.NODE, id
|
||||||
|
), ErrorPlaceType.NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(final String name) throws NotFoundException {
|
||||||
|
if (nodeRepository.existsByName(name)) {
|
||||||
|
nodeRepository.deleteByName(name);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"),
|
||||||
|
name
|
||||||
|
), ErrorPlaceType.NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(final NodeGraph nodeGraph) throws NotFoundException {
|
||||||
|
if (Objects.isNull(nodeGraph)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.NODE,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
NodeGraph nodeFromRepo = GraphUtil.nodeToNodeGraph(nodeRepository
|
||||||
|
.findById(nodeGraph.getId()).orElse(null));
|
||||||
|
if (nodeGraph.equals(nodeFromRepo)) {
|
||||||
|
nodeRepository.deleteById(nodeGraph.getId());
|
||||||
|
} else {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new NotFoundException(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"),
|
||||||
|
nodeGraph.toString()
|
||||||
|
), ErrorPlaceType.NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAll() {
|
||||||
|
nodeRepository.deleteAllInBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<NodeGraph> getAll() {
|
||||||
|
return GraphUtil.nodesToNodeGraphs(nodeRepository.findAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeGraph get(final String name) throws NotFoundException {
|
||||||
|
NodeGraph nodeGraph = GraphUtil.nodeToNodeGraph(nodeRepository.getByName(name));
|
||||||
|
return checkNotFound(nodeGraph,
|
||||||
|
String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"),
|
||||||
|
name
|
||||||
|
), ErrorPlaceType.NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeGraph getById(final Integer id) throws NotFoundException {
|
||||||
|
NodeGraph nodeGraph = GraphUtil.nodeToNodeGraph(nodeRepository
|
||||||
|
.findById(id).orElse(null));
|
||||||
|
return checkNotFound(nodeGraph,
|
||||||
|
String.format(
|
||||||
|
properties.getAppMsg().get("MSG_BY_ID_ERROR"),
|
||||||
|
ErrorPlaceType.NODE, id
|
||||||
|
), ErrorPlaceType.NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GraphService - the interface for work with <a href = https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)#Graph>undirected graph</a>.
|
||||||
|
*/
|
||||||
|
public interface GraphService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checking input graph data, removing cycles from input graph and saving it
|
||||||
|
* to the DB.
|
||||||
|
* @param graphTo graph {@link GraphDto}
|
||||||
|
* @return graph.
|
||||||
|
* @throws ApplicationException if found errors.
|
||||||
|
*/
|
||||||
|
GraphDto create(final GraphDto graphTo) throws ApplicationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get graph.
|
||||||
|
* @return graph {@link GraphDto}
|
||||||
|
*/
|
||||||
|
GraphDto get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove graph.
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checking route between nodes.
|
||||||
|
* @param nodeNameSet collection of the unique nodes name.
|
||||||
|
* @return check result in JSON format.
|
||||||
|
* @throws NotFoundException if route is not found
|
||||||
|
*/
|
||||||
|
String checkRoute(final Set<String> nodeNameSet) throws NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exporting graph to <a href = https://www.graphviz.org/about/>graphviz</a> format.
|
||||||
|
* @return string data in graphviz format.
|
||||||
|
*/
|
||||||
|
String exportToGraphViz();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to nodes of the graph.
|
||||||
|
* @return {@link GraphNodeService}
|
||||||
|
*/
|
||||||
|
GraphNodeService getNodes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to edges of the graph.
|
||||||
|
* @return {@link GraphEdgeService}
|
||||||
|
*/
|
||||||
|
GraphEdgeService getEdges();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.jgrapht.Graph;
|
||||||
|
import org.jgrapht.alg.interfaces.ShortestPathAlgorithm;
|
||||||
|
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
|
||||||
|
import org.jgrapht.graph.DefaultEdge;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.model.AbstractNamedEntity;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
import ru.resprojects.linkchecker.util.GraphUtil;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.util.GraphUtil.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GraphServiceImpl implements GraphService {
|
||||||
|
|
||||||
|
private final GraphEdgeService edges;
|
||||||
|
private final GraphNodeService nodes;
|
||||||
|
private final AppProperties properties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GraphServiceImpl(final GraphEdgeService edges, final GraphNodeService nodes, final AppProperties properties) {
|
||||||
|
this.edges = edges;
|
||||||
|
this.nodes = nodes;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphDto create(final GraphDto graphTo) throws ApplicationException {
|
||||||
|
if (Objects.isNull(graphTo)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.GRAPH,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (graphTo.getNodes().isEmpty() && !graphTo.getEdges().isEmpty()) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.GRAPH,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
"NODES: " + properties.getAppMsg().get("MSG_COLLECTION_EMPTY")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
GraphDto graph = graphToGraphDto(
|
||||||
|
removeCyclesFromGraph(graphBuilder(graphTo.getNodes(), graphTo.getEdges())));
|
||||||
|
Set<NodeGraph> nodeGraphSet = nodes.create(graph.getNodes());
|
||||||
|
Set<EdgeGraph> edgeGraphSet = edges.create(graph.getEdges());
|
||||||
|
return new GraphDto(nodeGraphSet, edgeGraphSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphDto get() {
|
||||||
|
return removeGraphCycles(new GraphDto(nodes.getAll(), edges.getAll()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String exportToGraphViz() {
|
||||||
|
return GraphUtil.exportToGraphViz(get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
nodes.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String checkRoute(final Set<String> nodeNameSet) throws NotFoundException {
|
||||||
|
if (Objects.isNull(nodeNameSet)) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.GRAPH,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_ARGUMENT_NULL")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (nodeNameSet.isEmpty()) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.GRAPH,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_COLLECTION_EMPTY")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (nodeNameSet.size() == 1) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
ErrorType.DATA_ERROR,
|
||||||
|
ErrorPlaceType.GRAPH,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_ONE_ELEMENT")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GraphDto graphDto = removeGraphCycles(new GraphDto(nodes.getAll(),
|
||||||
|
edges.getAll()));
|
||||||
|
Map<String, Boolean> faultNodes = getRandomNodeFault(graphDto.getNodes());
|
||||||
|
List<String> nodeNameList = new ArrayList<>(nodeNameSet);
|
||||||
|
Graph<Node, DefaultEdge> graph = graphBuilder(graphDto.getNodes(),
|
||||||
|
graphDto.getEdges());
|
||||||
|
DijkstraShortestPath<Node, DefaultEdge> dAlg = new DijkstraShortestPath<>(graph);
|
||||||
|
Node firstNode = nodeGraphToNode(graphDto.getNodes().stream()
|
||||||
|
.filter(ng -> ng.getName().equalsIgnoreCase(nodeNameList.get(0)))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null));
|
||||||
|
if (Objects.isNull(firstNode)) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), nodeNameList.get(0)),
|
||||||
|
ErrorPlaceType.GRAPH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ShortestPathAlgorithm.SingleSourcePaths<Node, DefaultEdge> paths = dAlg.getPaths(firstNode);
|
||||||
|
if (faultNodes.getOrDefault(firstNode.getName(), false)) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_IS_FAULT"), firstNode.getName()),
|
||||||
|
ErrorPlaceType.GRAPH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nodeNameList.stream().skip(1).forEach(name -> {
|
||||||
|
Node nextNode = nodeGraphToNode(graphDto.getNodes().stream()
|
||||||
|
.filter(ng -> ng.getName().equalsIgnoreCase(name))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null));
|
||||||
|
if (Objects.isNull(nextNode)) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), name),
|
||||||
|
ErrorPlaceType.GRAPH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (faultNodes.getOrDefault(nextNode.getName(), false)) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_IS_FAULT"), name),
|
||||||
|
ErrorPlaceType.GRAPH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
List<Node> findNodes = paths.getPath(nextNode).getVertexList();
|
||||||
|
List<String> findNodesName = findNodes.stream()
|
||||||
|
.map(AbstractNamedEntity::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!nodeNameList.containsAll(findNodesName)) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
String.format(properties.getNodeMsg().get("NODE_MSG_NOT_REACHABLE"), nodeNameList.get(0), name),
|
||||||
|
ErrorPlaceType.GRAPH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nodeNameList.forEach(name ->
|
||||||
|
graphDto.getNodes().stream()
|
||||||
|
.filter(ng -> ng.getName().equalsIgnoreCase(name))
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(ng -> {
|
||||||
|
ng.setCounter(ng.getCounter() + 1);
|
||||||
|
nodes.update(ng);
|
||||||
|
}));
|
||||||
|
return String.format("Route for nodes %s is found", nodeNameList.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private GraphDto removeGraphCycles(final GraphDto graph) {
|
||||||
|
if (Objects.isNull(graph) || graph.getEdges().isEmpty()) {
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
GraphDto optimizedGraph = graphToGraphDto(
|
||||||
|
removeCyclesFromGraph(graphBuilder(graph.getNodes(), graph.getEdges())));
|
||||||
|
//Checking, was removed edges or not from graph after optimizing
|
||||||
|
if (graph.getEdges().size() == optimizedGraph.getEdges().size()) {
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
//Because ID's lost's in optimized graph, we need recover them.
|
||||||
|
Set<EdgeGraph> optimizedEdges = graph.getEdges().stream()
|
||||||
|
.filter(e -> optimizedGraph.getEdges().stream()
|
||||||
|
.anyMatch(eg -> eg.getNodeOne().equalsIgnoreCase(e.getNodeOne())
|
||||||
|
&& eg.getNodeTwo().equalsIgnoreCase(e.getNodeTwo())))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
//Rewrite edge collection in optimized graph.
|
||||||
|
optimizedGraph.setEdges(optimizedEdges);
|
||||||
|
//Search all edges that was removed from graph and remove them from DB.
|
||||||
|
Set<EdgeGraph> removedEdgesGraph = graph.getEdges().stream()
|
||||||
|
.filter(eg -> !optimizedGraph.getEdges().contains(eg))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<Edge> removedEdges = getEdgesFromGraphDto(new GraphDto(
|
||||||
|
optimizedGraph.getNodes(),
|
||||||
|
removedEdgesGraph));
|
||||||
|
if (!removedEdges.isEmpty()) {
|
||||||
|
edges.delete(removedEdges);
|
||||||
|
return optimizedGraph;
|
||||||
|
}
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphEdgeService getEdges() {
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphNodeService getNodes() {
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
348
src/main/java/ru/resprojects/linkchecker/util/GraphUtil.java
Normal file
348
src/main/java/ru/resprojects/linkchecker/util/GraphUtil.java
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
package ru.resprojects.linkchecker.util;
|
||||||
|
|
||||||
|
import org.jgrapht.Graph;
|
||||||
|
import org.jgrapht.GraphPath;
|
||||||
|
import org.jgrapht.Graphs;
|
||||||
|
import org.jgrapht.alg.cycle.PatonCycleBase;
|
||||||
|
import org.jgrapht.graph.DefaultEdge;
|
||||||
|
import org.jgrapht.graph.SimpleGraph;
|
||||||
|
import org.jgrapht.io.ComponentNameProvider;
|
||||||
|
import org.jgrapht.io.DOTExporter;
|
||||||
|
import org.jgrapht.io.GraphExporter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for work with graph.
|
||||||
|
*/
|
||||||
|
public class GraphUtil {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
*/
|
||||||
|
private GraphUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Building graph in <a href = https://github.com/jgrapht/jgrapht/blob/master/README.md>JGraphT</a> format
|
||||||
|
* from collections of the nodes and edges.
|
||||||
|
* @param nodesGraph collection of nodes {@link NodeGraph}.
|
||||||
|
* @param edgesGraph collection of edges {@link EdgeGraph}.
|
||||||
|
* @return graph in JGraphT format.
|
||||||
|
*/
|
||||||
|
public static Graph<Node, DefaultEdge> graphBuilder(final Collection<NodeGraph> nodesGraph,
|
||||||
|
final Collection<EdgeGraph> edgesGraph) {
|
||||||
|
Graph<Node, DefaultEdge> graph = new SimpleGraph<>(DefaultEdge.class);
|
||||||
|
if (Objects.isNull(nodesGraph) || Objects.isNull(edgesGraph)) {
|
||||||
|
LOG.debug("graphBuilder: Return empty graph because one of the input collection is null");
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
Set<Node> nodes = nodeGraphsToNodes(nodesGraph);
|
||||||
|
Set<Edge> edges = edgesGraph.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(eg -> {
|
||||||
|
Node nodeOne = nodes.stream()
|
||||||
|
.filter(n -> n.getName().equalsIgnoreCase(eg.getNodeOne()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
Node nodeTwo = nodes.stream()
|
||||||
|
.filter(n -> n.getName().equalsIgnoreCase(eg.getNodeTwo()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (Objects.nonNull(nodeOne) && Objects.nonNull(nodeTwo)) {
|
||||||
|
return new Edge(eg.getId(), nodeOne, nodeTwo);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
} })
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
nodes.forEach(graph::addVertex);
|
||||||
|
edges.forEach(edge -> graph.addEdge(
|
||||||
|
edge.getNodeOne(), edge.getNodeTwo()
|
||||||
|
));
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert graph from {@see <a href = https://github.com/jgrapht/jgrapht/blob/master/README.md>JGraphT</a>} format
|
||||||
|
* to graph DTO {@link GraphDto} format.
|
||||||
|
* ATTENTION: GraphDto will return edges without IDs,
|
||||||
|
* because graph in JGraphT format does not store IDs for edges!
|
||||||
|
* @param graph graph in JGraphT format.
|
||||||
|
* @return {@link GraphDto}.
|
||||||
|
*/
|
||||||
|
public static GraphDto graphToGraphDto(final Graph<Node, DefaultEdge> graph) {
|
||||||
|
if (Objects.isNull(graph)) {
|
||||||
|
LOG.debug("graphToGraphDto: returned empty DTO graph because input graph is null.");
|
||||||
|
return new GraphDto();
|
||||||
|
}
|
||||||
|
return new GraphDto(getNodesDtoFromGraph(graph), getEdgesDtoFromGraph(graph));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting JGraphT nodes to the GraphDto nodes {@link NodeGraph}
|
||||||
|
* @param graph graph in the JGraphT format.
|
||||||
|
* @return collection of GraphDto nodes.
|
||||||
|
*/
|
||||||
|
private static Set<NodeGraph> getNodesDtoFromGraph(final Graph<Node, DefaultEdge> graph) {
|
||||||
|
if (Objects.isNull(graph)) {
|
||||||
|
LOG.debug("getNodesDtoFromGraph: returned empty collection, because input graph is null");
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return graph.vertexSet().stream()
|
||||||
|
.map(n -> new NodeGraph(n.getId(), n.getName(), n.getCounter()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting JGraphT edges to the GraphDto edges {@link NodeGraph}
|
||||||
|
* @param graph graph in the JGraphT format.
|
||||||
|
* @return collection of GraphDto edges without IDs.
|
||||||
|
*/
|
||||||
|
private static Set<EdgeGraph> getEdgesDtoFromGraph(final Graph<Node, DefaultEdge> graph) {
|
||||||
|
if (Objects.isNull(graph)) {
|
||||||
|
LOG.debug("getEdgesDtoFromGraph: returned empty collection, because input graph is null");
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return graph.edgeSet().stream()
|
||||||
|
.map(e -> new EdgeGraph(graph.getEdgeSource(e).getName(), graph.getEdgeTarget(e).getName()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a cycle basis of an undirected graph using a variant of Paton's
|
||||||
|
* algorithm from {@see <a href = https://github.com/jgrapht/jgrapht/blob/master/README.md>JGraphT</a>} library.
|
||||||
|
* NOTE: while removing cycles algorithm each time returns a random set of
|
||||||
|
* graph edges for the same graph.
|
||||||
|
* @param graph graph in JGraphT format.
|
||||||
|
* @return graph in JGraphT format without cycles.
|
||||||
|
*/
|
||||||
|
public static Graph<Node, DefaultEdge> removeCyclesFromGraph(
|
||||||
|
final Graph<Node, DefaultEdge> graph) {
|
||||||
|
LOG.debug("removeCyclesFromGraph: Detect cycles in graph by Paton algorithm");
|
||||||
|
if (!isGraphContainCycles(graph)) {
|
||||||
|
LOG.debug("removeCyclesFromGraph: Cycles not found!");
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
SimpleGraph<Node, DefaultEdge> result = new SimpleGraph<>(DefaultEdge.class);
|
||||||
|
Graphs.addGraph(result, graph);
|
||||||
|
while (true) {
|
||||||
|
LOG.debug("removeCyclesFromGraph: Try detect cycles");
|
||||||
|
PatonCycleBase<Node, DefaultEdge> patonCycleBase = new PatonCycleBase<>(result);
|
||||||
|
Set<GraphPath<Node, DefaultEdge>> paths = patonCycleBase.getCycleBasis().getCyclesAsGraphPaths();
|
||||||
|
Set<DefaultEdge> edgeSet = new HashSet<>();
|
||||||
|
if (paths.size() != 0) {
|
||||||
|
LOG.debug("removeCyclesFromGraph: Cycles found! Count of cycles in present graph = {}", paths.size());
|
||||||
|
for (GraphPath<Node, DefaultEdge> graphPath : paths) {
|
||||||
|
edgeSet.addAll(graphPath.getEdgeList());
|
||||||
|
}
|
||||||
|
LOG.debug("removeCyclesFromGraph: Remove edge from cycle");
|
||||||
|
if (edgeSet.iterator().hasNext()) {
|
||||||
|
DefaultEdge edge = edgeSet.iterator().next();
|
||||||
|
result.removeEdge(edge);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.debug("removeCyclesFromGraph: Cycles not found!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isGraphContainCycles(final Graph<Node, DefaultEdge> graph) {
|
||||||
|
SimpleGraph<Node, DefaultEdge> result = new SimpleGraph<>(DefaultEdge.class);
|
||||||
|
Graphs.addGraph(result, graph);
|
||||||
|
PatonCycleBase<Node, DefaultEdge> patonCycleBase = new PatonCycleBase<>(result);
|
||||||
|
Set<GraphPath<Node, DefaultEdge>> paths = patonCycleBase.getCycleBasis()
|
||||||
|
.getCyclesAsGraphPaths();
|
||||||
|
return !paths.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export graph to {@see <a href = https://www.graphviz.org/ >GraphViz.dot</a>}
|
||||||
|
* format.
|
||||||
|
* @param graphTo graph in DTO format, see {@link GraphDto}.
|
||||||
|
* @return graph in GraphViz.dot format.
|
||||||
|
*/
|
||||||
|
public static String exportToGraphViz(final GraphDto graphTo) {
|
||||||
|
if (Objects.isNull(graphTo)) return "";
|
||||||
|
Graph<Node, DefaultEdge> graph = graphBuilder(graphTo.getNodes(), graphTo.getEdges());
|
||||||
|
ComponentNameProvider<Node> vertexIdProvider = component ->
|
||||||
|
component.getName() + "_" + component.getId();
|
||||||
|
ComponentNameProvider<Node> vertexNameProvider = Node::getName;
|
||||||
|
GraphExporter<Node, DefaultEdge> exporter = new DOTExporter<>(
|
||||||
|
vertexIdProvider, vertexNameProvider, null
|
||||||
|
);
|
||||||
|
try (Writer writer = new StringWriter()) {
|
||||||
|
exporter.exportGraph(graph, writer);
|
||||||
|
LOG.debug(writer.toString());
|
||||||
|
return writer.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("Fail export graph to GraphViz format.", e);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting collection of {@link Node} into set of {@link NodeGraph}
|
||||||
|
* @param nodes node model objects collection.
|
||||||
|
* @return collection of graph node DTO or empty collection if nodes is null.
|
||||||
|
*/
|
||||||
|
public static Set<NodeGraph> nodesToNodeGraphs(final Collection<Node> nodes) {
|
||||||
|
if (Objects.isNull(nodes)) {
|
||||||
|
LOG.debug("nodesToNodeGraphs: return empty collection because input collection of nodes is null");
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return nodes.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(GraphUtil::nodeToNodeGraph)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting collection of {@link NodeGraph} to collection of {@link Node}
|
||||||
|
* @param nodeGraphs collection of graph node DTO
|
||||||
|
* @return collection of node model objects or empty collection if
|
||||||
|
* nodeGraphs is null.
|
||||||
|
*/
|
||||||
|
public static Set<Node> nodeGraphsToNodes(final Collection<NodeGraph> nodeGraphs) {
|
||||||
|
if (Objects.isNull(nodeGraphs)) {
|
||||||
|
LOG.debug("nodeGraphsToNodes: return empty collection because input collection of DTO nodes is null");
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return nodeGraphs.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(GraphUtil::nodeGraphToNode)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting {@link Node} to {@link NodeGraph}
|
||||||
|
* @param node model object.
|
||||||
|
* @return graph node DTO or null
|
||||||
|
*/
|
||||||
|
public static NodeGraph nodeToNodeGraph(final Node node) {
|
||||||
|
if (node != null) {
|
||||||
|
return new NodeGraph(
|
||||||
|
node.getId(),
|
||||||
|
node.getName(),
|
||||||
|
node.getCounter()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting {@link NodeGraph} to {@link Node}
|
||||||
|
* @param nodeGraph graph node DTO.
|
||||||
|
* @return model object or null
|
||||||
|
*/
|
||||||
|
public static Node nodeGraphToNode(final NodeGraph nodeGraph) {
|
||||||
|
if (nodeGraph != null) {
|
||||||
|
return new Node(
|
||||||
|
nodeGraph.getId(),
|
||||||
|
nodeGraph.getName(),
|
||||||
|
nodeGraph.getCounter()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting collection of {@link Edge} to collection of {@link EdgeGraph}
|
||||||
|
* @param edges model objects collection.
|
||||||
|
* @return collection of graph edge DTO or empty collection if param is null.
|
||||||
|
*/
|
||||||
|
public static Set<EdgeGraph> edgesToEdgeGraphs(final Collection<Edge> edges) {
|
||||||
|
if (Objects.isNull(edges)) {
|
||||||
|
LOG.debug("edgesToEdgeGraphs: return empty collection because input collection of edges is null");
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
return edges.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(GraphUtil::edgeToEdgeGraph)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converting {@link Edge} to {@link EdgeGraph}
|
||||||
|
* @param edge model object.
|
||||||
|
* @return graph edge DTO or null
|
||||||
|
*/
|
||||||
|
public static EdgeGraph edgeToEdgeGraph(final Edge edge) {
|
||||||
|
if (edge != null) {
|
||||||
|
return new EdgeGraph(edge.getId(), edge.getNodeOne().getName(),
|
||||||
|
edge.getNodeTwo().getName());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getting graph edges {@link Edge} from graph data transfer object {@link GraphDto}
|
||||||
|
* @param graph graph data transfer object
|
||||||
|
* @return collection of graph edges.
|
||||||
|
*/
|
||||||
|
public static Set<Edge> getEdgesFromGraphDto(final GraphDto graph) {
|
||||||
|
return graph.getEdges().stream()
|
||||||
|
.map(eg -> {
|
||||||
|
Node nodeOne = nodeGraphToNode(graph.getNodes().stream()
|
||||||
|
.filter(ng -> ng.getName().equalsIgnoreCase(eg.getNodeOne()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null));
|
||||||
|
Node nodeTwo = nodeGraphToNode(graph.getNodes().stream()
|
||||||
|
.filter(ng -> ng.getName().equalsIgnoreCase(eg.getNodeTwo()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null));
|
||||||
|
if (Objects.nonNull(nodeOne) && Objects.nonNull(nodeTwo)) {
|
||||||
|
return new Edge(eg.getId(), nodeOne, nodeTwo);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
} })
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node random failure generator.
|
||||||
|
* @param nodes node graph collection
|
||||||
|
* @return map with key as node graph name and value as fault of node graph
|
||||||
|
* state or null if node graph collection is empty or null.
|
||||||
|
*/
|
||||||
|
public static Map<String, Boolean> getRandomNodeFault(Collection<NodeGraph> nodes) {
|
||||||
|
LOG.debug("getRandomNodeFault: Generating random node fault");
|
||||||
|
Map<String, Boolean> result = new HashMap<>();
|
||||||
|
if (Objects.isNull(nodes) || nodes.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
nodes.forEach(nodeGraph -> {
|
||||||
|
boolean isFault = ThreadLocalRandom.current().nextInt(100) >= 90;
|
||||||
|
result.put(nodeGraph.getName(), isFault);
|
||||||
|
});
|
||||||
|
LOG.debug("getRandomNodeFault: result = " + result.toString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package ru.resprojects.linkchecker.util;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for work with validation.
|
||||||
|
*/
|
||||||
|
public final class ValidationUtil {
|
||||||
|
|
||||||
|
public static final int NODE_COUNTER_DEFAULT = 0;
|
||||||
|
public static final int MIN_NAME_SIZE = 1;
|
||||||
|
public static final int MAX_NAME_SIZE = 20;
|
||||||
|
public static final String VALIDATOR_NOT_NULL_MESSAGE = "Object is not be null";
|
||||||
|
public static final String VALIDATOR_NODE_NOT_BLANK_NAME_MESSAGE = "Node name is not be empty";
|
||||||
|
public static final String VALIDATOR_NODE_NAME_RANGE_MESSAGE = "Node name must be at range from "
|
||||||
|
+ MIN_NAME_SIZE + " to " + MAX_NAME_SIZE;
|
||||||
|
|
||||||
|
private ValidationUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T checkNotFound(T object, String msg, ErrorPlaceType place) {
|
||||||
|
checkNotFound(object != null, msg, place);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkNotFound(boolean found, String arg, ErrorPlaceType place) {
|
||||||
|
if (!found) {
|
||||||
|
throw new NotFoundException(arg, place);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://stackoverflow.com/a/28565320/548473
|
||||||
|
private static Throwable getRootCause(Throwable t) {
|
||||||
|
Throwable result = t;
|
||||||
|
Throwable cause;
|
||||||
|
|
||||||
|
while (null != (cause = result.getCause()) && (result != cause)) {
|
||||||
|
result = cause;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMessage(Throwable e) {
|
||||||
|
return e.getLocalizedMessage() != null ? e.getLocalizedMessage() : e.getClass().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Throwable logAndGetRootCause(Logger log, HttpServletRequest req,
|
||||||
|
Exception e, boolean logException, ErrorType errorType) {
|
||||||
|
Throwable rootCause = ValidationUtil.getRootCause(e);
|
||||||
|
if (logException) {
|
||||||
|
log.error(errorType + " at request " + req.getRequestURL(), rootCause);
|
||||||
|
} else {
|
||||||
|
log.warn("{} at request {}: {}", errorType, req.getRequestURL(), rootCause.toString());
|
||||||
|
}
|
||||||
|
return rootCause;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package ru.resprojects.linkchecker.util.exeptions;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class ApplicationException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -6458332116628903136L;
|
||||||
|
private final ErrorType type;
|
||||||
|
private final ErrorPlaceType place;
|
||||||
|
private final HttpStatus httpStatus;
|
||||||
|
private final String[] messages;
|
||||||
|
|
||||||
|
public ApplicationException(String messages, HttpStatus httpStatus) {
|
||||||
|
this(ErrorType.APP_ERROR, ErrorPlaceType.GRAPH, httpStatus, messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationException(ErrorType type, ErrorPlaceType place, HttpStatus httpStatus, String... messages) {
|
||||||
|
super(String.format("type=%s, place=%s, msg=%s", type, place, Arrays.toString(messages)));
|
||||||
|
this.type = type;
|
||||||
|
this.place = place;
|
||||||
|
this.messages = messages;
|
||||||
|
this.httpStatus = httpStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorPlaceType getPlace() {
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpStatus getHttpStatus() {
|
||||||
|
return httpStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMessages() {
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package ru.resprojects.linkchecker.util.exeptions;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class for exception handler.
|
||||||
|
*/
|
||||||
|
public class ErrorInfo {
|
||||||
|
|
||||||
|
private String url;
|
||||||
|
private ErrorType type;
|
||||||
|
private ErrorPlaceType place;
|
||||||
|
private String[] messages;
|
||||||
|
|
||||||
|
public ErrorInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param url REST request where an error has occurred
|
||||||
|
* @param type of error
|
||||||
|
* @param place where an error has occurred
|
||||||
|
* @param messages program error messages
|
||||||
|
*/
|
||||||
|
public ErrorInfo(String url, ErrorType type, ErrorPlaceType place, String... messages) {
|
||||||
|
this.url = url;
|
||||||
|
this.type = type;
|
||||||
|
this.place = place;
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(ErrorType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorPlaceType getPlace() {
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlace(ErrorPlaceType place) {
|
||||||
|
this.place = place;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMessages() {
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessages(String[] messages) {
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new StringJoiner(", ", ErrorInfo.class.getSimpleName() + "[", "]")
|
||||||
|
.add("url='" + url + "'")
|
||||||
|
.add("type=" + type)
|
||||||
|
.add("place=" + place)
|
||||||
|
.add("messages=" + Arrays.toString(messages))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ru.resprojects.linkchecker.util.exeptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places where errors are an occurred
|
||||||
|
* EDGE - errors in edges of the graph.
|
||||||
|
* NODE - error in nodes of the graph.
|
||||||
|
* GRAPH - error in graph.
|
||||||
|
* APP - error in application.
|
||||||
|
*/
|
||||||
|
public enum ErrorPlaceType {
|
||||||
|
EDGE, NODE, GRAPH, APP
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ru.resprojects.linkchecker.util.exeptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of errors what my be occurred in program
|
||||||
|
*/
|
||||||
|
public enum ErrorType {
|
||||||
|
APP_ERROR, //Types of errors that are associated with errors in the program as a whole
|
||||||
|
DATA_NOT_FOUND, //Types of errors that are associated with search and extract data
|
||||||
|
DATA_ERROR, //Types of errors that are associated with data handling
|
||||||
|
VALIDATION_ERROR, //Types of errors are associated with validating data in REST-controllers
|
||||||
|
WRONG_REQUEST //Types of errors that are associated with http requests
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package ru.resprojects.linkchecker.util.exeptions;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class NotFoundException extends ApplicationException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 7379365858788450248L;
|
||||||
|
|
||||||
|
public NotFoundException(final String message, ErrorPlaceType place) {
|
||||||
|
super(ErrorType.DATA_NOT_FOUND, place, HttpStatus.UNPROCESSABLE_ENTITY, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package ru.resprojects.linkchecker.web;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
|
||||||
|
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorInfo;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class CustomErrorController extends AbstractErrorController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CustomErrorController.class);
|
||||||
|
|
||||||
|
public CustomErrorController(ErrorAttributes errorAttributes) {
|
||||||
|
super(errorAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/error", produces = MediaType.TEXT_HTML_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
HttpStatus status = getStatus(request);
|
||||||
|
response.setStatus(status.value());
|
||||||
|
Map<String, Object> model = getModel(request);
|
||||||
|
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
|
||||||
|
LOG.debug("errorHtml: " + model);
|
||||||
|
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/error", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public ErrorInfo error(HttpServletRequest request) {
|
||||||
|
String errorRequestUrl = request.getScheme() + "://"+ request.getServerName()
|
||||||
|
+ ":" + request.getServerPort() + getModel(request).get("path").toString();
|
||||||
|
ErrorInfo errorInfo = new ErrorInfo(errorRequestUrl,
|
||||||
|
ErrorType.WRONG_REQUEST, ErrorPlaceType.APP, "Bad request");
|
||||||
|
LOG.debug("error: " + errorInfo);
|
||||||
|
return errorInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getModel(HttpServletRequest request) {
|
||||||
|
return Collections.unmodifiableMap(getErrorAttributes(request, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getErrorPath() {
|
||||||
|
return "/error";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package ru.resprojects.linkchecker.web;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class EntryPointController {
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public String index(Model model) {
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.MessageSourceResolvable;
|
||||||
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import ru.resprojects.linkchecker.util.ValidationUtil;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorInfo;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.ConstraintViolation;
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception handler for REST-controllers
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class ExceptionInfoHandler {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ExceptionInfoHandler.class);
|
||||||
|
|
||||||
|
private final MessageSource messageSource;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ExceptionInfoHandler(MessageSource messageSource) {
|
||||||
|
this.messageSource = messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = {ApplicationException.class, NotFoundException.class})
|
||||||
|
public ResponseEntity<ErrorInfo> appError(HttpServletRequest req, ApplicationException appEx) {
|
||||||
|
return ResponseEntity.status(appEx.getHttpStatus())
|
||||||
|
.body(logAndGetErrorInfo(req,appEx, false,
|
||||||
|
appEx.getType(), appEx.getPlace(), appEx.getMessages()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public ErrorInfo handleError(HttpServletRequest req, Exception e) {
|
||||||
|
return logAndGetErrorInfo(req,e, true,
|
||||||
|
ErrorType.APP_ERROR, ErrorPlaceType.APP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY)
|
||||||
|
@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class,
|
||||||
|
ConstraintViolationException.class})
|
||||||
|
public ErrorInfo validationsError(HttpServletRequest req, Exception e) {
|
||||||
|
String[] details;
|
||||||
|
if (e instanceof ConstraintViolationException) {
|
||||||
|
details = ((ConstraintViolationException) e).getConstraintViolations().stream()
|
||||||
|
.map(ConstraintViolation::getMessage)
|
||||||
|
.toArray(String[]::new);
|
||||||
|
} else {
|
||||||
|
BindingResult result = e instanceof BindException ?
|
||||||
|
((BindException) e).getBindingResult() : ((MethodArgumentNotValidException) e).getBindingResult();
|
||||||
|
details = result.getFieldErrors().stream()
|
||||||
|
.map(this::getMessage)
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
return logAndGetErrorInfo(req, e, false,
|
||||||
|
ErrorType.VALIDATION_ERROR, ErrorPlaceType.APP, details);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ErrorInfo logAndGetErrorInfo(HttpServletRequest req, Exception e,
|
||||||
|
boolean logException, ErrorType errorType, ErrorPlaceType placeType, String... msg) {
|
||||||
|
Throwable rootCause = ValidationUtil.logAndGetRootCause(LOG, req, e,
|
||||||
|
logException, errorType);
|
||||||
|
return new ErrorInfo(req.getRequestURL().toString(),errorType, placeType,
|
||||||
|
msg.length != 0 ? msg : new String[]{ValidationUtil.getMessage(rootCause)});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMessage(MessageSourceResolvable resolvable) {
|
||||||
|
return messageSource.getMessage(resolvable, LocaleContextHolder.getLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
import ru.resprojects.linkchecker.services.GraphService;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.web.rest.GraphRestController.REST_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST controller for work with edges of the data graph
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = GraphEdgeRestController.EDGE_REST_URL,
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public class GraphEdgeRestController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphEdgeRestController.class);
|
||||||
|
|
||||||
|
public static final String EDGE_REST_URL = REST_URL + "/edges";
|
||||||
|
|
||||||
|
private GraphService graphService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GraphEdgeRestController(final GraphService graphService) {
|
||||||
|
this.graphService = graphService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<EdgeGraph> create(@RequestBody @Valid EdgeGraph edge) {
|
||||||
|
LOG.info("Creating new graph edge");
|
||||||
|
EdgeGraph created = this.graphService.getEdges().create(edge);
|
||||||
|
URI uri = MvcUriComponentsBuilder.fromController(getClass())
|
||||||
|
.path(EDGE_REST_URL)
|
||||||
|
.buildAndExpand()
|
||||||
|
.toUri();
|
||||||
|
return ResponseEntity.created(uri).body(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
//How to validate data in collections https://stackoverflow.com/a/54394177
|
||||||
|
@PostMapping(value = "create/byBatch", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<Collection<EdgeGraph>> createByBatch(@RequestBody @Valid Set<EdgeGraph> edges) {
|
||||||
|
LOG.info("Creating new graph edges");
|
||||||
|
Set<EdgeGraph> created = this.graphService.getEdges().create(edges);
|
||||||
|
URI uri = MvcUriComponentsBuilder.fromController(getClass())
|
||||||
|
.path(EDGE_REST_URL)
|
||||||
|
.buildAndExpand()
|
||||||
|
.toUri();
|
||||||
|
return ResponseEntity.created(uri).body(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<Collection<EdgeGraph>> get() {
|
||||||
|
LOG.info("Getting all graph edges");
|
||||||
|
return ResponseEntity.ok(this.graphService.getEdges().getAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/byId/{id}")
|
||||||
|
public ResponseEntity<EdgeGraph> getById(@PathVariable Integer id) {
|
||||||
|
LOG.info("Getting graph edge by id = " + id);
|
||||||
|
return ResponseEntity.ok(graphService.getEdges().getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/byName/{name}")
|
||||||
|
public ResponseEntity<Collection<EdgeGraph>> getByName(@PathVariable String name) {
|
||||||
|
LOG.info("Getting graph edge by name = " + name);
|
||||||
|
return ResponseEntity.ok(graphService.getEdges().get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/byName")
|
||||||
|
@ResponseBody
|
||||||
|
public ResponseEntity<EdgeGraph> getByNames(@RequestParam("nodeOne") String nameNodeOne, @RequestParam("nodeTwo") String nameNodeTwo) {
|
||||||
|
LOG.info(String.format("Getting graph edge by node one {%s} and node two {%s} names", nameNodeOne, nameNodeTwo));
|
||||||
|
return ResponseEntity.ok(graphService.getEdges().get(nameNodeOne, nameNodeTwo));
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void delete() {
|
||||||
|
LOG.info("Removing all graph edges");
|
||||||
|
graphService.getEdges().deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/byId/{id}")
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void deleteById(@PathVariable Integer id) {
|
||||||
|
LOG.info("Removing graph edge by id = " + id);
|
||||||
|
graphService.getEdges().delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/byName/{name}")
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void deleteByName(@PathVariable String name) {
|
||||||
|
LOG.info("Removing graph edge by name = " + name);
|
||||||
|
graphService.getEdges().delete(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/byName")
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void deleteByNames(@RequestParam("nodeOne") String nodeOne, @RequestParam("nodeTwo") String nodeTwo) {
|
||||||
|
LOG.info(String.format("Removing graph edge by node one {%s} and node two {%s} names", nodeOne, nodeTwo));
|
||||||
|
graphService.getEdges().delete(nodeOne, nodeTwo);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
import ru.resprojects.linkchecker.services.GraphService;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.web.rest.GraphRestController.REST_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST controller for work with nodes of the data graph
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = GraphNodeRestController.NODES_REST_URL,
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public class GraphNodeRestController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphNodeRestController.class);
|
||||||
|
|
||||||
|
public static final String NODES_REST_URL = REST_URL + "/nodes";
|
||||||
|
|
||||||
|
private GraphService graphService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GraphNodeRestController(final GraphService graphService) {
|
||||||
|
this.graphService = graphService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<NodeGraph> create(@Valid @RequestBody NodeGraph node) {
|
||||||
|
LOG.info("Creating new graph node");
|
||||||
|
NodeGraph created = this.graphService.getNodes().create(node);
|
||||||
|
URI uri = MvcUriComponentsBuilder.fromController(getClass())
|
||||||
|
.path(NODES_REST_URL)
|
||||||
|
.buildAndExpand()
|
||||||
|
.toUri();
|
||||||
|
return ResponseEntity.created(uri).body(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/create/byBatch", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<Collection<NodeGraph>> createByBatch(@RequestBody @Valid Set<NodeGraph> nodes) {
|
||||||
|
LOG.info("Creating new graph nodes");
|
||||||
|
Set<NodeGraph> created = this.graphService.getNodes().create(nodes);
|
||||||
|
URI uri = MvcUriComponentsBuilder.fromController(getClass())
|
||||||
|
.path(NODES_REST_URL)
|
||||||
|
.buildAndExpand()
|
||||||
|
.toUri();
|
||||||
|
return ResponseEntity.created(uri).body(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<Collection<NodeGraph>> get() {
|
||||||
|
LOG.info("Getting all graph nodes");
|
||||||
|
return ResponseEntity.ok(this.graphService.getNodes().getAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/byId/{id}")
|
||||||
|
public ResponseEntity<NodeGraph> getById(@PathVariable Integer id) {
|
||||||
|
LOG.info("Getting graph node by id = " + id);
|
||||||
|
return ResponseEntity.ok(graphService.getNodes().getById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/byName/{name}")
|
||||||
|
public ResponseEntity<NodeGraph> getByName(@PathVariable String name) {
|
||||||
|
LOG.info("Getting graph node by name = " + name);
|
||||||
|
return ResponseEntity.ok(graphService.getNodes().get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/byId/{id}")
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void deleteById(@PathVariable Integer id) {
|
||||||
|
LOG.info("Removing graph node by id = " + id);
|
||||||
|
graphService.getNodes().delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/byName/{name}")
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void deleteByName(@PathVariable String name) {
|
||||||
|
LOG.info("Removing graph node by name = " + name);
|
||||||
|
graphService.getNodes().delete(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/byObj")
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void deleteByObject(@RequestBody NodeGraph obj) {
|
||||||
|
LOG.info("Removing graph node by object = " + Optional.ofNullable(obj));
|
||||||
|
graphService.getNodes().delete(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void delete() {
|
||||||
|
LOG.info("Removing all graph nodes and graph edges that are linked with these nodes");
|
||||||
|
graphService.getNodes().deleteAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.services.GraphService;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST controller for work with data graph in generally
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = GraphRestController.REST_URL, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public class GraphRestController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphRestController.class);
|
||||||
|
|
||||||
|
public static final String REST_URL = "/rest/v1/graph";
|
||||||
|
|
||||||
|
private GraphService graphService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GraphRestController(final GraphService graphService) {
|
||||||
|
this.graphService = graphService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.OPTIONS)
|
||||||
|
public ResponseEntity<?> options() {
|
||||||
|
return ResponseEntity
|
||||||
|
.ok()
|
||||||
|
.allow(HttpMethod.GET, HttpMethod.POST, HttpMethod.DELETE, HttpMethod.OPTIONS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<GraphDto> get() {
|
||||||
|
LOG.info("Getting graph");
|
||||||
|
return ResponseEntity.ok(this.graphService.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/export", produces = MediaType.TEXT_HTML_VALUE)
|
||||||
|
public ResponseEntity<String> exportToGraphViz() {
|
||||||
|
LOG.info("Export graph to GraphViz format");
|
||||||
|
return ResponseEntity.ok(this.graphService.exportToGraphViz());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/checkroute", produces = MediaType.TEXT_HTML_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<String> checkRoute(@RequestBody Set<String> nodeNames) {
|
||||||
|
LOG.info("Checking route for nodes " + nodeNames.toString());
|
||||||
|
return ResponseEntity.ok(this.graphService.checkRoute(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<GraphDto> create(@RequestBody @Valid GraphDto graph) {
|
||||||
|
LOG.info("Creating new graph");
|
||||||
|
GraphDto created = graphService.create(graph);
|
||||||
|
URI uri = MvcUriComponentsBuilder.fromController(getClass())
|
||||||
|
.path(REST_URL)
|
||||||
|
.buildAndExpand()
|
||||||
|
.toUri();
|
||||||
|
return ResponseEntity.created(uri).body(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public void delete() {
|
||||||
|
LOG.info("Removing graph");
|
||||||
|
graphService.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
109
src/main/resources/application.yml
Normal file
109
src/main/resources/application.yml
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
spring:
|
||||||
|
profiles:
|
||||||
|
active: demo
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
ru.resprojects: info
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: production
|
||||||
|
jpa:
|
||||||
|
database: postgresql
|
||||||
|
generate-ddl: true
|
||||||
|
properties:
|
||||||
|
hibernate:
|
||||||
|
jdbc:
|
||||||
|
lob:
|
||||||
|
non_contextual_creation: true
|
||||||
|
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
|
||||||
|
open-in-view: false
|
||||||
|
datasource:
|
||||||
|
url: ${LINKCHECKER_PGSQL_DB_HOST}:${LINKCHECKER_PGSQL_DB_PORT}/${LINKCHECKER_PGSQL_DB_NAME}
|
||||||
|
username: ${LINKCHECKER_PGSQL_DB_USER}
|
||||||
|
password: ${LINKCHECKER_PGSQL_DB_PASSWORD}
|
||||||
|
platform: postgresql
|
||||||
|
initialization-mode: never
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: demo, test
|
||||||
|
jpa:
|
||||||
|
database: h2
|
||||||
|
open-in-view: false
|
||||||
|
hibernate:
|
||||||
|
ddl-auto: none
|
||||||
|
datasource:
|
||||||
|
initialization-mode: always
|
||||||
|
platform: h2
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: test
|
||||||
|
datasource:
|
||||||
|
url: jdbc:h2:mem:linkchecker;DB_CLOSE_ON_EXIT=FALSE
|
||||||
|
thymeleaf:
|
||||||
|
cache: false
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: demo
|
||||||
|
datasource:
|
||||||
|
url: jdbc:h2:mem:linkchecker;DB_CLOSE_ON_EXIT=TRUE
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: debug
|
||||||
|
jpa:
|
||||||
|
show-sql: true
|
||||||
|
properties:
|
||||||
|
hibernate:
|
||||||
|
generate_statistics: true
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
ru.resprojects: debug
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: moc_test
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: demo, production, test
|
||||||
|
jpa:
|
||||||
|
properties:
|
||||||
|
hibernate:
|
||||||
|
jdbc:
|
||||||
|
batch_size: 10
|
||||||
|
order_inserts: true
|
||||||
|
order_updates: true
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
http:
|
||||||
|
converters:
|
||||||
|
preferred-json-mapper: gson
|
||||||
|
output:
|
||||||
|
ansi:
|
||||||
|
enabled: detect
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org.springframework: error
|
||||||
|
pattern:
|
||||||
|
file: "%d %p %c{1.} [%t] %m%n"
|
||||||
|
console: "%clr(%d{HH:mm:ss.SSS}){yellow} %clr(%-5p) %clr(---){faint} %clr([%t]){cyan} %clr(%logger{36}){blue} %clr(:){red} %clr(%msg){faint}%n"
|
||||||
|
file:
|
||||||
|
name: /log/linkchecker.log
|
||||||
|
max-size: 5MB
|
||||||
|
|
||||||
|
appmsg:
|
||||||
|
app-msg:
|
||||||
|
MSG_ARGUMENT_NULL: "Argument must not be null"
|
||||||
|
MSG_COLLECTION_EMPTY: "Collection must not be empty"
|
||||||
|
MSG_COLLECTION_CONTAIN_NULL: "Collection must not contain a null item"
|
||||||
|
MSG_COLLECTION_CONTAIN_ONE_ELEMENT: "Collection must have more than one element"
|
||||||
|
MSG_BY_ID_ERROR: "%s with ID = %d is not found"
|
||||||
|
edge-msg:
|
||||||
|
EDGE_MSG_GET_ERROR: "Edge for nodes [%s, %s] is not found"
|
||||||
|
EDGE_MSG_ALREADY_PRESENT_ERROR: "Edge for nodes ([%s, %s], [%s, %s]) already present in the graph"
|
||||||
|
EDGE_MSG_GET_BY_NAME_ERROR: "Edges for node %s is not found"
|
||||||
|
node-msg:
|
||||||
|
NODE_MSG_ALREADY_PRESENT_ERROR: "Node %s already present in the graph"
|
||||||
|
NODE_MSG_UPDATE_ERROR: "Error while update node with id = "
|
||||||
|
NODE_MSG_BY_NAME_ERROR: "Node with NAME = %s is not found"
|
||||||
|
NODE_MSG_BY_OBJECT_ERROR: "Node %s is not found"
|
||||||
|
NODE_MSG_NOT_REACHABLE: "Nodes %s and %s are not reachable to each other"
|
||||||
|
NODE_MSG_IS_FAULT: "Node %s is fault"
|
||||||
17
src/main/resources/data-h2.sql
Normal file
17
src/main/resources/data-h2.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
DELETE FROM edges;
|
||||||
|
DELETE FROM nodes;
|
||||||
|
|
||||||
|
ALTER SEQUENCE global_seq RESTART WITH 5000;
|
||||||
|
|
||||||
|
INSERT INTO nodes (name) VALUES
|
||||||
|
('v1'),
|
||||||
|
('v2'),
|
||||||
|
('v3'),
|
||||||
|
('v4'),
|
||||||
|
('v5');
|
||||||
|
|
||||||
|
INSERT INTO edges (nodeOne, nodeTwo) VALUES
|
||||||
|
(5000, 5001),
|
||||||
|
(5000, 5002),
|
||||||
|
(5000, 5004),
|
||||||
|
(5002, 5003);
|
||||||
17
src/main/resources/data-postgresql.sql
Normal file
17
src/main/resources/data-postgresql.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
DELETE FROM edges;
|
||||||
|
DELETE FROM nodes;
|
||||||
|
|
||||||
|
ALTER SEQUENCE global_seq RESTART WITH 5000;
|
||||||
|
|
||||||
|
INSERT INTO nodes (name) VALUES
|
||||||
|
('v1'),
|
||||||
|
('v2'),
|
||||||
|
('v3'),
|
||||||
|
('v4'),
|
||||||
|
('v5');
|
||||||
|
|
||||||
|
INSERT INTO edges (nodeOne, nodeTwo) VALUES
|
||||||
|
(5000, 5001),
|
||||||
|
(5000, 5002),
|
||||||
|
(5000, 5004),
|
||||||
|
(5002, 5003);
|
||||||
22
src/main/resources/schema-h2.sql
Normal file
22
src/main/resources/schema-h2.sql
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
DROP TABLE IF EXISTS nodes CASCADE;
|
||||||
|
DROP TABLE IF EXISTS edges;
|
||||||
|
DROP SEQUENCE IF EXISTS global_seq;
|
||||||
|
|
||||||
|
CREATE SEQUENCE global_seq MINVALUE 5000;
|
||||||
|
|
||||||
|
CREATE TABLE nodes (
|
||||||
|
id INT DEFAULT global_seq.nextval PRIMARY KEY,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
counter INT DEFAULT 0 NOT NULL
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX nodes_unique_name_idx ON nodes(name);
|
||||||
|
|
||||||
|
CREATE TABLE edges (
|
||||||
|
id INT DEFAULT global_seq.nextval PRIMARY KEY,
|
||||||
|
nodeone INT NOT NULL,
|
||||||
|
nodetwo INT NOT NULL,
|
||||||
|
FOREIGN KEY (nodeone) REFERENCES nodes(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (nodetwo) REFERENCES nodes(id) ON DELETE CASCADE,
|
||||||
|
CHECK (nodeone <> nodetwo),
|
||||||
|
CONSTRAINT unique_edge UNIQUE (nodeone, nodetwo)
|
||||||
|
);
|
||||||
22
src/main/resources/schema-postgresql.sql
Normal file
22
src/main/resources/schema-postgresql.sql
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
DROP TABLE IF EXISTS nodes CASCADE;
|
||||||
|
DROP TABLE IF EXISTS edges;
|
||||||
|
DROP SEQUENCE IF EXISTS global_seq CASCADE;
|
||||||
|
|
||||||
|
CREATE SEQUENCE global_seq START 5000;
|
||||||
|
|
||||||
|
CREATE TABLE nodes (
|
||||||
|
id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
counter INTEGER DEFAULT 0 NOT NULL
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX nodes_unique_name_idx ON nodes(name);
|
||||||
|
|
||||||
|
CREATE TABLE edges (
|
||||||
|
id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
|
||||||
|
nodeone INT NOT NULL,
|
||||||
|
nodetwo INT NOT NULL,
|
||||||
|
FOREIGN KEY (nodeone) REFERENCES nodes(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (nodetwo) REFERENCES nodes(id) ON DELETE CASCADE,
|
||||||
|
CHECK (nodeone <> nodetwo),
|
||||||
|
CONSTRAINT unique_edge UNIQUE (nodeone, nodetwo)
|
||||||
|
);
|
||||||
16
src/main/resources/static/css/main.css
Normal file
16
src/main/resources/static/css/main.css
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
.starter-template {
|
||||||
|
padding: 3rem 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-0 {
|
||||||
|
padding: 0%
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color:#0000FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color:#FF0000;
|
||||||
|
}
|
||||||
BIN
src/main/resources/static/pics/404.jpg
Normal file
BIN
src/main/resources/static/pics/404.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
src/main/resources/static/pics/logo.png
Normal file
BIN
src/main/resources/static/pics/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
34
src/main/resources/templates/error.html
Normal file
34
src/main/resources/templates/error.html
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="ru" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
|
<title>Linkchecker (тестовое задание)</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.min.css}"/>
|
||||||
|
<link rel="stylesheet" th:href="@{/css/main.css}"/>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top">
|
||||||
|
<a href="/" class="navbar-brand">
|
||||||
|
<img src="/pics/logo.png" width="52" height="52" alt="logo">
|
||||||
|
RESPROJECTS.RU
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container-fluid starter-template">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row text-center justify-content-center">
|
||||||
|
<img src="/pics/404.jpg" alt="">
|
||||||
|
</div>
|
||||||
|
<a href="/">Go Back</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript" th:src="@{/webjars/bootstrap/4.3.1/js/bootstrap.min.js}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
82
src/main/resources/templates/index.html
Normal file
82
src/main/resources/templates/index.html
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="ru" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
|
<title>Linkchecker (тестовое задание)</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" th:href="@{webjars/bootstrap/4.3.1/css/bootstrap.min.css}"/>
|
||||||
|
<link rel="stylesheet" th:href="@{/css/main.css}"/>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top">
|
||||||
|
<a href="/" class="navbar-brand">
|
||||||
|
<img src="pics/logo.png" width="52" height="52" alt="logo">
|
||||||
|
RESPROJECTS.RU
|
||||||
|
</a>
|
||||||
|
<div class="navbar-nav mr-auto">
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-success my2 my-sm-0" href="/docs/api-guide-v1.html" role="button">Linkchecker REST API Guide v1</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container-fluid p-0">
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<h1>Linkchecker (тестовое задание)</h1>
|
||||||
|
|
||||||
|
<h2>Оригинальный текст задания</h2>
|
||||||
|
|
||||||
|
<p>Разработать REST-сервис, проверяющий работоспособность любой последовательности узлов.
|
||||||
|
Каждый узел имеет уникальное имя, вероятность, с которой откажет при обращении к нему, и счетчик успешно выполненных запросов.</p>
|
||||||
|
|
||||||
|
<p>Сервис должен реализовывать два POST-метода:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li><b>setNodes</b> - устанавливает граф из узлов, описанных выше. Формат входных данных - JSON. Программа должна исключать циклические связи узлов.</li>
|
||||||
|
<li><b>checkRoute</b> - принимает набор вершин (или их идентификаторов) в формате JSON и проходит по этим вершинам, проверяя на каждом пройденном узле, не отказал ли он. Если путь существует в графе и ни один из узлов пути не отказал, следует увеличить счетчик в каждом из узлов пути. В противном случае отображать ошибку в ответе POST-метода (произвольный формат).</li>
|
||||||
|
<li>Узлы и связи должны храниться в базе данных.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>Изменённый вариант задания</h2>
|
||||||
|
|
||||||
|
<p>После введённых корректировок, итоговый вид тестового задания выглядит следующим образом:</p>
|
||||||
|
|
||||||
|
<p>Разработать REST-сервис, проверяющий работоспособность любой последовательности узлов.</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Каждый узел имеет уникальное имя и счетчик успешно выполненных запросов, так же для хранения в базе данных есть уникальный идентификатор, который присваивается автоматически при записи в БД. Был исключен элемент вероятность отказа узла. Этот параметр перестал быть нужным, так как вероятность отказа узла стала случайным фактором, возникающая автоматически, во время проверки последовательности узлов.</li>
|
||||||
|
<li>Граф в программе неориентированный, т.е. вершины графа связаны друг с другом рёбрами, не имеющими направления. В базе данных, хранение графа осуществляется в двух таблицах. В одной таблице осуществляется хранение набора узлов графа, в другой набор рёбер графа. Более подробно смотрите запись в wiki <a href="https://gitlab.com/Aleksandrov/linkchecker/wikis/%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">План работы</a></li>
|
||||||
|
<li>Программа позволяет делать следующее:
|
||||||
|
<ol>
|
||||||
|
<li>Работать с графом обобщённо:
|
||||||
|
<ol>
|
||||||
|
<li>Создавать новый граф (при этом информация о прежнем графе будет удалена с БД)</li>
|
||||||
|
<li>Извлекать информацию о графе в заданном формате</li>
|
||||||
|
<li>Удалять целиком весь граф</li>
|
||||||
|
<li>Проверять работоспособность заданной последовательности узлов (по условию задачи) выполнив соответствующий запрос.</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>Работать с узлами и ребрами по отдельности, т.е. добавлять, удалять, искать информацию по заданным параметрам. Ручное изменение какой-либо информации о узле и ребре не предусмотрена, т.е. возможно либо добавления узла или ребра в БД или удаление из БД)</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Так как по условию задания, граф должен исключить все виды циклов (т.е. граф должен быть ациклическим), то при любом запросе информации о графе целиком или же при проверки набора заданных узлов будет происходить автоматический поиск и удаление циклов из графа. Удаление циклов происходит при помощи удаления набора рёбер, создающие циклы. Поэтому в случае обнаружения циклов в графе, исходный набор рёбер будет отличаться от набора рёбер хранящихся в БД.</p>
|
||||||
|
|
||||||
|
<p>Автоматический поиск и удаление циклов не срабатывает, если происходит работа только с набором данных рёбер графа в отдельности, т.е. можно добавлять в базу рёбра, образующие циклы.</p>
|
||||||
|
|
||||||
|
<p><b>Используемый стек</b> : <b>Spring Boot</b>, <b>Spring Data</b>, <b>ORM (Hibernate)</b>, <a href="https://jgrapht.org/"><b>JGraphT</b></a> : (для работы с графом), <b>GSON</b> (используется вместо используемого по умолчанию Jackson для работы с json),
|
||||||
|
<b>Thymeleaf</b> и <b>Bootstrap</b> (используется для формирования стартовой информационной страницы), <b>Mockito</b> (идёт вместе с Spring Boot),
|
||||||
|
<b>Powermock</b> (подключается отдельной библиотекой, используется в дополнении к mockito для тестов)</p>
|
||||||
|
|
||||||
|
<p><b>Хранилище данных</b> : PostgeSQL (для production), H2 (для тестов)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript" th:src="@{webjars/bootstrap/4.3.1/js/bootstrap.min.js}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
48
src/test/java/ru/resprojects/linkchecker/TestUtils.java
Normal file
48
src/test/java/ru/resprojects/linkchecker/TestUtils.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package ru.resprojects.linkchecker;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for unit testing.
|
||||||
|
*/
|
||||||
|
public class TestUtils {
|
||||||
|
|
||||||
|
public static final GraphDto.NodeGraph nodeGraph = new GraphDto.NodeGraph(5000, "v1", 0);
|
||||||
|
public static final GraphDto.EdgeGraph edgeGraph = new GraphDto.EdgeGraph(5005, "v1", "v2");
|
||||||
|
public static final Set<GraphDto.NodeGraph> nodesGraph = Stream.of(
|
||||||
|
nodeGraph,
|
||||||
|
new GraphDto.NodeGraph(5001, "v2", 0),
|
||||||
|
new GraphDto.NodeGraph(5002, "v3", 0),
|
||||||
|
new GraphDto.NodeGraph(5003, "v4", 0),
|
||||||
|
new GraphDto.NodeGraph(5004, "v5", 0)
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
public static final Set<GraphDto.EdgeGraph> edgesGraph = Stream.of(
|
||||||
|
edgeGraph,
|
||||||
|
new GraphDto.EdgeGraph(5006, "v1", "v3"),
|
||||||
|
new GraphDto.EdgeGraph(5007, "v1", "v5"),
|
||||||
|
new GraphDto.EdgeGraph(5008, "v3", "v4")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
public static final GraphDto graph = new GraphDto(nodesGraph, edgesGraph);
|
||||||
|
|
||||||
|
private TestUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mapToJson(Object obj) {
|
||||||
|
return new Gson().toJson(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T mapFromJson(String json, Type type) {
|
||||||
|
return new Gson().fromJson(json, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T mapFromJson(String json, Class<T> clazz) {
|
||||||
|
return new Gson().fromJson(json, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package ru.resprojects.linkchecker.model;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.util.ValidationUtil;
|
||||||
|
|
||||||
|
import javax.validation.ConstraintViolation;
|
||||||
|
import javax.validation.Validation;
|
||||||
|
import javax.validation.Validator;
|
||||||
|
import javax.validation.ValidatorFactory;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = "moc_test")
|
||||||
|
public class ValidationModelTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ValidationModelTests.class);
|
||||||
|
private static ValidatorFactory validatorFactory;
|
||||||
|
private static Validator validator;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void createValidator() {
|
||||||
|
validatorFactory = Validation.buildDefaultValidatorFactory();
|
||||||
|
validator = validatorFactory.getValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void close() {
|
||||||
|
validatorFactory.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tryCreateNodeWithBlankName() {
|
||||||
|
Node node = new Node("");
|
||||||
|
Set<ConstraintViolation<Node>> violations = validator.validate(node);
|
||||||
|
Assert.assertEquals(2, violations.size());
|
||||||
|
ConstraintViolation<Node> violation = violations.stream()
|
||||||
|
.filter(v -> ValidationUtil.VALIDATOR_NODE_NOT_BLANK_NAME_MESSAGE.equals(v.getMessage()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
Assert.assertNotNull(violation);
|
||||||
|
violation = violations.stream()
|
||||||
|
.filter(v -> ValidationUtil.VALIDATOR_NODE_NAME_RANGE_MESSAGE.equals(v.getMessage()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
Assert.assertNotNull(violation);
|
||||||
|
printViolationMessage(violations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tryCreateNodeWithTooLongNodeName() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < 51; i++) {
|
||||||
|
sb.append('a');
|
||||||
|
}
|
||||||
|
Node node = new Node(sb.toString());
|
||||||
|
Set<ConstraintViolation<Node>> violations = validator.validate(node);
|
||||||
|
Assert.assertEquals(1, violations.size());
|
||||||
|
ConstraintViolation<Node> violation = violations.stream()
|
||||||
|
.filter(v -> ValidationUtil.VALIDATOR_NODE_NAME_RANGE_MESSAGE.equals(v.getMessage()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
Assert.assertNotNull(violation);
|
||||||
|
printViolationMessage(violations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printViolationMessage(Set<ConstraintViolation<Node>> violations) {
|
||||||
|
violations.forEach(v -> {
|
||||||
|
LOG.info("VIOLATION INFO");
|
||||||
|
LOG.info("--> MESSAGE: " + v.getMessage());
|
||||||
|
LOG.info("--> PROPERTY PATH: " + v.getPropertyPath().toString());
|
||||||
|
LOG.info("--> INVALID VALUE: " + v.getInvalidValue());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package ru.resprojects.linkchecker.repositories;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
public class EdgeRepositoryH2DBTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(EdgeRepositoryH2DBTests.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
EdgeRepository edgeRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
NodeRepository nodeRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void persistNewEdge() {
|
||||||
|
Node nodeOne = nodeRepository.save(new Node("v6"));
|
||||||
|
Node nodeTwo = nodeRepository.getByName("v5");
|
||||||
|
Edge edge = edgeRepository.save(new Edge(nodeOne, nodeTwo));
|
||||||
|
Assert.assertNotNull(edge);
|
||||||
|
LOG.info("New Edge: " + edge);
|
||||||
|
List<Edge> edges = edgeRepository.findAll();
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertEquals(5, edges.size());
|
||||||
|
LOG.info("EDGES count = " + edges.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void persistEdgeList() {
|
||||||
|
List<Node> nodes = nodeRepository.findAll();
|
||||||
|
Node nodeOne = nodeRepository.save(new Node("v6"));
|
||||||
|
List<Edge> edges = new ArrayList<>();
|
||||||
|
nodes.forEach(node -> edges.add(new Edge(nodeOne, node)));
|
||||||
|
edgeRepository.saveAll(edges);
|
||||||
|
List<Edge> newEdgeList = edgeRepository.findAll();
|
||||||
|
Assert.assertNotNull(newEdgeList);
|
||||||
|
Assert.assertEquals(9, newEdgeList.size());
|
||||||
|
LOG.info("Size: " + newEdgeList.size());
|
||||||
|
newEdgeList.forEach(edge -> LOG.info(edge.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllEdges() {
|
||||||
|
List<Edge> edges = edgeRepository.findAll();
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertEquals(4, edges.size());
|
||||||
|
LOG.info("LIST count = " + edges.size());
|
||||||
|
edges.forEach(edge -> LOG.info(edge.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeById() {
|
||||||
|
Edge edge = edgeRepository.findById(5005).orElse(null);
|
||||||
|
Assert.assertNotNull(edge);
|
||||||
|
Assert.assertEquals("v1", edge.getNodeOne().getName());
|
||||||
|
LOG.info("EDGE INFO WITH ID = 5005: " + edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByNodeOneAndNodeTwo() {
|
||||||
|
Node nodeOne = nodeRepository.getByName("v1");
|
||||||
|
Node nodeTwo = nodeRepository.getByName("v2");
|
||||||
|
Edge edge = edgeRepository.findEdgeByNodeOneAndNodeTwo(nodeOne, nodeTwo).orElse(null);
|
||||||
|
Assert.assertNotNull(edge);
|
||||||
|
Assert.assertEquals(new Integer(5005), edge.getId());
|
||||||
|
LOG.info("EDGE FOR NODES v1 and v2: " + edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByNodeOneOrNodeTwo() {
|
||||||
|
Node nodeOne = nodeRepository.getByName("v1");
|
||||||
|
Node nodeTwo = nodeRepository.getByName("v2");
|
||||||
|
List<Edge> edges = edgeRepository.findEdgesByNodeOneOrNodeTwo(nodeOne, null);
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertNotEquals(0, edges.size());
|
||||||
|
edges.forEach(edge -> LOG.info(edge.toString()));
|
||||||
|
LOG.info("-------------");
|
||||||
|
edges = edgeRepository.findEdgesByNodeOneOrNodeTwo(null, nodeTwo);
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertNotEquals(0, edges.size());
|
||||||
|
edges.forEach(edge -> LOG.info(edge.toString()));
|
||||||
|
LOG.info("-------------");
|
||||||
|
edges = edgeRepository.findEdgesByNodeOneOrNodeTwo(nodeOne, nodeTwo);
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertNotEquals(0, edges.size());
|
||||||
|
edges.forEach(edge -> LOG.info(edge.toString()));
|
||||||
|
LOG.info("-------------");
|
||||||
|
edges = edgeRepository.findEdgesByNodeOneOrNodeTwo(nodeTwo, nodeTwo);
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertNotEquals(0, edges.size());
|
||||||
|
edges.forEach(edge -> LOG.info(edge.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgesInBatch() {
|
||||||
|
Node node = nodeRepository.getByName("v1");
|
||||||
|
List<Edge> edges = edgeRepository.findEdgesByNodeOneOrNodeTwo(node, node);
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
edgeRepository.deleteInBatch(edges);
|
||||||
|
edges = edgeRepository.findAll();
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
edges.forEach(edge -> LOG.info(edge.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteById() {
|
||||||
|
edgeRepository.deleteById(5005);
|
||||||
|
List<Edge> edges = edgeRepository.findAll();
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertEquals(3, edges.size());
|
||||||
|
LOG.info("EDGES count = " + edges.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteAllEdges() {
|
||||||
|
edgeRepository.deleteAllInBatch();
|
||||||
|
List<Edge> edges = edgeRepository.findAll();
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertEquals(0, edges.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package ru.resprojects.linkchecker.repositories;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
public class NodeRepositoryH2DBTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(NodeRepositoryH2DBTests.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
NodeRepository nodeRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
EdgeRepository edgeRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void persistNewNode() {
|
||||||
|
Node node = new Node("v11");
|
||||||
|
Node savedNode = nodeRepository.save(node);
|
||||||
|
Assert.assertNotNull(savedNode.getId());
|
||||||
|
LOG.info(nodeRepository.getByName("v11").toString());
|
||||||
|
int count = nodeRepository.findAll().size();
|
||||||
|
Assert.assertEquals(6, count);
|
||||||
|
LOG.info("LIST count = " + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void persistNodeList() {
|
||||||
|
List<Node> nodes = new ArrayList<>();
|
||||||
|
IntStream.range(1, 60).forEach(i -> nodes.add(new Node("w" + i)));
|
||||||
|
nodeRepository.saveAll(nodes);
|
||||||
|
List<Node> savedNodes = nodeRepository.findAll();
|
||||||
|
Assert.assertNotNull(savedNodes);
|
||||||
|
Assert.assertEquals(64, savedNodes.size());
|
||||||
|
LOG.info("LIST count = " + savedNodes.size());
|
||||||
|
savedNodes.forEach(node -> LOG.info(node.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllNodes() {
|
||||||
|
List<Node> nodes = nodeRepository.findAll();
|
||||||
|
Assert.assertNotNull(nodes);
|
||||||
|
Assert.assertEquals(5, nodes.size());
|
||||||
|
LOG.info("LIST count = " + nodes.size());
|
||||||
|
nodes.forEach(node -> LOG.info(node.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeById() {
|
||||||
|
Node node = nodeRepository.findById(5000).orElse(null);
|
||||||
|
Assert.assertNotNull(node);
|
||||||
|
Assert.assertEquals("v1", node.getName());
|
||||||
|
LOG.info("NODE INFO WITH ID = 5000: " + node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeNotFoundById() {
|
||||||
|
Node node = nodeRepository.findById(5010).orElse(null);
|
||||||
|
Assert.assertNull(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByName() {
|
||||||
|
Node node = nodeRepository.getByName("v1");
|
||||||
|
Assert.assertNotNull(node);
|
||||||
|
Assert.assertEquals("v1", node.getName());
|
||||||
|
LOG.info("NODE INFO WITH ID = 5000: " + node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeNotFoundIfNameIsNull() {
|
||||||
|
Node node = nodeRepository.getByName(null);
|
||||||
|
Assert.assertNull(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeNotFoundByName() {
|
||||||
|
Node node = nodeRepository.getByName("v11");
|
||||||
|
Assert.assertNull(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteById() {
|
||||||
|
nodeRepository.deleteById(5000);
|
||||||
|
List<Node> nodes = nodeRepository.findAll();
|
||||||
|
Assert.assertNotNull(nodes);
|
||||||
|
Assert.assertEquals(4, nodes.size());
|
||||||
|
LOG.info("LIST count = " + nodes.size());
|
||||||
|
nodes.forEach(node -> LOG.info(node.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteByName() {
|
||||||
|
nodeRepository.deleteByName("v1");
|
||||||
|
List<Node> nodes = nodeRepository.findAll();
|
||||||
|
Assert.assertNotNull(nodes);
|
||||||
|
Assert.assertEquals(4, nodes.size());
|
||||||
|
LOG.info("LIST count = " + nodes.size());
|
||||||
|
nodes.forEach(node -> LOG.info(node.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cascadeDeleteAllNodesAndEdges() {
|
||||||
|
nodeRepository.deleteAllInBatch();
|
||||||
|
List<Node> nodes = nodeRepository.findAll();
|
||||||
|
Assert.assertNotNull(nodes);
|
||||||
|
Assert.assertEquals(0, nodes.size());
|
||||||
|
List<Edge> edges = edgeRepository.findAll();
|
||||||
|
Assert.assertNotNull(edges);
|
||||||
|
Assert.assertEquals(0, edges.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void existNodeByName() {
|
||||||
|
Assert.assertTrue(nodeRepository.existsByName("v1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
public class GraphEdgeServiceH2DBTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphEdgeServiceH2DBTests.class);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GraphEdgeService edgeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdge() {
|
||||||
|
EdgeGraph edgeGraph = new EdgeGraph("v1", "v4");
|
||||||
|
EdgeGraph actual = edgeService.create(edgeGraph);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(new Integer(5009), actual.getId());
|
||||||
|
Set<EdgeGraph> egList = edgeService.getAll();
|
||||||
|
Assert.assertEquals(5, egList.size());
|
||||||
|
egList.forEach(eg -> LOG.info("---- EDGE: " + eg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgeNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
edgeService.create((EdgeGraph) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgeNodeNotFoundException() {
|
||||||
|
EdgeGraph edgeGraph = new EdgeGraph("v10", "v4");
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage( String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v10"));
|
||||||
|
edgeService.create(edgeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgeAlreadyPresentException() {
|
||||||
|
EdgeGraph edgeGraph = new EdgeGraph("v1", "v2");
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_ALREADY_PRESENT_ERROR"), "v1", "v2", "v2", "v1"));
|
||||||
|
edgeService.create(edgeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgeAlreadyPresentVariantTwoException() {
|
||||||
|
EdgeGraph edgeGraph = new EdgeGraph("v2", "v1");
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_ALREADY_PRESENT_ERROR"), "v2", "v1", "v1", "v2"));
|
||||||
|
edgeService.create(edgeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdges() {
|
||||||
|
Set<EdgeGraph> edgeGraphs = Stream.of(
|
||||||
|
new EdgeGraph("v2", "v3"),
|
||||||
|
new EdgeGraph("v2", "v5"),
|
||||||
|
new EdgeGraph("v3", "v5")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
Set<EdgeGraph> actual = edgeService.create(edgeGraphs);
|
||||||
|
Assert.assertFalse(actual.isEmpty());
|
||||||
|
Assert.assertNotNull(actual.iterator().next().getId());
|
||||||
|
actual.forEach(eg -> LOG.info("---- RETURNED EDGE: " + eg));
|
||||||
|
Set<EdgeGraph> egList = edgeService.getAll();
|
||||||
|
Assert.assertEquals(7, egList.size());
|
||||||
|
egList.forEach(eg -> LOG.info("---- EDGE: " + eg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesEmptyCollectionException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_EMPTY"));
|
||||||
|
edgeService.create(new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesNodeNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v21"));
|
||||||
|
Set<EdgeGraph> edgeGraphs = Stream.of(
|
||||||
|
new EdgeGraph("v21", "v3"),
|
||||||
|
new EdgeGraph("v2", "v5"),
|
||||||
|
new EdgeGraph("v3", "v5")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
edgeService.create(edgeGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesCollectionContainNullException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_NULL"));
|
||||||
|
Set<EdgeGraph> edgeGraphs = Stream.of(
|
||||||
|
null,
|
||||||
|
new EdgeGraph("v2", "v5"),
|
||||||
|
new EdgeGraph("v3", "v5")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
edgeService.create(edgeGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesEdgeAlreadyPresentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_ALREADY_PRESENT_ERROR"), "v1", "v2", "v2", "v1"));
|
||||||
|
Set<EdgeGraph> edgeGraphs = Stream.of(
|
||||||
|
new EdgeGraph("v1", "v2"),
|
||||||
|
new EdgeGraph("v2", "v5")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
edgeService.create(edgeGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeById() {
|
||||||
|
edgeService.delete(5005);
|
||||||
|
Set<EdgeGraph> egList = edgeService.getAll();
|
||||||
|
Assert.assertEquals(3, egList.size());
|
||||||
|
egList.forEach(eg -> LOG.info("---- EDGE: " + eg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "EDGE", 5022));
|
||||||
|
edgeService.delete(5022);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeOneAndNodeTwoNames() {
|
||||||
|
edgeService.delete("v1", "v2");
|
||||||
|
Set<EdgeGraph> actual = edgeService.getAll();
|
||||||
|
actual.forEach(eg -> LOG.info("---- EDGE: " + eg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeOneAndNodeTwoNamesNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_ERROR"), "v15", "v2"));
|
||||||
|
edgeService.delete("v15", "v2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeName() {
|
||||||
|
edgeService.delete("v1");
|
||||||
|
Set<EdgeGraph> actual = edgeService.getAll();
|
||||||
|
actual.forEach(eg -> LOG.info("---- EDGE: " + eg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeNameNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_BY_NAME_ERROR"), "v15"));
|
||||||
|
edgeService.delete("v15");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteAllEdges() {
|
||||||
|
edgeService.deleteAll();
|
||||||
|
Set<EdgeGraph> actual = edgeService.getAll();
|
||||||
|
Assert.assertTrue(actual.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllEdges() {
|
||||||
|
Set<EdgeGraph> actual = edgeService.getAll();
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
assertThat(actual.stream()
|
||||||
|
.filter(eg -> eg.getId().equals(5007))
|
||||||
|
.findFirst()
|
||||||
|
.get().getNodeOne()).isEqualTo("v1");
|
||||||
|
assertThat(actual.stream()
|
||||||
|
.filter(eg -> eg.getId().equals(5007))
|
||||||
|
.findFirst()
|
||||||
|
.get().getNodeTwo()).isEqualTo("v5");
|
||||||
|
actual.forEach(eg -> LOG.info("---- EDGE: " + eg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeById() {
|
||||||
|
EdgeGraph actual = edgeService.getById(5005);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(TestUtils.edgeGraph, actual);
|
||||||
|
LOG.info(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "EDGE", 7000));
|
||||||
|
edgeService.getById(7000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesByNodeName() {
|
||||||
|
Set<EdgeGraph> actual = edgeService.get("v1");
|
||||||
|
Set<EdgeGraph> expected = TestUtils.edgesGraph.stream()
|
||||||
|
.filter(eg -> eg.getId() != 5008)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Assert.assertFalse(actual.isEmpty());
|
||||||
|
Assert.assertEquals(expected.size(), actual.size());
|
||||||
|
assertThat(actual).containsAnyOf(expected.iterator().next());
|
||||||
|
actual.forEach(eg -> LOG.info("---- EDGE: " + eg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesByNodeNameNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_BY_NAME_ERROR"), "v100"));
|
||||||
|
edgeService.get("v100");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByNodeNameOneAndNodeNameTwo() {
|
||||||
|
EdgeGraph actual = edgeService.get("v1", "v2");
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(TestUtils.edgeGraph, actual);
|
||||||
|
Integer actualId = actual.getId();
|
||||||
|
LOG.info(actual.toString());
|
||||||
|
actual = edgeService.get("v2", "v1");
|
||||||
|
Assert.assertEquals(actualId, actual.getId()); //must equal because graph is undirected
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,314 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
import ru.resprojects.linkchecker.repositories.EdgeRepository;
|
||||||
|
import ru.resprojects.linkchecker.repositories.NodeRepository;
|
||||||
|
import ru.resprojects.linkchecker.util.GraphUtil;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyIterable;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = "moc_test")
|
||||||
|
public class GraphEdgeServiceMockTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private EdgeRepository edgeRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private NodeRepository nodeRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
private GraphEdgeService edgeService;
|
||||||
|
|
||||||
|
private List<Node> nodes;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
edgeService = new GraphEdgeServiceImpl(edgeRepository, nodeRepository, properties);
|
||||||
|
nodes = Stream.of(
|
||||||
|
new Node(5000, "v1", 0),
|
||||||
|
new Node(5001, "v2", 0),
|
||||||
|
new Node(5002, "v3", 0),
|
||||||
|
new Node(5003, "v4", 0),
|
||||||
|
new Node(5004, "v5", 0)
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdge() {
|
||||||
|
Node nodeOne = nodes.get(0);
|
||||||
|
Node nodeTwo = nodes.get(1);
|
||||||
|
Edge edge = new Edge(5005, nodeOne, nodeTwo);
|
||||||
|
EdgeGraph edgeGraph = new EdgeGraph("v1", "v2");
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(nodeOne);
|
||||||
|
given(nodeRepository.getByName("v2")).willReturn(nodeTwo);
|
||||||
|
when(edgeRepository.save(any(Edge.class))).thenReturn(edge);
|
||||||
|
EdgeGraph actual = edgeService.create(edgeGraph);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(new Integer(5005), actual.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgeNodeNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v1"));
|
||||||
|
EdgeGraph edgeGraph = new EdgeGraph("v1", "v2");
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(null);
|
||||||
|
edgeService.create(edgeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgeNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
edgeService.create((EdgeGraph) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdges() {
|
||||||
|
List<Edge> edges = new ArrayList<>();
|
||||||
|
edges.add(new Edge(5005,nodes.get(0), nodes.get(1)));
|
||||||
|
edges.add(new Edge(5006,nodes.get(0), nodes.get(2)));
|
||||||
|
edges.add(new Edge(5007,nodes.get(0), nodes.get(4)));
|
||||||
|
edges.add(new Edge(5008,nodes.get(2), nodes.get(3)));
|
||||||
|
Set<EdgeGraph> edgeGraphs = edges.stream()
|
||||||
|
.map(e -> new EdgeGraph(e.getNodeOne().getName(), e.getNodeTwo().getName()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(nodes.get(0));
|
||||||
|
given(nodeRepository.getByName("v2")).willReturn(nodes.get(1));
|
||||||
|
given(nodeRepository.getByName("v3")).willReturn(nodes.get(2));
|
||||||
|
given(nodeRepository.getByName("v4")).willReturn(nodes.get(3));
|
||||||
|
given(nodeRepository.getByName("v5")).willReturn(nodes.get(4));
|
||||||
|
when(edgeRepository.saveAll(anyIterable())).thenReturn(edges);
|
||||||
|
Set<EdgeGraph> actual = edgeService.create(edgeGraphs);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesNodeNotFoundException() {
|
||||||
|
List<Edge> edges = Stream.of(
|
||||||
|
new Edge(5005,nodes.get(0), nodes.get(1)),
|
||||||
|
new Edge(5006,nodes.get(0), nodes.get(2)),
|
||||||
|
new Edge(5007,nodes.get(0), nodes.get(4)),
|
||||||
|
new Edge(5008,nodes.get(2), nodes.get(3))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
Set<EdgeGraph> edgeGraphs = edges.stream()
|
||||||
|
.map(e -> new EdgeGraph(e.getNodeOne().getName(), e.getNodeTwo().getName()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v1"));
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(null);
|
||||||
|
edgeService.create(edgeGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
edgeService.create((Set<EdgeGraph>) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesEmptyCollectionException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_EMPTY"));
|
||||||
|
edgeService.create(new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createEdgesCollectionContainNullException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_NULL"));
|
||||||
|
Set<EdgeGraph> edgeGraphs = new HashSet<>();
|
||||||
|
edgeGraphs.add(new EdgeGraph("v1", "v2"));
|
||||||
|
edgeGraphs.add(null);
|
||||||
|
edgeService.create(edgeGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeById() {
|
||||||
|
List<Edge> edges = Stream.of(
|
||||||
|
new Edge(5008, nodes.get(2), nodes.get(3))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
given(edgeRepository.existsById(new Integer(5005))).willReturn(true);
|
||||||
|
given(edgeRepository.findAll()).willReturn(edges);
|
||||||
|
edgeService.delete(5005);
|
||||||
|
Set<EdgeGraph> actual = edgeService.getAll();
|
||||||
|
Assert.assertEquals(1, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "EDGE", 5050));
|
||||||
|
when(edgeRepository.existsById(5050)).thenReturn(false);
|
||||||
|
edgeService.delete(5050);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgesByNodeName() {
|
||||||
|
List<Edge> edges = Stream.of(
|
||||||
|
new Edge(5005,nodes.get(0), nodes.get(1)),
|
||||||
|
new Edge(5006,nodes.get(0), nodes.get(2)),
|
||||||
|
new Edge(5007,nodes.get(0), nodes.get(4))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
List<Edge> edgesAfterDelete = Stream.of(
|
||||||
|
new Edge(5008, nodes.get(2), nodes.get(3))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(nodes.get(0));
|
||||||
|
given(edgeRepository.findEdgesByNodeOneOrNodeTwo(any(Node.class), any(Node.class))).willReturn(edges);
|
||||||
|
given(edgeRepository.findAll()).willReturn(edgesAfterDelete);
|
||||||
|
edgeService.delete("v1");
|
||||||
|
Set<EdgeGraph> actual = edgeService.getAll();
|
||||||
|
Assert.assertEquals(1, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgesByNodeNameNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_BY_NAME_ERROR"), "v1"));
|
||||||
|
List<Edge> emptyList = new ArrayList<>();
|
||||||
|
given(edgeRepository.findEdgesByNodeOneOrNodeTwo(any(Node.class), any(Node.class))).
|
||||||
|
willReturn(emptyList);
|
||||||
|
edgeService.delete("v1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeNameOneAndNodeNameTwo() {
|
||||||
|
Edge edge = new Edge(5005,nodes.get(0), nodes.get(1));
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(nodes.get(0));
|
||||||
|
given(nodeRepository.getByName("v2")).willReturn(nodes.get(1));
|
||||||
|
given(edgeRepository.findEdgeByNodeOneAndNodeTwo(any(Node.class), any(Node.class))).
|
||||||
|
willReturn(Optional.of(edge));
|
||||||
|
edgeService.delete("v1", "v2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeNameOneAndNodeNameTwoNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_ERROR"), "v1", "v2"));
|
||||||
|
edgeService.delete("v1", "v2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllEdges() {
|
||||||
|
List<Edge> edges = Stream.of(
|
||||||
|
new Edge(5005, nodes.get(0), nodes.get(1)),
|
||||||
|
new Edge(5006, nodes.get(0), nodes.get(2)),
|
||||||
|
new Edge(5007, nodes.get(0), nodes.get(4)),
|
||||||
|
new Edge(5008, nodes.get(2), nodes.get(3))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
given(edgeRepository.findAll()).willReturn(edges);
|
||||||
|
Set<EdgeGraph> actual = edgeService.getAll();
|
||||||
|
EdgeGraph edgeGraph = GraphUtil.edgeToEdgeGraph(edges.get(2));
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
assertThat(actual).contains(edgeGraph);
|
||||||
|
assertThat(actual.stream()
|
||||||
|
.filter(eg -> eg.getId().equals(5007))
|
||||||
|
.findFirst()
|
||||||
|
.get().getNodeOne()).isEqualTo("v1");
|
||||||
|
assertThat(actual.stream()
|
||||||
|
.filter(eg -> eg.getId().equals(5007))
|
||||||
|
.findFirst()
|
||||||
|
.get().getNodeTwo()).isEqualTo("v5");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeById() {
|
||||||
|
Node nodeOne = nodes.get(0);
|
||||||
|
Node nodeTwo = nodes.get(1);
|
||||||
|
Edge edge = new Edge(5005, nodeOne, nodeTwo);
|
||||||
|
given(edgeRepository.findById(5005)).willReturn(Optional.of(edge));
|
||||||
|
EdgeGraph actual = edgeService.getById(5005);
|
||||||
|
Assert.assertEquals("v1", actual.getNodeOne());
|
||||||
|
Assert.assertEquals("v2", actual.getNodeTwo());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "EDGE", 7000));
|
||||||
|
edgeService.getById(7000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesByNodeName() {
|
||||||
|
List<Edge> edges = Stream.of(
|
||||||
|
new Edge(5005, nodes.get(0), nodes.get(1)),
|
||||||
|
new Edge(5006, nodes.get(0), nodes.get(2)),
|
||||||
|
new Edge(5007, nodes.get(0), nodes.get(4))
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(nodes.get(0));
|
||||||
|
given(edgeRepository.findEdgesByNodeOneOrNodeTwo(nodes.get(0),nodes.get(0)))
|
||||||
|
.willReturn(edges);
|
||||||
|
Set<EdgeGraph> actual = edgeService.get("v1");
|
||||||
|
EdgeGraph edgeGraph = GraphUtil.edgeToEdgeGraph(edges.get(0));
|
||||||
|
assertThat(actual).contains(edgeGraph);
|
||||||
|
assertThat(actual.stream()
|
||||||
|
.filter(eg -> eg.getId().equals(5005))
|
||||||
|
.findFirst()
|
||||||
|
.get().getNodeOne()).isEqualTo("v1");
|
||||||
|
assertThat(actual.stream()
|
||||||
|
.filter(eg -> eg.getId().equals(5005))
|
||||||
|
.findFirst()
|
||||||
|
.get().getNodeTwo()).isEqualTo("v2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByNodeOneAndNodeTwoNames() {
|
||||||
|
Node nodeOne = nodes.get(0);
|
||||||
|
Node nodeTwo = nodes.get(1);
|
||||||
|
Edge edge = new Edge(5005, nodeOne, nodeTwo);
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(nodeOne);
|
||||||
|
given(nodeRepository.getByName("v2")).willReturn(nodeTwo);
|
||||||
|
given(edgeRepository.findEdgeByNodeOneAndNodeTwo(nodeOne, nodeTwo)).willReturn(Optional.of(edge));
|
||||||
|
EdgeGraph actual = edgeService.get("v1", "v2");
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals("v1", actual.getNodeOne());
|
||||||
|
Assert.assertEquals("v2", actual.getNodeTwo());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exceptionWhileEdgeByNodeOneAndNodeTwoNames() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_ERROR"), "v1", "v2"));
|
||||||
|
edgeService.get("v1", "v2");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
public class GraphNodeServiceH2DBTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphNodeServiceH2DBTests.class);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
GraphNodeService nodeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
AppProperties properties;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByName() {
|
||||||
|
NodeGraph nodeGraph = nodeService.get("v1");
|
||||||
|
Assert.assertNotNull(nodeGraph);
|
||||||
|
Assert.assertEquals("v1", nodeGraph.getName());
|
||||||
|
LOG.info("NODE DTO: " + nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeById() {
|
||||||
|
NodeGraph nodeGraph = nodeService.getById(5000);
|
||||||
|
Assert.assertNotNull(nodeGraph);
|
||||||
|
Assert.assertEquals("v1", nodeGraph.getName());
|
||||||
|
LOG.info("NODE DTO: " + nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByNameNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage( String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v11"));
|
||||||
|
nodeService.get("v11");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "NODE", 5050));
|
||||||
|
nodeService.getById(5050);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllNodes() {
|
||||||
|
Set<NodeGraph> actual = nodeService.getAll();
|
||||||
|
Assert.assertEquals(5, actual.size());
|
||||||
|
assertThat(actual.stream()
|
||||||
|
.filter(eg -> eg.getId().equals(5000))
|
||||||
|
.findFirst()
|
||||||
|
.get().getName()).isEqualTo("v1");
|
||||||
|
actual.forEach(ng -> LOG.info("---- NODE: " + ng));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNodeGraph() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5000, "v1", 0);
|
||||||
|
nodeService.delete(nodeGraph);
|
||||||
|
Set<NodeGraph> actual = nodeService.getAll();
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNodeGraphNotFoundException() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5020, "v1", 0);
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"), nodeGraph.toString()));
|
||||||
|
nodeService.delete(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNodeGraphAnotherNotFoundException() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5000, "v1", 1);
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"), nodeGraph.toString()));
|
||||||
|
nodeService.delete(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByName() {
|
||||||
|
nodeService.delete("v1");
|
||||||
|
Set<NodeGraph> actual = nodeService.getAll();
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNameNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage( String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v10"));
|
||||||
|
nodeService.delete("v10");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeById() {
|
||||||
|
nodeService.delete(5000);
|
||||||
|
Set<NodeGraph> actual = nodeService.getAll();
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "NODE", 5100));
|
||||||
|
nodeService.delete(5100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteAllNodes() {
|
||||||
|
nodeService.deleteAll();
|
||||||
|
Set<NodeGraph> nodeGraphs = nodeService.getAll();
|
||||||
|
Assert.assertNotNull(nodeGraphs);
|
||||||
|
Assert.assertEquals(0, nodeGraphs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNode() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph("v6");
|
||||||
|
nodeService.create(nodeGraph);
|
||||||
|
NodeGraph actual = nodeService.get("v6");
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Set<NodeGraph> nodeGraphs = nodeService.getAll();
|
||||||
|
nodeGraphs.forEach(ng -> LOG.info("---- NODE: " + ng));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodes() {
|
||||||
|
Set<NodeGraph> nodeGraphs = new HashSet<>();
|
||||||
|
IntStream.range(1, 6).forEach(i -> {
|
||||||
|
nodeGraphs.add(new NodeGraph("w" + i));
|
||||||
|
});
|
||||||
|
nodeService.create(nodeGraphs);
|
||||||
|
Set<NodeGraph> actual = nodeService.getAll();
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(10, actual.size());
|
||||||
|
Assert.assertEquals("w1", actual.stream()
|
||||||
|
.filter(ng -> "w1".equals(ng.getName()))
|
||||||
|
.findFirst().get().getName());
|
||||||
|
actual.forEach(ng -> LOG.info("---- NODE: " + ng));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodeNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
nodeService.create((NodeGraph) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeUpdate() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5000, "v1", 1);
|
||||||
|
nodeService.update(nodeGraph);
|
||||||
|
NodeGraph actual = nodeService.get("v1");
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(1, actual.getCounter(), 0);
|
||||||
|
Set<NodeGraph> nodeGraphs = nodeService.getAll();
|
||||||
|
nodeGraphs.forEach(ng -> LOG.info("---- NODE: " + ng));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeUpdateNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
nodeService.update(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
import ru.resprojects.linkchecker.repositories.NodeRepository;
|
||||||
|
import ru.resprojects.linkchecker.util.GraphUtil;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyIterable;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.BDDMockito.when;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = "moc_test")
|
||||||
|
public class GraphNodeServiceMockTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
private GraphNodeService graphNodeService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private NodeRepository nodeRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
private List<Node> nodes = Stream.of(
|
||||||
|
new Node(5001, "v2", 0),
|
||||||
|
new Node(5002, "v3", 0),
|
||||||
|
new Node(5003, "v4", 0),
|
||||||
|
new Node(5004, "v5", 0)
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
graphNodeService = new GraphNodeServiceImpl(nodeRepository, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByName() {
|
||||||
|
given(nodeRepository.getByName("v1")).willReturn(
|
||||||
|
new Node(5000, "v1", 0)
|
||||||
|
);
|
||||||
|
NodeGraph actual = graphNodeService.get("v1");
|
||||||
|
assertThat(actual.getName()).isEqualTo("v1");
|
||||||
|
assertThat(actual.getCounter()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByNameNotFoundException() throws NotFoundException {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v1"));
|
||||||
|
graphNodeService.get("v1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeById() {
|
||||||
|
given(nodeRepository.findById(5000)).willReturn(
|
||||||
|
Optional.of(new Node(5000, "v1", 0))
|
||||||
|
);
|
||||||
|
NodeGraph actual = graphNodeService.getById(5000);
|
||||||
|
assertThat(actual.getName()).isEqualTo("v1");
|
||||||
|
assertThat(actual.getCounter()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage( String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "NODE", 5000));
|
||||||
|
graphNodeService.getById(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllNodes() {
|
||||||
|
List<Node> nodes = Stream.of(
|
||||||
|
new Node(5000, "v1", 0),
|
||||||
|
new Node(5001, "v2", 0),
|
||||||
|
new Node(5002, "v3", 0),
|
||||||
|
new Node(5003, "v4", 0),
|
||||||
|
new Node(5004, "v5", 0)
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
given(nodeRepository.findAll()).willReturn(nodes);
|
||||||
|
Set<NodeGraph> actual = graphNodeService.getAll();
|
||||||
|
NodeGraph nodeGraph = GraphUtil.nodeToNodeGraph(nodes.get(4));
|
||||||
|
Assert.assertEquals(5, actual.size());
|
||||||
|
assertThat(actual).contains(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNodeGraph() {
|
||||||
|
given(nodeRepository.findById(5000)).willReturn(
|
||||||
|
Optional.of(new Node(5000, "v1", 0))
|
||||||
|
);
|
||||||
|
given(nodeRepository.findAll()).willReturn(nodes);
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5000, "v1", 0);
|
||||||
|
graphNodeService.delete(nodeGraph);
|
||||||
|
Set<NodeGraph> actual = graphNodeService.getAll();
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNodeGraphNotFoundException() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5000, "v1", 0);
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"), nodeGraph.toString()));
|
||||||
|
graphNodeService.delete(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNodeGraphWithNullIdNotFoundException() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(null, "v1", 0);
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"), nodeGraph.toString()));
|
||||||
|
graphNodeService.delete(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNodeGraphNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
graphNodeService.delete((NodeGraph) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByName() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v1"));
|
||||||
|
when(nodeRepository.existsByName("v1")).thenReturn(true).thenReturn(false);
|
||||||
|
given(nodeRepository.findAll()).willReturn(nodes);
|
||||||
|
graphNodeService.delete("v1");
|
||||||
|
Set<NodeGraph> actual = graphNodeService.getAll();
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
graphNodeService.delete("v1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNameNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "null"));
|
||||||
|
graphNodeService.delete((String) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeById() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage( String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "NODE", 5000));
|
||||||
|
when(nodeRepository.existsById(5000)).thenReturn(true).thenReturn(false);
|
||||||
|
given(nodeRepository.findAll()).willReturn(nodes);
|
||||||
|
graphNodeService.delete(5000);
|
||||||
|
Set<NodeGraph> actual = graphNodeService.getAll();
|
||||||
|
Assert.assertEquals(4, actual.size());
|
||||||
|
graphNodeService.delete(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByIdNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage( String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), "NODE", null));
|
||||||
|
graphNodeService.delete((Integer) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNode() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph("v1");
|
||||||
|
Node node = new Node("v1");
|
||||||
|
node.setId(5000);
|
||||||
|
when(nodeRepository.save(any(Node.class))).thenReturn(node);
|
||||||
|
NodeGraph actual = graphNodeService.create(nodeGraph);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertNotNull(actual.getId());
|
||||||
|
Assert.assertEquals(5000, actual.getId().intValue());
|
||||||
|
Assert.assertEquals("v1", actual.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodeIsPresentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
NodeGraph nodeGraph = new NodeGraph("v1");
|
||||||
|
thrown.expectMessage(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
nodeGraph.getName()
|
||||||
|
));
|
||||||
|
Node node = new Node("v1");
|
||||||
|
node.setId(5000);
|
||||||
|
when(nodeRepository.getByName(any(String.class))).thenReturn(node);
|
||||||
|
graphNodeService.create(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodeNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
graphNodeService.create((NodeGraph) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodes() {
|
||||||
|
Set<NodeGraph> nodeGraphs = new HashSet<>();
|
||||||
|
List<Node> nodes = new ArrayList<>();
|
||||||
|
IntStream.range(1, 6).forEach(i -> {
|
||||||
|
nodeGraphs.add(new NodeGraph("w" + i));
|
||||||
|
nodes.add(new Node(5000 + i, "w" + i, 0));
|
||||||
|
});
|
||||||
|
when(nodeRepository.saveAll(anyIterable())).thenReturn(nodes);
|
||||||
|
Set<NodeGraph> actual = graphNodeService.create(nodeGraphs);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(5, actual.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodesIsPresentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
"w1"
|
||||||
|
));
|
||||||
|
Set<NodeGraph> nodeGraphs = new HashSet<>();
|
||||||
|
nodeGraphs.add(new NodeGraph("w1"));
|
||||||
|
Node node = new Node(5000, "w1", 0);
|
||||||
|
when(nodeRepository.getByName(any(String.class))).thenReturn(node);
|
||||||
|
graphNodeService.create(nodeGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodesNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
graphNodeService.create((Set<NodeGraph>) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodesEmptyCollectionException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_EMPTY"));
|
||||||
|
graphNodeService.create(new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNodesCollectionContainNullException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_NULL"));
|
||||||
|
Set<NodeGraph> nodeGraphs = new HashSet<>();
|
||||||
|
nodeGraphs.add(new NodeGraph("v1"));
|
||||||
|
nodeGraphs.add(null);
|
||||||
|
graphNodeService.create(nodeGraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateNode() {
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5000, "v1", 2);
|
||||||
|
Node node = new Node(5000, "v1", 2);
|
||||||
|
when(nodeRepository.save(any(Node.class))).thenReturn(node);
|
||||||
|
when(nodeRepository.findById(5000)).thenReturn(Optional.of(node));
|
||||||
|
graphNodeService.update(nodeGraph);
|
||||||
|
NodeGraph actual = graphNodeService.getById(5000);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(nodeGraph, GraphUtil.nodeToNodeGraph(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateNodeNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
graphNodeService.update(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateNodeWhileUpdateException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_UPDATE_ERROR"), 5000));
|
||||||
|
NodeGraph nodeGraph = new NodeGraph(5000, "v1", 0);
|
||||||
|
when(nodeRepository.save(any(Node.class))).thenReturn(null);
|
||||||
|
graphNodeService.update(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ApplicationException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
public class GraphServiceH2DBTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphServiceH2DBTests.class);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GraphService graphService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
private Set<EdgeGraph> edgeGraphSet = Stream.of(
|
||||||
|
new EdgeGraph("v1", "v2"),
|
||||||
|
new EdgeGraph("v1", "v3"),
|
||||||
|
new EdgeGraph("v1", "v4"),
|
||||||
|
new EdgeGraph("v2", "v3"),
|
||||||
|
new EdgeGraph("v2", "v4"),
|
||||||
|
new EdgeGraph("v3", "v4")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraph() {
|
||||||
|
GraphDto graphDto = new GraphDto();
|
||||||
|
graphDto.setNodes(Stream.of(
|
||||||
|
new NodeGraph("v1"),
|
||||||
|
new NodeGraph("v2"),
|
||||||
|
new NodeGraph("v3"),
|
||||||
|
new NodeGraph("v4")
|
||||||
|
).collect(Collectors.toSet()));
|
||||||
|
graphDto.setEdges(edgeGraphSet);
|
||||||
|
GraphDto actual = graphService.create(graphDto);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
LOG.info(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraphWithExtraEdges() {
|
||||||
|
GraphDto graphDto = new GraphDto();
|
||||||
|
graphDto.setNodes(Stream.of(
|
||||||
|
new NodeGraph("v1"),
|
||||||
|
new NodeGraph("v2"),
|
||||||
|
new NodeGraph("v3")
|
||||||
|
).collect(Collectors.toSet()));
|
||||||
|
graphDto.setEdges(edgeGraphSet);
|
||||||
|
GraphDto actual = graphService.create(graphDto);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
LOG.info(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraphNullArgumentException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
graphService.create(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraphEmptyCollectionException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage("NODES: " + properties.getAppMsg().get("MSG_COLLECTION_EMPTY"));
|
||||||
|
GraphDto graphDto = new GraphDto();
|
||||||
|
graphDto.setNodes(new HashSet<>());
|
||||||
|
graphDto.setEdges(edgeGraphSet);
|
||||||
|
graphService.create(graphDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getGraphWithRemovedEdges() {
|
||||||
|
graphService.getEdges().create(Stream.of(
|
||||||
|
new EdgeGraph("v2", "v3"),
|
||||||
|
new EdgeGraph("v3", "v5"),
|
||||||
|
new EdgeGraph("v2", "v4"),
|
||||||
|
new EdgeGraph("v5", "v4")
|
||||||
|
).collect(Collectors.toSet()));
|
||||||
|
Set<EdgeGraph> edgeGraphs = graphService.getEdges().getAll();
|
||||||
|
LOG.info(edgeGraphs.toString());
|
||||||
|
GraphDto actual = graphService.get();
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertNotEquals(edgeGraphs.size(), actual.getEdges().size());
|
||||||
|
LOG.info(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getGraphWithoutRemovingEdges() {
|
||||||
|
GraphDto actual = graphService.get();
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(4, actual.getEdges().size());
|
||||||
|
LOG.info(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteGraph() {
|
||||||
|
graphService.clear();
|
||||||
|
GraphDto actual = graphService.get();
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(0, actual.getEdges().size());
|
||||||
|
Assert.assertEquals(0, actual.getNodes().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getGraphAfterAddedNewNode() {
|
||||||
|
graphService.getNodes().create(new NodeGraph("v6"));
|
||||||
|
GraphDto actual = graphService.get();
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(6, actual.getNodes().size());
|
||||||
|
Assert.assertEquals(4, actual.getEdges().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkNodesRoute() {
|
||||||
|
Set<String> nodeNames = Stream.of("v1", "v2", "v3", "v5").collect(Collectors.toSet());
|
||||||
|
int faultCount = 0;
|
||||||
|
Map<String, Integer> nodeErrorStat = new HashMap<>();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
try {
|
||||||
|
LOG.info(graphService.checkRoute(nodeNames));
|
||||||
|
} catch (ApplicationException e) {
|
||||||
|
String node = e.getMessage().split(" ")[1];
|
||||||
|
LOG.info(node);
|
||||||
|
if (!nodeErrorStat.containsKey(node)) {
|
||||||
|
nodeErrorStat.put(node, 1);
|
||||||
|
} else {
|
||||||
|
Integer val = nodeErrorStat.get(node);
|
||||||
|
nodeErrorStat.put(node, ++val);
|
||||||
|
}
|
||||||
|
faultCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.info(graphService.get().toString());
|
||||||
|
LOG.info("FAULT COUNT for CHECK ROUTE = " + faultCount);
|
||||||
|
nodeErrorStat.forEach((key, value) -> LOG.info("NODE " + key + " error count = " + value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNullCollectionException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_ARGUMENT_NULL"));
|
||||||
|
graphService.checkRoute(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteEmptyCollectionException() {
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_EMPTY"));
|
||||||
|
graphService.checkRoute(new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteCollectionHaveOneElementException() {
|
||||||
|
Set<String> nodeNames = Stream.of("v10").collect(Collectors.toSet());
|
||||||
|
thrown.expect(ApplicationException.class);
|
||||||
|
thrown.expectMessage(properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_ONE_ELEMENT"));
|
||||||
|
graphService.checkRoute(nodeNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package ru.resprojects.linkchecker.services;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||||
|
import org.powermock.modules.junit4.PowerMockRunner;
|
||||||
|
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.util.GraphUtil;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyCollection;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.BDDMockito.when;
|
||||||
|
import static org.powermock.api.mockito.PowerMockito.spy;
|
||||||
|
|
||||||
|
//How to use PowerMock https://www.baeldung.com/intro-to-powermock
|
||||||
|
//How to use PowerMock and SpringRunner https://stackoverflow.com/a/57780838
|
||||||
|
@RunWith(PowerMockRunner.class)
|
||||||
|
@PowerMockRunnerDelegate(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = "moc_test")
|
||||||
|
@PrepareForTest(GraphUtil.class)
|
||||||
|
@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*",
|
||||||
|
"javax.xml.transform.*", "org.xml.*", "javax.management.*",
|
||||||
|
"javax.net.ssl.*", "com.sun.org.apache.xalan.internal.xsltc.trax.*"})
|
||||||
|
public class GraphServiceMockTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
private GraphService graphService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private GraphEdgeService edgeService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private GraphNodeService nodeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
graphService = new GraphServiceImpl(edgeService, nodeService, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNodeFaultException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_IS_FAULT"), "v1"));
|
||||||
|
spy(GraphUtil.class);
|
||||||
|
Map<String, Boolean> nodesFault = new HashMap<>();
|
||||||
|
nodesFault.put("v1", true);
|
||||||
|
nodesFault.put("v2", false);
|
||||||
|
nodesFault.put("v3", false);
|
||||||
|
given(nodeService.getAll()).willReturn(TestUtils.nodesGraph);
|
||||||
|
given(edgeService.getAll()).willReturn(TestUtils.edgesGraph);
|
||||||
|
when(GraphUtil.getRandomNodeFault(anyCollection())).thenReturn(nodesFault);
|
||||||
|
graphService.checkRoute(Stream.of("v1", "v2", "v3").collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNodeNotReachableException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_NOT_REACHABLE"), "v1", "v4"));
|
||||||
|
spy(GraphUtil.class);
|
||||||
|
Map<String, Boolean> nodesFault = new HashMap<>();
|
||||||
|
nodesFault.put("v1", false);
|
||||||
|
nodesFault.put("v2", false);
|
||||||
|
nodesFault.put("v3", false);
|
||||||
|
nodesFault.put("v4", false);
|
||||||
|
given(nodeService.getAll()).willReturn(TestUtils.nodesGraph);
|
||||||
|
given(edgeService.getAll()).willReturn(TestUtils.edgesGraph);
|
||||||
|
when(GraphUtil.getRandomNodeFault(anyCollection())).thenReturn(nodesFault);
|
||||||
|
graphService.checkRoute(Stream.of("v1", "v2", "v4").collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNodeNotFoundException() {
|
||||||
|
thrown.expect(NotFoundException.class);
|
||||||
|
thrown.expectMessage(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v7"));
|
||||||
|
spy(GraphUtil.class);
|
||||||
|
Map<String, Boolean> nodesFault = new HashMap<>();
|
||||||
|
nodesFault.put("v1", false);
|
||||||
|
nodesFault.put("v2", false);
|
||||||
|
nodesFault.put("v3", false);
|
||||||
|
given(nodeService.getAll()).willReturn(TestUtils.nodesGraph);
|
||||||
|
given(edgeService.getAll()).willReturn(TestUtils.edgesGraph);
|
||||||
|
when(GraphUtil.getRandomNodeFault(anyCollection())).thenReturn(nodesFault);
|
||||||
|
graphService.checkRoute(Stream.of("v1", "v2", "v3", "v7").collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
package ru.resprojects.linkchecker.util;
|
||||||
|
|
||||||
|
import org.jgrapht.Graph;
|
||||||
|
import org.jgrapht.graph.DefaultEdge;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.model.Edge;
|
||||||
|
import ru.resprojects.linkchecker.model.Node;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.util.GraphUtil.*;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = "moc_test")
|
||||||
|
public class GraphUtilTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphUtilTests.class);
|
||||||
|
|
||||||
|
private GraphDto graphDto;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
Set<NodeGraph> nodeGraphSet = Stream.of(
|
||||||
|
new NodeGraph(5000, "v1", 0),
|
||||||
|
new NodeGraph(5001, "v2", 0),
|
||||||
|
new NodeGraph(5002, "v3", 0),
|
||||||
|
new NodeGraph(5003, "v4", 0),
|
||||||
|
new NodeGraph(5004, "v5", 0)
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
Set<EdgeGraph> edgeGraphSet = Stream.of(
|
||||||
|
new EdgeGraph(5005, "v1", "v2"),
|
||||||
|
new EdgeGraph(5006, "v1", "v3"),
|
||||||
|
new EdgeGraph(5007, "v1", "v5"),
|
||||||
|
new EdgeGraph(5008, "v3", "v4")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
graphDto = new GraphDto(nodeGraphSet, edgeGraphSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateRandomNodeFaultTest() {
|
||||||
|
Set<NodeGraph> nodeGraphSet = new HashSet<>();
|
||||||
|
IntStream.range(0, 23).forEach(v -> nodeGraphSet.add(new NodeGraph(5000 + v, "v" + v, 0)));
|
||||||
|
Map<String, Boolean> result = getRandomNodeFault(nodeGraphSet);
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
result.forEach((key, value) -> LOG.debug("Node: " + key + " is fault = " + value));
|
||||||
|
long countOfFault = result.entrySet().stream().filter(Map.Entry::getValue).count();
|
||||||
|
LOG.debug("Count of fault elements = " + countOfFault);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void returnEmptyMapFromGenerateRandomNodeFault() {
|
||||||
|
Map<String, Boolean> result = getRandomNodeFault(null);
|
||||||
|
Assert.assertTrue(result.isEmpty());
|
||||||
|
result = getRandomNodeFault(new HashSet<>());
|
||||||
|
Assert.assertTrue(result.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesFromGraphDtoTest() {
|
||||||
|
Set<Edge> actual = getEdgesFromGraphDto(graphDto);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
assertThat(actual).isNotEmpty();
|
||||||
|
Assert.assertEquals(graphDto.getEdges().size(), actual.size());
|
||||||
|
Assert.assertTrue(actual.stream()
|
||||||
|
.anyMatch(edge -> edge.getId().equals(
|
||||||
|
graphDto.getEdges().iterator().next().getId())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
actual.forEach(edge -> LOG.debug(edge.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesFromGraphDtoSkipEdgeGraph() {
|
||||||
|
EdgeGraph eg = new EdgeGraph(5009, "v3", "v7");
|
||||||
|
graphDto.getEdges().add(eg);
|
||||||
|
Set<Edge> actual = getEdgesFromGraphDto(graphDto);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertTrue(actual.stream().noneMatch(
|
||||||
|
edge -> edge.getId().equals(eg.getId()))
|
||||||
|
);
|
||||||
|
LOG.debug("EdgeGraph collection:");
|
||||||
|
graphDto.getEdges().forEach(edgeGraph -> LOG.debug(edgeGraph.toString()));
|
||||||
|
LOG.debug("Edge collection:");
|
||||||
|
actual.forEach(edge -> LOG.debug(edge.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void edgeToEdgeGraphTest() {
|
||||||
|
Edge edge = new Edge(3, new Node(1, "v1", 0),
|
||||||
|
new Node(2, "v2", 0));
|
||||||
|
EdgeGraph actual = edgeToEdgeGraph(edge);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(edge.getId(), actual.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void edgeToEdgeGraphReturnNull() {
|
||||||
|
Assert.assertNull(edgeToEdgeGraph(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void edgesToEdgeGraphsTest() {
|
||||||
|
Set<Edge> edges = Stream.of(
|
||||||
|
new Edge(3, new Node(1, "v1", 0),
|
||||||
|
new Node(2, "v2", 0)),
|
||||||
|
new Edge(6, new Node(4, "v1", 0),
|
||||||
|
new Node(5, "v3", 0))
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
Set<EdgeGraph> actual = edgesToEdgeGraphs(edges);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
assertThat(actual).isNotEmpty();
|
||||||
|
Assert.assertEquals(edges.size(), actual.size());
|
||||||
|
for (EdgeGraph edgeGraph : actual) {
|
||||||
|
Assert.assertTrue(edges.stream()
|
||||||
|
.anyMatch(e -> e.getId().equals(edgeGraph.getId())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void edgesToEdgeGraphsReturnEmptyCollection() {
|
||||||
|
assertThat(edgesToEdgeGraphs(null)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeGraphToNodeTest() {
|
||||||
|
NodeGraph nodeGraph = graphDto.getNodes().iterator().next();
|
||||||
|
Node node = nodeGraphToNode(nodeGraph);
|
||||||
|
Assert.assertNotNull(node);
|
||||||
|
Assert.assertEquals(nodeGraph.getId(), node.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeGraphToNodeReturnNull() {
|
||||||
|
Assert.assertNull(nodeGraphToNode(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeToNodeGraphTest() {
|
||||||
|
Node node = new Node(1, "v1", 0);
|
||||||
|
NodeGraph actual = nodeToNodeGraph(node);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(node.getId(), node.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeToNodeGraphReturnNull() {
|
||||||
|
Assert.assertNull(nodeToNodeGraph(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeGraphsToNodesTest() {
|
||||||
|
Set<Node> actual = nodeGraphsToNodes(graphDto.getNodes());
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
assertThat(actual).isNotEmpty();
|
||||||
|
Assert.assertEquals(graphDto.getNodes().size(), actual.size());
|
||||||
|
for (Node node : actual) {
|
||||||
|
Assert.assertTrue(graphDto.getNodes().stream()
|
||||||
|
.anyMatch(n -> n.getId().equals(node.getId())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodeGraphsToNodesReturnEmptyCollection() {
|
||||||
|
assertThat(nodeGraphsToNodes(null)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodesToNodeGraphsTest() {
|
||||||
|
Set<Node> nodes = Stream.of(
|
||||||
|
new Node(1, "v1", 0),
|
||||||
|
new Node(2, "v2", 0)
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
Set<NodeGraph> actual = nodesToNodeGraphs(nodes);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
assertThat(actual).isNotEmpty();
|
||||||
|
for (NodeGraph nodeGraph : actual) {
|
||||||
|
Assert.assertTrue(nodes.stream()
|
||||||
|
.anyMatch(n -> n.getId().equals(nodeGraph.getId())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nodesToNodeGraphsReturnEmptyCollection() {
|
||||||
|
assertThat(nodesToNodeGraphs(null)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exportToGraphVizTest() {
|
||||||
|
String actual = exportToGraphViz(graphDto);
|
||||||
|
assertThat(actual).isNotEmpty();
|
||||||
|
assertThat(actual).contains("strict graph");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exportToGraphVizReturnNull() {
|
||||||
|
assertThat(exportToGraphViz(null)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void graphBuilderTest() {
|
||||||
|
Graph<Node, DefaultEdge> actual = graphBuilder(graphDto.getNodes(),
|
||||||
|
graphDto.getEdges());
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertEquals(actual.vertexSet().size(), graphDto.getNodes().size());
|
||||||
|
Assert.assertEquals(actual.edgeSet().size(), graphDto.getEdges().size());
|
||||||
|
LOG.debug(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void graphBuilderSkipNullElementFromNodesAndEdges() {
|
||||||
|
graphDto.getNodes().add(null);
|
||||||
|
graphDto.getEdges().add(null);
|
||||||
|
Graph<Node, DefaultEdge> actual = graphBuilder(graphDto.getNodes(),
|
||||||
|
graphDto.getEdges());
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertNotEquals(actual.vertexSet().size(), graphDto.getNodes().size());
|
||||||
|
Assert.assertNotEquals(actual.edgeSet().size(), graphDto.getEdges().size());
|
||||||
|
LOG.debug(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void graphBuilderSkipEdgeWithNonExistsNodes() {
|
||||||
|
graphDto.getEdges().add(new EdgeGraph(5009, "v10", "v12"));
|
||||||
|
Graph<Node, DefaultEdge> actual = graphBuilder(graphDto.getNodes(),
|
||||||
|
graphDto.getEdges());
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
Assert.assertNotEquals(actual.edgeSet().size(), graphDto.getEdges().size());
|
||||||
|
LOG.debug(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void graphBuilderReturnEmptyGraph() {
|
||||||
|
Graph<Node, DefaultEdge> actual = graphBuilder(null,
|
||||||
|
graphDto.getEdges());
|
||||||
|
assertThat(actual.vertexSet()).isEmpty();
|
||||||
|
assertThat(actual.edgeSet()).isEmpty();
|
||||||
|
LOG.debug(actual.toString());
|
||||||
|
actual = graphBuilder(graphDto.getNodes(), null);
|
||||||
|
assertThat(actual.vertexSet()).isEmpty();
|
||||||
|
assertThat(actual.edgeSet()).isEmpty();
|
||||||
|
LOG.debug(actual.toString());
|
||||||
|
actual = graphBuilder(null, null);
|
||||||
|
assertThat(actual.vertexSet()).isEmpty();
|
||||||
|
assertThat(actual.edgeSet()).isEmpty();
|
||||||
|
LOG.debug(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void graphToGraphDtoTest() {
|
||||||
|
GraphDto actual = graphToGraphDto(graphBuilder(graphDto.getNodes(),
|
||||||
|
graphDto.getEdges()));
|
||||||
|
assertThat(actual.getNodes()).isNotEmpty();
|
||||||
|
assertThat(actual.getEdges()).isNotEmpty();
|
||||||
|
Assert.assertEquals(graphDto.getNodes().size(), actual.getNodes().size());
|
||||||
|
Assert.assertEquals(graphDto.getEdges().size(), actual.getEdges().size());
|
||||||
|
for (NodeGraph nodeGraph : actual.getNodes()) {
|
||||||
|
Assert.assertTrue(graphDto.getNodes().stream()
|
||||||
|
.anyMatch(ng -> ng.equals(nodeGraph)));
|
||||||
|
}
|
||||||
|
// Because method graphToGraphDto is return edges without IDs ,
|
||||||
|
// IDs is not checked.
|
||||||
|
for (EdgeGraph edgeGraph : actual.getEdges()) {
|
||||||
|
Assert.assertTrue(graphDto.getEdges().stream()
|
||||||
|
.anyMatch(eg -> eg.getNodeOne().equals(edgeGraph.getNodeOne())
|
||||||
|
&& eg.getNodeTwo().equals(edgeGraph.getNodeTwo()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LOG.debug(actual.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void graphToGraphDtoReturnEmptyGraphDto() {
|
||||||
|
GraphDto actual = graphToGraphDto(null);
|
||||||
|
assertThat(actual.getNodes()).isEmpty();
|
||||||
|
assertThat(actual.getEdges()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeCyclesFromGraphTest() {
|
||||||
|
GraphDto cyclesGraph = new GraphDto();
|
||||||
|
cyclesGraph.getNodes().addAll(graphDto.getNodes());
|
||||||
|
cyclesGraph.getEdges().addAll(graphDto.getEdges());
|
||||||
|
cyclesGraph.getEdges().add(new EdgeGraph(5009, "v2", "v4"));
|
||||||
|
cyclesGraph.getEdges().add(new EdgeGraph(5010, "v2", "v3"));
|
||||||
|
cyclesGraph.getEdges().add(new EdgeGraph(5011, "v3", "v5"));
|
||||||
|
cyclesGraph.getEdges().add(new EdgeGraph(5012, "v3", "v4"));
|
||||||
|
cyclesGraph.getEdges().add(new EdgeGraph(5013, "v5", "v4"));
|
||||||
|
GraphDto actual = graphToGraphDto(removeCyclesFromGraph(graphBuilder(
|
||||||
|
cyclesGraph.getNodes(), cyclesGraph.getEdges())));
|
||||||
|
Assert.assertEquals(graphDto.getNodes().size(), actual.getNodes().size());
|
||||||
|
Assert.assertEquals(graphDto.getEdges().size(), actual.getEdges().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeCyclesFromGraphCyclesNotFound() {
|
||||||
|
GraphDto actual = graphToGraphDto(removeCyclesFromGraph(graphBuilder(
|
||||||
|
graphDto.getNodes(), graphDto.getEdges())));
|
||||||
|
for (NodeGraph nodeGraph : actual.getNodes()) {
|
||||||
|
Assert.assertTrue(graphDto.getNodes().stream()
|
||||||
|
.anyMatch(ng -> ng.equals(nodeGraph)));
|
||||||
|
}
|
||||||
|
// Because method graphToGraphDto is return edges without IDs ,
|
||||||
|
// IDs is not checked.
|
||||||
|
for (EdgeGraph edgeGraph : actual.getEdges()) {
|
||||||
|
Assert.assertTrue(graphDto.getEdges().stream()
|
||||||
|
.anyMatch(eg -> eg.getNodeOne().equals(edgeGraph.getNodeOne())
|
||||||
|
&& eg.getNodeTwo().equals(edgeGraph.getNodeTwo()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,310 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorInfo;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
public class GraphEdgeRestControllerTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphRestControllerTests.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdge() throws Exception {
|
||||||
|
EdgeGraph newEdge = new EdgeGraph("v1", "v4");
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newEdge))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus());
|
||||||
|
EdgeGraph returnedEdge = TestUtils.mapFromJson(result.getResponse().getContentAsString(), EdgeGraph.class);
|
||||||
|
Assert.assertNotNull(returnedEdge);
|
||||||
|
Assert.assertEquals(newEdge.getNodeOne(), returnedEdge.getNodeOne());
|
||||||
|
Assert.assertEquals(newEdge.getNodeTwo(), returnedEdge.getNodeTwo());
|
||||||
|
Assert.assertNotNull(returnedEdge.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgeValidationException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(new EdgeGraph()))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.VALIDATION_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.APP, error.getPlace());
|
||||||
|
LOG.info(Arrays.asList(error.getMessages()).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgeAlreadyPresentException() throws Exception {
|
||||||
|
EdgeGraph newEdge = new EdgeGraph("v1", "v2");
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newEdge))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getEdgeMsg().get("EDGE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
newEdge.getNodeOne(), newEdge.getNodeTwo(),
|
||||||
|
newEdge.getNodeTwo(), newEdge.getNodeOne())));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdges() throws Exception {
|
||||||
|
Set<EdgeGraph> newEdges = Stream.of(
|
||||||
|
new EdgeGraph("v1", "v4"),
|
||||||
|
new EdgeGraph("v2", "v4")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newEdges))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus());
|
||||||
|
Type listType = new TypeToken<HashSet<EdgeGraph>>() {}.getType();
|
||||||
|
Set<EdgeGraph> returnedEdges = TestUtils.mapFromJson(result.getResponse().getContentAsString(), listType);
|
||||||
|
Assert.assertEquals(newEdges.size(), returnedEdges.size());
|
||||||
|
Assert.assertTrue(returnedEdges.stream().anyMatch(ng -> ng.getNodeOne().equals("v1") && ng.getNodeTwo().equals("v4")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgesEmptyCollectionException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(Collections.emptySet()))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(properties.getAppMsg().get("MSG_COLLECTION_EMPTY")));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgesCollectionContainNullObjectException() throws Exception {
|
||||||
|
Set<EdgeGraph> newEdges = Stream.of(
|
||||||
|
null,
|
||||||
|
new EdgeGraph("v1", "v4"),
|
||||||
|
new EdgeGraph("v2", "v4")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newEdges))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_NULL")));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgesCollectionContainAlreadyPresentNodeException() throws Exception {
|
||||||
|
EdgeGraph newEdge = new EdgeGraph("v1", "v2");
|
||||||
|
Set<EdgeGraph> newEdges = Stream.of(
|
||||||
|
newEdge,
|
||||||
|
new EdgeGraph("v1", "v4"),
|
||||||
|
new EdgeGraph("v2", "v4")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newEdges))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getEdgeMsg().get("EDGE_MSG_ALREADY_PRESENT_ERROR"),
|
||||||
|
newEdge.getNodeOne(), newEdge.getNodeTwo(),
|
||||||
|
newEdge.getNodeTwo(), newEdge.getNodeOne())));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdges() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(TestUtils.edgesGraph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeById() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byId/5005").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(TestUtils.edgeGraph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesByNodeName() throws Exception {
|
||||||
|
Set<EdgeGraph> expected = TestUtils.edgesGraph.stream()
|
||||||
|
.filter(eg -> eg.getId() != 5008)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byName/v1").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByNodeNames() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byName?nodeOne=v1&nodeTwo=v2").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(TestUtils.edgeGraph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByIdNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byId/5050")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), ErrorPlaceType.EDGE, 5050)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesByNameNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byName/v100")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_BY_NAME_ERROR"), "v100")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteAllEdges() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(Collections.EMPTY_SET)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeById() throws Exception {
|
||||||
|
Set<EdgeGraph> expected = TestUtils.edgesGraph.stream()
|
||||||
|
.filter(eg -> eg.getId() != 5005)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byId/5005").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByIdNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byId/5050")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), ErrorPlaceType.EDGE, 5050)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgesByNodeName() throws Exception {
|
||||||
|
Set<EdgeGraph> expected = TestUtils.edgesGraph.stream()
|
||||||
|
.filter(eg -> eg.getId() != 5008)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName/v4").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgesByNodeNameNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName/v50")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_BY_NAME_ERROR"), "v50")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeNames() throws Exception {
|
||||||
|
Set<EdgeGraph> expected = TestUtils.edgesGraph.stream()
|
||||||
|
.filter(eg -> eg.getId() != 5005)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName?nodeOne=v1&nodeTwo=v2").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeNamesNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName?nodeOne=v50&nodeTwo=v2")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.EDGE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getEdgeMsg().get("EDGE_MSG_GET_ERROR"), "v50", "v2")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorInfo;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
public class GraphNodeRestControllerTests {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GraphNodeRestControllerTests.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodes() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(TestUtils.nodesGraph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeById() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL + "/byId/5000").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(TestUtils.nodeGraph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByName() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL + "/byName/v1").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(TestUtils.nodeGraph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByNameNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL + "/byName/v10")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v10")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByIdNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL + "/byId/5050")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getAppMsg().get("MSG_BY_ID_ERROR"), ErrorPlaceType.NODE, 5050)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodeToGraph() throws Exception {
|
||||||
|
NodeGraph newNode = new NodeGraph("v6");
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus());
|
||||||
|
NodeGraph returnedNode = TestUtils.mapFromJson(result.getResponse().getContentAsString(), NodeGraph.class);
|
||||||
|
Assert.assertNotNull(returnedNode);
|
||||||
|
Assert.assertEquals(newNode.getName(), returnedNode.getName());
|
||||||
|
Assert.assertNotNull(returnedNode.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesToGraph() throws Exception {
|
||||||
|
Set<NodeGraph> newNodes = Stream.of(
|
||||||
|
new NodeGraph("v6"),
|
||||||
|
new NodeGraph("v7"),
|
||||||
|
new NodeGraph("v8")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNodes))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus());
|
||||||
|
Type listType = new TypeToken<HashSet<NodeGraph>>() {}.getType();
|
||||||
|
Set<NodeGraph> returnedNodes = TestUtils.mapFromJson(result.getResponse().getContentAsString(), listType);
|
||||||
|
Assert.assertEquals(newNodes.size(), returnedNodes.size());
|
||||||
|
Assert.assertTrue(returnedNodes.stream().anyMatch(ng -> ng.getName().equals("v6")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodeValidationException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(new NodeGraph()))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.VALIDATION_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.APP, error.getPlace());
|
||||||
|
LOG.info(Arrays.asList(error.getMessages()).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodeAlreadyPresentException() throws Exception {
|
||||||
|
NodeGraph newNode = new NodeGraph("v1");
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getNodeMsg().get("NODE_MSG_ALREADY_PRESENT_ERROR"), newNode.getName())));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesEmptyCollectionException() throws Exception {
|
||||||
|
Set<NodeGraph> newNodes = Collections.emptySet();
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNodes))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(properties.getAppMsg().get("MSG_COLLECTION_EMPTY")));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesCollectionContainNullObjectException() throws Exception {
|
||||||
|
Set<NodeGraph> newNodes = Stream.of(
|
||||||
|
null,
|
||||||
|
new NodeGraph("v7"),
|
||||||
|
new NodeGraph("v8")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNodes))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_NULL")));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesCollectionContainAlreadyPresentNodeException() throws Exception {
|
||||||
|
Set<NodeGraph> newNodes = Stream.of(
|
||||||
|
new NodeGraph("v1"),
|
||||||
|
new NodeGraph("v7"),
|
||||||
|
new NodeGraph("v8")
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNodes))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_ALREADY_PRESENT_ERROR"),"v1")));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteAllNodes() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(Collections.EMPTY_SET)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeById() throws Exception {
|
||||||
|
Set<NodeGraph> nodes = TestUtils.nodesGraph.stream().filter(ng -> ng.getId() != 5000).collect(Collectors.toSet());
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byId/5000").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(nodes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByName() throws Exception {
|
||||||
|
Set<NodeGraph> nodes = TestUtils.nodesGraph.stream().filter(ng -> !ng.getName().equals("v1")).collect(Collectors.toSet());
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byName/v1").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(nodes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObject() throws Exception {
|
||||||
|
Set<NodeGraph> nodes = TestUtils.nodesGraph.stream().filter(ng -> !ng.getName().equals("v1")).collect(Collectors.toSet());
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj").contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(TestUtils.nodeGraph)))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(nodes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByIdNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byId/5050")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(
|
||||||
|
properties.getAppMsg().get("MSG_BY_ID_ERROR"), ErrorPlaceType.NODE, 5050)));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNameNotFoundException() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byName/v10")
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v10")));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObjectWithNullIdNotFoundException() throws Exception {
|
||||||
|
NodeGraph newNode = new NodeGraph(null, "v10", 0);
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"), newNode.toString())));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObjectNotFoundException() throws Exception {
|
||||||
|
NodeGraph newNode = new NodeGraph(5020, "v10", 0);
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"), newNode.toString())));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObjectWithIncorrectIdException() throws Exception {
|
||||||
|
NodeGraph newNode = new NodeGraph(5000, "v10", 0);
|
||||||
|
MvcResult result = this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.NODE, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(
|
||||||
|
properties.getNodeMsg().get("NODE_MSG_BY_OBJECT_ERROR"), newNode.toString())));
|
||||||
|
LOG.info(errMsgs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.services.GraphService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anySet;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@WebMvcTest(GraphRestController.class)
|
||||||
|
public class GraphRestControllerMockTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private GraphService graphService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteInGraph() throws Exception {
|
||||||
|
List<String> route = Stream.of("v1", "v2", "v3").collect(Collectors.toList());
|
||||||
|
String returnedResult = String.format("Route for nodes %s is found", route.toString());
|
||||||
|
given(this.graphService.checkRoute(anySet())).willReturn(returnedResult);
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus());
|
||||||
|
Assert.assertEquals(result.getResponse().getContentAsString(), returnedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import ru.resprojects.linkchecker.AppProperties;
|
||||||
|
import ru.resprojects.linkchecker.LinkcheckerApplication;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorInfo;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorPlaceType;
|
||||||
|
import ru.resprojects.linkchecker.util.exeptions.ErrorType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.NodeGraph;
|
||||||
|
import static ru.resprojects.linkchecker.dto.GraphDto.EdgeGraph;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = LinkcheckerApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test", "debug"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
public class GraphRestControllerTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AppProperties properties;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getGraph() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphRestController.REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(TestUtils.graph)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exportGraphToGraphVizFormat() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(get(GraphRestController.REST_URL + "/export").accept(MediaType.TEXT_HTML_VALUE))
|
||||||
|
.andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus());
|
||||||
|
String content = result.getResponse().getContentAsString();
|
||||||
|
Assert.assertFalse(content.isEmpty());
|
||||||
|
Assert.assertTrue(content.contains("strict graph G"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraph() throws Exception {
|
||||||
|
Set<NodeGraph> nodesGraph = TestUtils.nodesGraph.stream()
|
||||||
|
.map(ng -> new GraphDto.NodeGraph(ng.getName()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<EdgeGraph> edgesGraph = TestUtils.edgesGraph.stream()
|
||||||
|
.map(eg -> new EdgeGraph(eg.getNodeOne(), eg.getNodeTwo()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
GraphDto graph = new GraphDto(nodesGraph, edgesGraph);
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphRestController.REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(graph))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus());
|
||||||
|
GraphDto returnedGraph = TestUtils.mapFromJson(result.getResponse().getContentAsString(), GraphDto.class);
|
||||||
|
Assert.assertNotNull(returnedGraph);
|
||||||
|
Assert.assertEquals(nodesGraph.size(), returnedGraph.getNodes().size());
|
||||||
|
Assert.assertEquals(edgesGraph.size(), returnedGraph.getEdges().size());
|
||||||
|
Assert.assertNotNull(returnedGraph.getNodes().iterator().next().getId());
|
||||||
|
Assert.assertNotNull(returnedGraph.getEdges().iterator().next().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraphEmptyNodeCollectionException() throws Exception {
|
||||||
|
Set<NodeGraph> nodesGraph = Collections.emptySet();
|
||||||
|
Set<EdgeGraph> edgesGraph = TestUtils.edgesGraph.stream()
|
||||||
|
.map(eg -> new EdgeGraph(eg.getNodeOne(), eg.getNodeTwo()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
GraphDto graph = new GraphDto(nodesGraph, edgesGraph);
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphRestController.REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(graph))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.GRAPH, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains("NODES: " + properties.getAppMsg().get("MSG_COLLECTION_EMPTY")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteGraph() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphRestController.REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent());
|
||||||
|
this.mvc.perform(get(GraphRestController.REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json(TestUtils.mapToJson(new GraphDto())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getOptions() throws Exception {
|
||||||
|
MvcResult result = this.mvc.perform(options(GraphRestController.REST_URL)
|
||||||
|
.accept(MediaType.APPLICATION_JSON)).andReturn();
|
||||||
|
Assert.assertTrue(result.getResponse().containsHeader("Allow"));
|
||||||
|
Assert.assertEquals("GET,POST,DELETE,OPTIONS", result.getResponse().getHeader("Allow"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteEmptyInputCollectionException() throws Exception {
|
||||||
|
List<String> route = new ArrayList<>();
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.GRAPH, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(properties.getAppMsg().get("MSG_COLLECTION_EMPTY")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNotEnoughDataException() throws Exception {
|
||||||
|
List<String> route = Collections.singletonList("v1");
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_ERROR, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.GRAPH, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(properties.getAppMsg().get("MSG_COLLECTION_CONTAIN_ONE_ELEMENT")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNotFoundException() throws Exception {
|
||||||
|
List<String> route = Stream.of("v7", "v2", "v1").collect(Collectors.toList());
|
||||||
|
MvcResult result = this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route))).andReturn();
|
||||||
|
Assert.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY.value(), result.getResponse().getStatus());
|
||||||
|
ErrorInfo error = TestUtils.mapFromJson(result.getResponse().getContentAsString(), ErrorInfo.class);
|
||||||
|
Assert.assertEquals(ErrorType.DATA_NOT_FOUND, error.getType());
|
||||||
|
Assert.assertEquals(ErrorPlaceType.GRAPH, error.getPlace());
|
||||||
|
List<String> errMsgs = Arrays.asList(error.getMessages());
|
||||||
|
Assert.assertTrue(errMsgs.contains(String.format(properties.getNodeMsg().get("NODE_MSG_BY_NAME_ERROR"), "v7")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest.apidocs;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.web.rest.GraphRestController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles(profiles = {"test"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
|
||||||
|
public class GraphApiDocumentation {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getGraph() throws Exception {
|
||||||
|
this.mvc.perform(MockMvcRequestBuilders.get(GraphRestController.REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(getGraphResponseDoc("get-graph"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exportGraphToGraphVizFormat() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphRestController.REST_URL + "/export").accept(MediaType.TEXT_HTML_VALUE))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("export-graph"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraph() throws Exception {
|
||||||
|
String jsonGraph = "{\n" +
|
||||||
|
" \"nodes\":[\n" +
|
||||||
|
" {\"name\":\"v1\"},\n" +
|
||||||
|
" {\"name\":\"v2\"},\n" +
|
||||||
|
" {\"name\":\"v3\"},\n" +
|
||||||
|
" {\"name\":\"v4\"},\n" +
|
||||||
|
" {\"name\":\"v5\"}\n" +
|
||||||
|
" ],\n" +
|
||||||
|
" \"edges\":[\n" +
|
||||||
|
" {\"nodeOne\":\"v1\",\"nodeTwo\":\"v2\"},\n" +
|
||||||
|
" {\"nodeOne\":\"v2\",\"nodeTwo\":\"v3\"},\n" +
|
||||||
|
" {\"nodeOne\":\"v3\",\"nodeTwo\":\"v4\"},\n" +
|
||||||
|
" {\"nodeOne\":\"v3\",\"nodeTwo\":\"v5\"},\n" +
|
||||||
|
" {\"nodeOne\":\"v5\",\"nodeTwo\":\"v4\"},\n" +
|
||||||
|
" {\"nodeOne\":\"v5\",\"nodeTwo\":\"v2\"}\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
this.mvc.perform(post(GraphRestController.REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonGraph))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andDo(document("create-graph",
|
||||||
|
requestFields(
|
||||||
|
fieldWithPath("nodes")
|
||||||
|
.description("Коллекция вершин графа (ноды)"),
|
||||||
|
fieldWithPath("nodes[].name")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("edges")
|
||||||
|
.description("Коллекция рёбер графа"),
|
||||||
|
fieldWithPath("edges[].nodeOne")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("edges[].nodeTwo")
|
||||||
|
.description("Уникальное имя вершины графа")
|
||||||
|
)))
|
||||||
|
.andDo(getGraphResponseDoc("create-graph"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createGraphEmptyNodeCollectionException() throws Exception {
|
||||||
|
Set<GraphDto.NodeGraph> nodesGraph = Collections.emptySet();
|
||||||
|
Set<GraphDto.EdgeGraph> edgesGraph = TestUtils.edgesGraph.stream()
|
||||||
|
.map(eg -> new GraphDto.EdgeGraph(eg.getNodeOne(), eg.getNodeTwo()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
GraphDto graph = new GraphDto(nodesGraph, edgesGraph);
|
||||||
|
this.mvc.perform(post(GraphRestController.REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(graph)))
|
||||||
|
.andDo(ErrorResponseDoc("create-graph-exception"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteEmptyInputCollectionException() throws Exception {
|
||||||
|
List<String> route = new ArrayList<>();
|
||||||
|
this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route)))
|
||||||
|
.andDo(ErrorResponseDoc( "checkroute-graph-exception-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNotEnoughDataException() throws Exception {
|
||||||
|
List<String> route = Collections.singletonList("v1");
|
||||||
|
this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route)))
|
||||||
|
.andDo(ErrorResponseDoc( "checkroute-graph-exception-2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteNotFoundException() throws Exception {
|
||||||
|
List<String> route = Stream.of("v7", "v2", "v1").collect(Collectors.toList());
|
||||||
|
this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route)))
|
||||||
|
.andDo(ErrorResponseDoc( "checkroute-graph-exception-3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteGraph() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphRestController.REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-graph"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestDocumentationResultHandler getGraphResponseDoc(String documentIdentifier) {
|
||||||
|
return document(documentIdentifier,
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("nodes")
|
||||||
|
.description("Коллекция вершин графа (ноды)"),
|
||||||
|
fieldWithPath("nodes[].id")
|
||||||
|
.description("Идентификатор вершины графа"),
|
||||||
|
fieldWithPath("nodes[].name")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("nodes[].counter")
|
||||||
|
.description("Колличество проходов через узел"),
|
||||||
|
fieldWithPath("edges")
|
||||||
|
.description("Коллекция рёбер графа"),
|
||||||
|
fieldWithPath("edges[].id")
|
||||||
|
.description("Уникальный идентификатор ребра графа"),
|
||||||
|
fieldWithPath("edges[].nodeOne")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("edges[].nodeTwo")
|
||||||
|
.description("Уникальное имя вершины графа")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RestDocumentationResultHandler ErrorResponseDoc(String documentIdentifier) {
|
||||||
|
return document(documentIdentifier,
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("url")
|
||||||
|
.description("REST-запрос, при котором возникла ошибка"),
|
||||||
|
fieldWithPath("type")
|
||||||
|
.description("тип ошибки"),
|
||||||
|
fieldWithPath("place")
|
||||||
|
.description("места возникновения ошибок"),
|
||||||
|
fieldWithPath("messages")
|
||||||
|
.description("сообщения об ошибках")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest.apidocs;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.services.GraphService;
|
||||||
|
import ru.resprojects.linkchecker.web.rest.GraphRestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anySet;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@WebMvcTest(GraphRestController.class)
|
||||||
|
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
|
||||||
|
public class GraphCheckRouteApiDocumentation {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private GraphService graphService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkRouteInGraph() throws Exception {
|
||||||
|
List<String> route = Stream.of("v1", "v2", "v3").collect(Collectors.toList());
|
||||||
|
String returnedResult = String.format("Route for nodes %s is found", route.toString());
|
||||||
|
given(this.graphService.checkRoute(anySet())).willReturn(returnedResult);
|
||||||
|
this.mvc.perform(post(GraphRestController.REST_URL + "/checkroute")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(route)))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(document("checkroute-graph"))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest.apidocs;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import ru.resprojects.linkchecker.web.rest.GraphEdgeRestController;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles(profiles = {"test"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
|
||||||
|
public class GraphEdgeApiDocumentation {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdges() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(ResponseEdgesDoc("get-edges"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeById() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byId/5005").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(ResponseEdgeDoc("get-edge-by-id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesByNodeName() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byName/v1").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(ResponseEdgesDoc("get-edges-by-node-name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByNodeNames() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byName?nodeOne=v1&nodeTwo=v2").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(ResponseEdgeDoc("get-edge-by-nodes-name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgeByIdNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byId/5050")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("get-edge-exception-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getEdgesByNameNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphEdgeRestController.EDGE_REST_URL + "/byName/v100")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("get-edge-exception-2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdge() throws Exception {
|
||||||
|
String jsonEdge = "{\"nodeOne\": \"v1\", \"nodeTwo\": \"v4\"}";
|
||||||
|
this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonEdge))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andDo(document("create-edge",
|
||||||
|
requestFields(
|
||||||
|
fieldWithPath("nodeOne")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("nodeTwo")
|
||||||
|
.description("Уникальное имя вершины графа")
|
||||||
|
)))
|
||||||
|
.andDo(ResponseEdgeDoc("create-edge"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdges() throws Exception {
|
||||||
|
String jsonEdge = "[{\"nodeOne\": \"v1\", \"nodeTwo\": \"v4\"},{\"nodeOne\": \"v2\", \"nodeTwo\": \"v4\"}]";
|
||||||
|
this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonEdge))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andDo(document("create-edges",
|
||||||
|
requestFields(
|
||||||
|
fieldWithPath("[]")
|
||||||
|
.description("Коллекция рёбер графа"),
|
||||||
|
fieldWithPath("[].nodeOne")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("[].nodeTwo")
|
||||||
|
.description("Уникальное имя вершины графа")
|
||||||
|
)))
|
||||||
|
.andDo(ResponseEdgesDoc("create-edges"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgeValidationException() throws Exception {
|
||||||
|
this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content("{\"nodeOne\": \"\", \"nodeTwo\": \"\"}"))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-edge-exception-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgeAlreadyPresentException() throws Exception {
|
||||||
|
this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content("{\"nodeOne\": \"v1\", \"nodeTwo\": \"v2\"}"))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-edge-exception-2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgesEmptyCollectionException() throws Exception {
|
||||||
|
this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content("[]"))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-edge-exception-3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgesCollectionContainNullObjectException() throws Exception {
|
||||||
|
String jsonEdge = "[null,{\"nodeOne\": \"v2\", \"nodeTwo\": \"v4\"}]";
|
||||||
|
this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonEdge))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-edge-exception-4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewEdgesCollectionContainAlreadyPresentNodeException() throws Exception {
|
||||||
|
String jsonEdge = "[{\"nodeOne\": \"v1\", \"nodeTwo\": \"v2\"},{\"nodeOne\": \"v1\", \"nodeTwo\": \"v4\"},{\"nodeOne\": \"v2\", \"nodeTwo\": \"v4\"}]";
|
||||||
|
this.mvc.perform(post(GraphEdgeRestController.EDGE_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonEdge))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-edge-exception-5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteAllEdges() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-all-edges"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeById() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byId/5005").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-edge-by-id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgesByNodeName() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName/v4").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-edges-by-node-name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeNames() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName?nodeOne=v1&nodeTwo=v2").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-edge-by-nodes-name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByIdNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byId/5050")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-edge-exception-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgesByNodeNameNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName/v50")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-edge-exception-2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteEdgeByNodeNamesNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphEdgeRestController.EDGE_REST_URL + "/byName?nodeOne=v50&nodeTwo=v2")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-edge-exception-3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RestDocumentationResultHandler ResponseEdgeDoc(String documentIdentifier) {
|
||||||
|
return document(documentIdentifier,
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("id")
|
||||||
|
.description("Идентификатор ребра графа"),
|
||||||
|
fieldWithPath("nodeOne")
|
||||||
|
.description("Уникальное имя первой вершины графа, которое связывается текущим ребром"),
|
||||||
|
fieldWithPath("nodeTwo")
|
||||||
|
.description("Уникальное имя второй вершины графа, которое связывается текущим ребром")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RestDocumentationResultHandler ResponseEdgesDoc(String documentIdentifier) {
|
||||||
|
return document(documentIdentifier,
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("[]")
|
||||||
|
.description("Коллекция рёбер"),
|
||||||
|
fieldWithPath("[].id")
|
||||||
|
.description("Идентификатор ребра графа"),
|
||||||
|
fieldWithPath("[].nodeOne")
|
||||||
|
.description("Уникальное имя первой вершины графа, которое связывается текущим ребром"),
|
||||||
|
fieldWithPath("[].nodeTwo")
|
||||||
|
.description("Уникальное имя второй вершины графа, которое связывается текущим ребром")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest.apidocs;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import ru.resprojects.linkchecker.TestUtils;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
import ru.resprojects.linkchecker.web.rest.GraphNodeRestController;
|
||||||
|
|
||||||
|
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||||
|
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles(profiles = {"test"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql", "classpath:data-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
|
||||||
|
public class GraphNodeApiDocumentation {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mvc;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodes() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(ResponseNodesDoc("get-nodes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeById() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL + "/byId/5000").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(ResponseNodeDoc("get-node-by-id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByName() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL + "/byName/v1").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(ResponseNodeDoc("get-node-by-name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getNodeByNameNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(get(GraphNodeRestController.NODES_REST_URL + "/byName/v10")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("get-node-by-name-exception"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodeToGraph() throws Exception {
|
||||||
|
String jsonNode = "{\"name\": \"v6\"}";
|
||||||
|
this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonNode))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andDo(document("create-node",
|
||||||
|
requestFields(
|
||||||
|
fieldWithPath("name")
|
||||||
|
.description("Уникальное имя вершины графа")
|
||||||
|
)))
|
||||||
|
.andDo(ResponseNodeDoc("create-node"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesToGraph() throws Exception {
|
||||||
|
String jsonNodes = "[{\"name\":\"v6\"}, {\"name\":\"v7\"}, {\"name\":\"v8\"}]";
|
||||||
|
this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonNodes))
|
||||||
|
.andDo(document("create-nodes",
|
||||||
|
requestFields(
|
||||||
|
fieldWithPath("[]")
|
||||||
|
.description("Коллекция вершин графа (ноды)"),
|
||||||
|
fieldWithPath("[].name")
|
||||||
|
.description("Уникальное имя вершины графа")
|
||||||
|
)))
|
||||||
|
.andDo(ResponseNodesDoc("create-nodes"))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodeValidationException() throws Exception {
|
||||||
|
String jsonNode = "{\"name\":\"\"}";
|
||||||
|
this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonNode))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-node-exception-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodeAlreadyPresentException() throws Exception {
|
||||||
|
String jsonNode = "{\"name\": \"v1\"}";
|
||||||
|
this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonNode))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-node-exception-2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesEmptyCollectionException() throws Exception {
|
||||||
|
this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content("[]"))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-node-exception-3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesCollectionContainNullObjectException() throws Exception {
|
||||||
|
String jsonNodes = "[null, {\"name\": \"v7\"}, {\"name\": \"v8\"}]";
|
||||||
|
this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonNodes))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-node-exception-4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNewNodesCollectionContainAlreadyPresentNodeException() throws Exception {
|
||||||
|
String jsonNodes = "[{\"name\":\"v1\"}, {\"name\":\"v7\"}, {\"name\":\"v8\"}]";
|
||||||
|
this.mvc.perform(post(GraphNodeRestController.NODES_REST_URL + "/create/byBatch")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(jsonNodes))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("create-node-exception-5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteAllNodes() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL).accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-all-nodes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeById() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byId/5000").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-node-by-id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByName() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byName/v1").accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-node-by-name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObject() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj").contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(TestUtils.nodeGraph)))
|
||||||
|
.andExpect(status().isNoContent())
|
||||||
|
.andDo(document("delete-node-by-obj"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByIdNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byId/5050")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-node-exception-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByNameNotFoundException() throws Exception {
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byName/v10")
|
||||||
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-node-exception-2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObjectWithNullIdNotFoundException() throws Exception {
|
||||||
|
GraphDto.NodeGraph newNode = new GraphDto.NodeGraph(null, "v10", 0);
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode)))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-node-exception-3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObjectNotFoundException() throws Exception {
|
||||||
|
GraphDto.NodeGraph newNode = new GraphDto.NodeGraph(5020, "v10", 0);
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode)))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-node-exception-4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteNodeByObjectWithIncorrectIdException() throws Exception {
|
||||||
|
GraphDto.NodeGraph newNode = new GraphDto.NodeGraph(5000, "v10", 0);
|
||||||
|
this.mvc.perform(delete(GraphNodeRestController.NODES_REST_URL + "/byObj")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(TestUtils.mapToJson(newNode)))
|
||||||
|
.andDo(GraphApiDocumentation.ErrorResponseDoc("delete-node-exception-5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RestDocumentationResultHandler ResponseNodeDoc(String documentIdentifier) {
|
||||||
|
return document(documentIdentifier,
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("id")
|
||||||
|
.description("Идентификатор вершины графа"),
|
||||||
|
fieldWithPath("name")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("counter")
|
||||||
|
.description("Колличество проходов через вершину графа")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RestDocumentationResultHandler ResponseNodesDoc(String documentIdentifier) {
|
||||||
|
return document(documentIdentifier,
|
||||||
|
responseFields(
|
||||||
|
fieldWithPath("[]")
|
||||||
|
.description("Коллекция вершин графа (ноды)"),
|
||||||
|
fieldWithPath("[].id")
|
||||||
|
.description("Идентификатор вершины графа"),
|
||||||
|
fieldWithPath("[].name")
|
||||||
|
.description("Уникальное имя вершины графа"),
|
||||||
|
fieldWithPath("[].counter")
|
||||||
|
.description("Колличество проходов через вершину графа")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package ru.resprojects.linkchecker.web.rest.json;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.json.JsonTest;
|
||||||
|
import org.springframework.boot.test.json.GsonTester;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.linkchecker.dto.GraphDto;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static ru.resprojects.linkchecker.TestUtils.*;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@JsonTest
|
||||||
|
public class JsonGraphDtoTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GsonTester<GraphDto> jsonGraph;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GsonTester<GraphDto.NodeGraph> jsonNodeGraph;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GsonTester<GraphDto.EdgeGraph> jsonEdgeGraph;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GsonTester<Set<GraphDto.NodeGraph>> jsonNodesGraph;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GsonTester<Set<GraphDto.EdgeGraph>> jsonEdgesGraph;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeJsonGraphDto() throws Exception {
|
||||||
|
assertThat(this.jsonGraph.write(graph)).isEqualTo("graph.json");
|
||||||
|
assertThat(this.jsonGraph.write(graph)).isEqualToJson("graph.json");
|
||||||
|
assertThat(this.jsonGraph.write(graph)).hasJsonPathArrayValue("@.nodes");
|
||||||
|
assertThat(this.jsonGraph.write(graph)).hasJsonPathArrayValue("@.edges");
|
||||||
|
assertThat(this.jsonGraph.write(graph))
|
||||||
|
.extractingJsonPathArrayValue("@.nodes")
|
||||||
|
.hasSameSizeAs(graph.getNodes());
|
||||||
|
assertThat(this.jsonGraph.write(graph))
|
||||||
|
.extractingJsonPathArrayValue("@.edges")
|
||||||
|
.hasSameSizeAs(graph.getEdges());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeJsonNodes() throws Exception {
|
||||||
|
assertThat(this.jsonNodesGraph.write(nodesGraph)).isEqualTo("nodes.json");
|
||||||
|
assertThat(this.jsonNodesGraph.write(nodesGraph)).isEqualToJson("nodes.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeJsonEdges() throws Exception {
|
||||||
|
assertThat(this.jsonEdgesGraph.write(edgesGraph)).isEqualTo("edges.json");
|
||||||
|
assertThat(this.jsonEdgesGraph.write(edgesGraph)).isEqualToJson("edges.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeJsonNode() throws Exception {
|
||||||
|
assertThat(this.jsonNodeGraph.write(nodeGraph)).isEqualTo("node.json");
|
||||||
|
assertThat(this.jsonNodeGraph.write(nodeGraph)).isEqualToJson("node.json");
|
||||||
|
assertThat(this.jsonNodeGraph.write(nodeGraph)).extractingJsonPathStringValue("@.name")
|
||||||
|
.isEqualTo(nodeGraph.getName());
|
||||||
|
assertThat(this.jsonNodeGraph.write(nodeGraph))
|
||||||
|
.extractingJsonPathNumberValue("@.id")
|
||||||
|
.isEqualTo(nodeGraph.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeJsonEdge() throws Exception {
|
||||||
|
assertThat(this.jsonEdgeGraph.write(edgeGraph)).isEqualTo("edge.json");
|
||||||
|
assertThat(this.jsonEdgeGraph.write(edgeGraph)).isEqualToJson("edge.json");
|
||||||
|
assertThat(this.jsonEdgeGraph.write(edgeGraph)).extractingJsonPathStringValue("@.nodeOne")
|
||||||
|
.isEqualTo(edgeGraph.getNodeOne());
|
||||||
|
assertThat(this.jsonEdgeGraph.write(edgeGraph))
|
||||||
|
.extractingJsonPathStringValue("@.nodeTwo")
|
||||||
|
.isEqualTo(edgeGraph.getNodeTwo());
|
||||||
|
assertThat(this.jsonEdgeGraph.write(edgeGraph))
|
||||||
|
.extractingJsonPathNumberValue("@.id")
|
||||||
|
.isEqualTo(edgeGraph.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deserializeJsonNode() throws Exception {
|
||||||
|
String content = "{\"id\": 5000, \"name\": \"v1\", \"counter\": 0}";
|
||||||
|
assertThat(this.jsonNodeGraph.parse(content)).isEqualTo(nodeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deserializeJsonEdge() throws Exception {
|
||||||
|
String content = "{\"id\": 5005, \"nodeOne\": \"v1\", \"nodeTwo\": \"v2\"}";
|
||||||
|
assertThat(this.jsonEdgeGraph.parse(content)).isEqualTo(edgeGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"id": 5005, "nodeOne": "v1", "nodeTwo": "v2"}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 5006,
|
||||||
|
"nodeOne": "v1",
|
||||||
|
"nodeTwo": "v3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5005,
|
||||||
|
"nodeOne": "v1",
|
||||||
|
"nodeTwo": "v2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5007,
|
||||||
|
"nodeOne": "v1",
|
||||||
|
"nodeTwo": "v5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5008,
|
||||||
|
"nodeOne": "v3",
|
||||||
|
"nodeTwo": "v4"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": 5000,
|
||||||
|
"name": "v1",
|
||||||
|
"counter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5001,
|
||||||
|
"name": "v2",
|
||||||
|
"counter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5002,
|
||||||
|
"name": "v3",
|
||||||
|
"counter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5003,
|
||||||
|
"name": "v4",
|
||||||
|
"counter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5004,
|
||||||
|
"name": "v5",
|
||||||
|
"counter": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"id": 5006,
|
||||||
|
"nodeOne": "v1",
|
||||||
|
"nodeTwo": "v3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5005,
|
||||||
|
"nodeOne": "v1",
|
||||||
|
"nodeTwo": "v2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5007,
|
||||||
|
"nodeOne": "v1",
|
||||||
|
"nodeTwo": "v5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5008,
|
||||||
|
"nodeOne": "v3",
|
||||||
|
"nodeTwo": "v4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"id": 5000, "name": "v1", "counter": 0}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user