From ec65ec6ad288ebac2be6d5a7cfc7c79c02b269c2 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Sun, 3 Aug 2025 11:16:57 +0300 Subject: [PATCH 1/8] =?UTF-8?q?feature:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=209=D0=B3=D0=BE=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/libraries/gson_2_9_0.xml | 9 + java-kanban.iml | 1 + src/tracker/server/BaseHttpHandler.java | 26 ++ src/tracker/server/HttpTaskServer.java | 321 +++++++++++++++++++++ test/tracker/HttpTaskManagerTasksTest.java | 213 ++++++++++++++ 5 files changed, 570 insertions(+) create mode 100644 .idea/libraries/gson_2_9_0.xml create mode 100644 src/tracker/server/BaseHttpHandler.java create mode 100644 src/tracker/server/HttpTaskServer.java create mode 100644 test/tracker/HttpTaskManagerTasksTest.java diff --git a/.idea/libraries/gson_2_9_0.xml b/.idea/libraries/gson_2_9_0.xml new file mode 100644 index 0000000..2377008 --- /dev/null +++ b/.idea/libraries/gson_2_9_0.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/java-kanban.iml b/java-kanban.iml index 635e7f3..6982687 100644 --- a/java-kanban.iml +++ b/java-kanban.iml @@ -40,5 +40,6 @@ + \ No newline at end of file diff --git a/src/tracker/server/BaseHttpHandler.java b/src/tracker/server/BaseHttpHandler.java new file mode 100644 index 0000000..c268bde --- /dev/null +++ b/src/tracker/server/BaseHttpHandler.java @@ -0,0 +1,26 @@ +package tracker.server; + +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class BaseHttpHandler { + public static void sendText(HttpExchange httpExchange, String text) throws IOException { + byte[] response = text.getBytes(StandardCharsets.UTF_8); + httpExchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8"); + httpExchange.sendResponseHeaders(200, response.length); + httpExchange.getResponseBody().write(response); + httpExchange.close(); + } + + public static void sendNotFound(HttpExchange httpExchange) throws IOException { + httpExchange.sendResponseHeaders(404, 0); + httpExchange.close(); + } + + public static void sendHasOverlaps(HttpExchange httpExchange) throws IOException { + httpExchange.sendResponseHeaders(406, 0); + httpExchange.close(); + } +} diff --git a/src/tracker/server/HttpTaskServer.java b/src/tracker/server/HttpTaskServer.java new file mode 100644 index 0000000..b78146c --- /dev/null +++ b/src/tracker/server/HttpTaskServer.java @@ -0,0 +1,321 @@ +package tracker.server; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import tracker.controllers.Managers; +import tracker.controllers.TaskManager; +import tracker.model.Epic; +import tracker.model.Subtask; +import tracker.model.Task; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; + +public class HttpTaskServer { + private final int port; + final TaskManager taskManager; + private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + private static final Gson gson = new Gson(); + private HttpServer httpServer; + + public HttpTaskServer(int port, TaskManager taskManager) { + this.port = port; + this.taskManager = taskManager; + } + + public static void main(String[] args) throws IOException { + final long MINUTES_IN_DAY = 60 * 24; + final LocalDateTime TASK_START_TIME = LocalDateTime.now(); + TaskManager inMemoryTaskManager = Managers.getDefault(); + HttpTaskServer taskServer = new HttpTaskServer(80, inMemoryTaskManager); + taskServer.start(); + + // Создайте две задачи, а также эпик с двумя подзадачами и эпик с одной подзадачей + Task task1 = new Task("tracker.model.Task 1", "Do task 1", inMemoryTaskManager.getTaskId(), + MINUTES_IN_DAY, TASK_START_TIME.minusDays(4)); + inMemoryTaskManager.createTask(task1); + Task task2 = new Task("tracker.model.Task 2", "Do task 2", inMemoryTaskManager.getTaskId(), + MINUTES_IN_DAY, TASK_START_TIME.minusDays(3)); + inMemoryTaskManager.createTask(task2); + Epic epic1 = new Epic("tracker.model.Epic 1", "Do all subtasks from epic 1", + inMemoryTaskManager.getTaskId()); + inMemoryTaskManager.createEpic(epic1); + Epic epic2 = new Epic("tracker.model.Epic 2", "Do all subtasks from epic 2", + inMemoryTaskManager.getTaskId()); + inMemoryTaskManager.createEpic(epic2); + Subtask subtask1 = new Subtask("tracker.model.Subtask 1", "Do subtask 1", inMemoryTaskManager.getTaskId(), + epic1, MINUTES_IN_DAY, TASK_START_TIME.minusDays(2)); + inMemoryTaskManager.createSubtask(subtask1); + Subtask subtask2 = new Subtask("tracker.model.Subtask 2", "Do subtask 2", inMemoryTaskManager.getTaskId(), + epic1, MINUTES_IN_DAY, TASK_START_TIME.minusDays(1)); + inMemoryTaskManager.createSubtask(subtask2); + Subtask subtask3 = new Subtask("tracker.model.Subtask 3", "Do subtask 3", inMemoryTaskManager.getTaskId(), + epic2, MINUTES_IN_DAY, TASK_START_TIME); + inMemoryTaskManager.createSubtask(subtask3); + } + + public void start() throws IOException { + httpServer = HttpServer.create(); + httpServer.bind(new InetSocketAddress(port), 0); + httpServer.createContext("/tasks", new TasksHandler()); + httpServer.createContext("/subtasks", new SubtasksHandler()); + httpServer.createContext("/epics", new EpicsHandler()); + httpServer.createContext("/history", new HistoryHandler()); + httpServer.createContext("/prioritized", new PrioritizedHandler()); + httpServer.start(); + } + + public void stop() { + httpServer.stop(0); + } + + class TasksHandler implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + switch (method) { + case "GET" -> { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, "Получен список задач"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(taskManager.getTasks()).getBytes()); + } + return; + } else if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Task task = taskManager.getTaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, "Задача с id=" + task.getId() + " найдена"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(task).getBytes()); + } + } + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + case "POST" -> { + if (partsOfPath.length == 3) { + InputStream inputStream = httpExchange.getRequestBody(); + String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + Task task = gson.fromJson(body, Task.class); + taskManager.createTask(task); + BaseHttpHandler.sendText(httpExchange, "Задача с id=" + task.getId() + " создана"); + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + case "DELETE" -> { + if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Task task = taskManager.getTaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + taskManager.deleteTask(task); + BaseHttpHandler.sendText(httpExchange, "Задача с id=" + task.getId() + " удалена"); + } + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + default -> BaseHttpHandler.sendNotFound(httpExchange); + } + } + } + + class SubtasksHandler implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + switch (method) { + case "GET" -> { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, "Получен список подзадач"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(taskManager.getSubtasks()).getBytes()); + } + return; + } else if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Subtask task = taskManager.getSubtaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, "Подзадача с id=" + task.getId() + " найдена"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(task).getBytes()); + } + } + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + case "POST" -> { + if (partsOfPath.length == 3) { + InputStream inputStream = httpExchange.getRequestBody(); + String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + Subtask task = gson.fromJson(body, Subtask.class); + taskManager.createSubtask(task); + BaseHttpHandler.sendText(httpExchange, "Подзадача с id=" + task.getId() + " создана"); + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + case "DELETE" -> { + if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Subtask task = taskManager.getSubtaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + taskManager.deleteTask(task); + BaseHttpHandler.sendText(httpExchange, "Подзадача с id=" + task.getId() + " удалена"); + } + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + default -> BaseHttpHandler.sendNotFound(httpExchange); + } + } + } + + class EpicsHandler implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + switch (method) { + case "GET" -> { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, "Получен список эпиков"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(taskManager.getEpics()).getBytes()); + } + return; + } else if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Epic epic = taskManager.getEpicById(id); + if (epic == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " найден"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(epic).getBytes()); + } + } + } else if (partsOfPath.length == 4 && partsOfPath[3].equals("subtasks")) { + int id = Integer.parseInt(partsOfPath[2]); + Epic epic = taskManager.getEpicById(id); + if (epic == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " найден"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(taskManager.getEpicsSubtasks(id)).getBytes()); + } + } + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + case "POST" -> { + if (partsOfPath.length == 3) { + InputStream inputStream = httpExchange.getRequestBody(); + String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + Epic epic = gson.fromJson(body, Epic.class); + taskManager.createEpic(epic); + BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " создан"); + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + case "DELETE" -> { + if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Epic epic = taskManager.getEpicById(id); + if (epic == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + taskManager.deleteEpic(epic); + BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " удален"); + } + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } + default -> BaseHttpHandler.sendNotFound(httpExchange); + } + } + } + + class HistoryHandler implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + if (method.equals("GET")) { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, "Получена история просмотра задач"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(taskManager.getHistory()).getBytes()); + } + return; + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + } + } + + class PrioritizedHandler implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + if (method.equals("GET")) { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, "Получен отсортированный список задач"); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(gson.toJson(taskManager.getPrioritizedTasks()).getBytes()); + } + return; + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + httpExchange.close(); + } else { + BaseHttpHandler.sendNotFound(httpExchange); + } + } + } +} diff --git a/test/tracker/HttpTaskManagerTasksTest.java b/test/tracker/HttpTaskManagerTasksTest.java new file mode 100644 index 0000000..b6150cd --- /dev/null +++ b/test/tracker/HttpTaskManagerTasksTest.java @@ -0,0 +1,213 @@ +package tracker; + +import com.google.gson.Gson; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterEach; +import tracker.controllers.InMemoryTaskManager; +import tracker.controllers.TaskManager; +import tracker.model.Epic; +import tracker.model.Subtask; +import tracker.model.Task; +import tracker.server.HttpTaskServer; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class HttpTaskManagerTasksTest { + + TaskManager taskManager = new InMemoryTaskManager(); + HttpTaskServer taskServer = new HttpTaskServer(8080, taskManager); + private static final Gson gson = new Gson(); + final long MINUTES_IN_DAY = 60 * 24; + final LocalDateTime TASK_START_TIME = LocalDateTime.now(); + + @BeforeEach + public void setUp() throws IOException { + taskServer.start(); + } + + @AfterEach + public void shutDown() { + taskServer.stop(); + } + + @Test + public void testTasks() throws IOException, InterruptedException { + Task task1 = new Task("Task 1", "Do task 1", taskManager.getTaskId(), MINUTES_IN_DAY, + TASK_START_TIME.minusDays(4)); + Task task2 = new Task("Task 2", "Do task 2", taskManager.getTaskId(), MINUTES_IN_DAY, + TASK_START_TIME.minusDays(3)); + + String task1Json = gson.toJson(task1); + String task2Json = gson.toJson(task2); + URI urlTasks = URI.create("http://localhost:8080/tasks"); + + HttpResponse response; + HttpRequest request; + + try (HttpClient client = HttpClient.newHttpClient()) { + request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task1Json)) + .build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + // 1. создаем 1 задачу + List tasksFromManager = taskManager.getTasks(); + + assertNotNull(tasksFromManager, "Список задач пуст"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество задач"); + assertEquals("Task 1", tasksFromManager.get(0).getName(), "Некорректное имя задачи"); + + // 2. создаем 2 задачу + try (HttpClient client = HttpClient.newHttpClient()) { + request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task2Json)) + .build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + tasksFromManager = taskManager.getTasks(); + assertNotNull(tasksFromManager, "Список задач пуст"); + assertEquals(2, tasksFromManager.size(), "Некорректное количество задач"); + assertEquals("Task 1", tasksFromManager.get(0).getName(), "Некорректное имя задачи"); + assertEquals("Task 2", tasksFromManager.get(1).getName(), "Некорректное имя задачи"); + + // 3. удаляем 1 задачу + try (HttpClient client = HttpClient.newHttpClient()) { + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE() + .build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + tasksFromManager = taskManager.getTasks(); + assertNotNull(tasksFromManager, "Список задач пуст"); + assertEquals(1, tasksFromManager.size(), "Некорректное количество задач"); + assertEquals("Task 2", tasksFromManager.get(1).getName(), "Некорректное имя задачи"); + + // 4. удаляем 2 задачу + try (HttpClient client = HttpClient.newHttpClient()) { + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE() + .build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + tasksFromManager = taskManager.getTasks(); + assertEquals(0, tasksFromManager.size(), "Некорректное количество задач"); + } + + public void checkEpicsAndSubtasks() throws IOException, InterruptedException { + Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", taskManager.getTaskId()); + Epic epic2 = new Epic("Epic 2", "Do all subtasks from epic 2", taskManager.getTaskId()); + Subtask subtask1 = new Subtask("Subtask 1", "Do subtask 1", taskManager.getTaskId(), epic1, + MINUTES_IN_DAY, TASK_START_TIME.minusDays(2)); + Subtask subtask2 = new Subtask("Subtask 2", "Do subtask 2", taskManager.getTaskId(), epic1, + MINUTES_IN_DAY, TASK_START_TIME.minusDays(1)); + Subtask subtask3 = new Subtask("Subtask 3", "Do subtask 3", taskManager.getTaskId(), epic2, + MINUTES_IN_DAY, TASK_START_TIME); + + String epic1Json = gson.toJson(epic1); + String epic2Json = gson.toJson(epic2); + String subtask1Json = gson.toJson(subtask1); + String subtask2Json = gson.toJson(subtask2); + String subtask3Json = gson.toJson(subtask3); + + URI urlEpics = URI.create("http://localhost:8080/epics"); + URI urlSubtasks = URI.create("http://localhost:8080/subtasks"); + + HttpRequest request; + HttpResponse response; + // 1. Создаем эпики + try (HttpClient client = HttpClient.newHttpClient()) { + request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers. + ofString(epic1Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers. + ofString(epic2Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + List epicsFromManager = taskManager.getEpics(); + + assertNotNull(epicsFromManager, "Список задач пуст"); + assertEquals(2, epicsFromManager.size(), "Некорректное количество эпиков"); + assertEquals("Epic 1", epicsFromManager.get(0).getName(), "Некорректное имя эпика"); + assertEquals("Epic 2", epicsFromManager.get(1).getName(), "Некорректное имя эпика"); + + // 2. Создаем подзадачи + try (HttpClient client = HttpClient.newHttpClient()) { + HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers. + ofString(subtask1Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers. + ofString(subtask2Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers. + ofString(subtask3Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + List subtasksFromManager = taskManager.getSubtasks(); + + assertNotNull(subtasksFromManager, "Список задач пуст"); + assertEquals(3, subtasksFromManager.size(), "Некорректное количество подзадач"); + assertEquals("Subtask 1", subtasksFromManager.get(0).getName(), "Некорректное имя подзадачи"); + assertEquals("Subtask 2", subtasksFromManager.get(1).getName(), "Некорректное имя подзадачи"); + assertEquals("Subtask 3", subtasksFromManager.get(2).getName(), "Некорректное имя подзадачи"); + + // 3. удаляем подзадачи + try (HttpClient client = HttpClient.newHttpClient()) { + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask1.getId())) + .DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask2.getId())) + .DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask3.getId())) + .DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + subtasksFromManager = taskManager.getSubtasks(); + assertEquals(0, subtasksFromManager.size(), "Некорректное количество задач"); + + // 4. удаляем эпики + try (HttpClient client = HttpClient.newHttpClient()) { + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic1.getId())) + .DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic2.getId())) + .DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + epicsFromManager = taskManager.getEpics(); + assertEquals(0, epicsFromManager.size(), "Некорректное количество задач"); + } +} \ No newline at end of file From 13c9a9ddcc2950aa24cbc75247db1a4d84787dcf Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Sun, 3 Aug 2025 11:28:28 +0300 Subject: [PATCH 2/8] =?UTF-8?q?feature:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=209=D0=B3=D0=BE=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/inspectionProfiles/Project_Default.xml | 8 ++ src/tracker/server/HttpTaskServer.java | 2 +- test/tracker/HttpTaskManagerTasksTest.java | 123 ++++++++----------- 3 files changed, 61 insertions(+), 72 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..869c305 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/src/tracker/server/HttpTaskServer.java b/src/tracker/server/HttpTaskServer.java index b78146c..6bd4738 100644 --- a/src/tracker/server/HttpTaskServer.java +++ b/src/tracker/server/HttpTaskServer.java @@ -34,7 +34,7 @@ public static void main(String[] args) throws IOException { final long MINUTES_IN_DAY = 60 * 24; final LocalDateTime TASK_START_TIME = LocalDateTime.now(); TaskManager inMemoryTaskManager = Managers.getDefault(); - HttpTaskServer taskServer = new HttpTaskServer(80, inMemoryTaskManager); + HttpTaskServer taskServer = new HttpTaskServer(8080, inMemoryTaskManager); taskServer.start(); // Создайте две задачи, а также эпик с двумя подзадачами и эпик с одной подзадачей diff --git a/test/tracker/HttpTaskManagerTasksTest.java b/test/tracker/HttpTaskManagerTasksTest.java index b6150cd..9a3c9b9 100644 --- a/test/tracker/HttpTaskManagerTasksTest.java +++ b/test/tracker/HttpTaskManagerTasksTest.java @@ -53,12 +53,10 @@ public void testTasks() throws IOException, InterruptedException { HttpResponse response; HttpRequest request; - try (HttpClient client = HttpClient.newHttpClient()) { - request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task1Json)) - .build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + HttpClient client = HttpClient.newHttpClient(); + request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task1Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); // 1. создаем 1 задачу List tasksFromManager = taskManager.getTasks(); @@ -68,12 +66,9 @@ public void testTasks() throws IOException, InterruptedException { assertEquals("Task 1", tasksFromManager.get(0).getName(), "Некорректное имя задачи"); // 2. создаем 2 задачу - try (HttpClient client = HttpClient.newHttpClient()) { - request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task2Json)) - .build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task2Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); tasksFromManager = taskManager.getTasks(); assertNotNull(tasksFromManager, "Список задач пуст"); @@ -82,12 +77,9 @@ public void testTasks() throws IOException, InterruptedException { assertEquals("Task 2", tasksFromManager.get(1).getName(), "Некорректное имя задачи"); // 3. удаляем 1 задачу - try (HttpClient client = HttpClient.newHttpClient()) { - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE() - .build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); tasksFromManager = taskManager.getTasks(); assertNotNull(tasksFromManager, "Список задач пуст"); @@ -95,17 +87,16 @@ public void testTasks() throws IOException, InterruptedException { assertEquals("Task 2", tasksFromManager.get(1).getName(), "Некорректное имя задачи"); // 4. удаляем 2 задачу - try (HttpClient client = HttpClient.newHttpClient()) { - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE() - .build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE() + .build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); tasksFromManager = taskManager.getTasks(); assertEquals(0, tasksFromManager.size(), "Некорректное количество задач"); } + @Test public void checkEpicsAndSubtasks() throws IOException, InterruptedException { Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", taskManager.getTaskId()); Epic epic2 = new Epic("Epic 2", "Do all subtasks from epic 2", taskManager.getTaskId()); @@ -128,17 +119,14 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { HttpRequest request; HttpResponse response; // 1. Создаем эпики - try (HttpClient client = HttpClient.newHttpClient()) { - request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers. - ofString(epic1Json)).build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - - request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers. - ofString(epic2Json)).build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + HttpClient client = HttpClient.newHttpClient(); + request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers.ofString(epic1Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers.ofString(epic2Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); List epicsFromManager = taskManager.getEpics(); @@ -148,22 +136,19 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { assertEquals("Epic 2", epicsFromManager.get(1).getName(), "Некорректное имя эпика"); // 2. Создаем подзадачи - try (HttpClient client = HttpClient.newHttpClient()) { - HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers. - ofString(subtask1Json)).build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - - request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers. - ofString(subtask2Json)).build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - - request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers. - ofString(subtask3Json)).build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask1Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask2Json)). + build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + + request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask3Json)) + .build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); List subtasksFromManager = taskManager.getSubtasks(); @@ -174,38 +159,34 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { assertEquals("Subtask 3", subtasksFromManager.get(2).getName(), "Некорректное имя подзадачи"); // 3. удаляем подзадачи - try (HttpClient client = HttpClient.newHttpClient()) { - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask1.getId())) - .DELETE().build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask1.getId())) + .DELETE().build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask2.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask2.getId())) .DELETE().build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask3.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask3.getId())) .DELETE().build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); subtasksFromManager = taskManager.getSubtasks(); assertEquals(0, subtasksFromManager.size(), "Некорректное количество задач"); // 4. удаляем эпики - try (HttpClient client = HttpClient.newHttpClient()) { - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic1.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic1.getId())) .DELETE().build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic2.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic2.getId())) .DELETE().build(); - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - } + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); epicsFromManager = taskManager.getEpics(); assertEquals(0, epicsFromManager.size(), "Некорректное количество задач"); From 48970db62a92bf8315a813ef949ef0364648d1a7 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Mon, 4 Aug 2025 00:16:30 +0300 Subject: [PATCH 3/8] =?UTF-8?q?feature:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=209=D0=B3=D0=BE=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tracker/model/LocalDateAdapter.java | 23 +++++++ src/tracker/server/HttpTaskServer.java | 76 ++++++++-------------- test/tracker/HttpTaskManagerTasksTest.java | 49 ++++++++------ 3 files changed, 78 insertions(+), 70 deletions(-) create mode 100644 src/tracker/model/LocalDateAdapter.java diff --git a/src/tracker/model/LocalDateAdapter.java b/src/tracker/model/LocalDateAdapter.java new file mode 100644 index 0000000..9964f2a --- /dev/null +++ b/src/tracker/model/LocalDateAdapter.java @@ -0,0 +1,23 @@ +package tracker.model; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class LocalDateAdapter extends TypeAdapter { + private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS"); + + @Override + public void write(final JsonWriter jsonWriter, final LocalDateTime localDate) throws IOException { + jsonWriter.value(localDate.format(dtf)); + } + + @Override + public LocalDateTime read(final JsonReader jsonReader) throws IOException { + return LocalDateTime.parse(jsonReader.nextString(), dtf); + } +} diff --git a/src/tracker/server/HttpTaskServer.java b/src/tracker/server/HttpTaskServer.java index 6bd4738..2da0705 100644 --- a/src/tracker/server/HttpTaskServer.java +++ b/src/tracker/server/HttpTaskServer.java @@ -1,18 +1,18 @@ package tracker.server; -import com.google.gson.Gson; +import com.google.gson.*; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import tracker.controllers.Managers; import tracker.controllers.TaskManager; import tracker.model.Epic; +import tracker.model.LocalDateAdapter; import tracker.model.Subtask; import tracker.model.Task; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.net.InetSocketAddress; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -22,12 +22,17 @@ public class HttpTaskServer { private final int port; final TaskManager taskManager; private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; - private static final Gson gson = new Gson(); + + private static Gson gson; private HttpServer httpServer; public HttpTaskServer(int port, TaskManager taskManager) { this.port = port; this.taskManager = taskManager; + gson = new GsonBuilder() + .serializeNulls() + .registerTypeAdapter(LocalDateTime.class, new LocalDateAdapter()) + .create(); } public static void main(String[] args) throws IOException { @@ -85,10 +90,7 @@ public void handle(HttpExchange httpExchange) throws IOException { switch (method) { case "GET" -> { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, "Получен список задач"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(taskManager.getTasks()).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getTasks())); return; } else if (partsOfPath.length == 3) { int id = Integer.parseInt(partsOfPath[2]); @@ -96,10 +98,7 @@ public void handle(HttpExchange httpExchange) throws IOException { if (task == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, "Задача с id=" + task.getId() + " найдена"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(task).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); } } else { BaseHttpHandler.sendNotFound(httpExchange); @@ -107,12 +106,12 @@ public void handle(HttpExchange httpExchange) throws IOException { httpExchange.close(); } case "POST" -> { - if (partsOfPath.length == 3) { + if (partsOfPath.length == 2) { InputStream inputStream = httpExchange.getRequestBody(); String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); Task task = gson.fromJson(body, Task.class); taskManager.createTask(task); - BaseHttpHandler.sendText(httpExchange, "Задача с id=" + task.getId() + " создана"); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); } else { BaseHttpHandler.sendNotFound(httpExchange); } @@ -126,7 +125,7 @@ public void handle(HttpExchange httpExchange) throws IOException { BaseHttpHandler.sendNotFound(httpExchange); } else { taskManager.deleteTask(task); - BaseHttpHandler.sendText(httpExchange, "Задача с id=" + task.getId() + " удалена"); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); } } else { BaseHttpHandler.sendNotFound(httpExchange); @@ -147,10 +146,7 @@ public void handle(HttpExchange httpExchange) throws IOException { switch (method) { case "GET" -> { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, "Получен список подзадач"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(taskManager.getSubtasks()).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getSubtasks())); return; } else if (partsOfPath.length == 3) { int id = Integer.parseInt(partsOfPath[2]); @@ -158,10 +154,7 @@ public void handle(HttpExchange httpExchange) throws IOException { if (task == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, "Подзадача с id=" + task.getId() + " найдена"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(task).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); } } else { BaseHttpHandler.sendNotFound(httpExchange); @@ -169,12 +162,12 @@ public void handle(HttpExchange httpExchange) throws IOException { httpExchange.close(); } case "POST" -> { - if (partsOfPath.length == 3) { + if (partsOfPath.length == 2) { InputStream inputStream = httpExchange.getRequestBody(); String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); Subtask task = gson.fromJson(body, Subtask.class); taskManager.createSubtask(task); - BaseHttpHandler.sendText(httpExchange, "Подзадача с id=" + task.getId() + " создана"); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); } else { BaseHttpHandler.sendNotFound(httpExchange); } @@ -187,8 +180,8 @@ public void handle(HttpExchange httpExchange) throws IOException { if (task == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - taskManager.deleteTask(task); - BaseHttpHandler.sendText(httpExchange, "Подзадача с id=" + task.getId() + " удалена"); + taskManager.deleteSubtask(task); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); } } else { BaseHttpHandler.sendNotFound(httpExchange); @@ -209,10 +202,7 @@ public void handle(HttpExchange httpExchange) throws IOException { switch (method) { case "GET" -> { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, "Получен список эпиков"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(taskManager.getEpics()).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpics())); return; } else if (partsOfPath.length == 3) { int id = Integer.parseInt(partsOfPath[2]); @@ -220,10 +210,7 @@ public void handle(HttpExchange httpExchange) throws IOException { if (epic == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " найден"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(epic).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic)); } } else if (partsOfPath.length == 4 && partsOfPath[3].equals("subtasks")) { int id = Integer.parseInt(partsOfPath[2]); @@ -231,10 +218,7 @@ public void handle(HttpExchange httpExchange) throws IOException { if (epic == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " найден"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(taskManager.getEpicsSubtasks(id)).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpicsSubtasks(id))); } } else { BaseHttpHandler.sendNotFound(httpExchange); @@ -242,12 +226,12 @@ public void handle(HttpExchange httpExchange) throws IOException { httpExchange.close(); } case "POST" -> { - if (partsOfPath.length == 3) { + if (partsOfPath.length == 2) { InputStream inputStream = httpExchange.getRequestBody(); String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); Epic epic = gson.fromJson(body, Epic.class); taskManager.createEpic(epic); - BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " создан"); + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic)); } else { BaseHttpHandler.sendNotFound(httpExchange); } @@ -261,7 +245,7 @@ public void handle(HttpExchange httpExchange) throws IOException { BaseHttpHandler.sendNotFound(httpExchange); } else { taskManager.deleteEpic(epic); - BaseHttpHandler.sendText(httpExchange, "Эпик с id=" + epic.getId() + " удален"); + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic)); } } else { BaseHttpHandler.sendNotFound(httpExchange); @@ -281,10 +265,7 @@ public void handle(HttpExchange httpExchange) throws IOException { String[] partsOfPath = path.split("/"); if (method.equals("GET")) { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, "Получена история просмотра задач"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(taskManager.getHistory()).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getHistory())); return; } else { BaseHttpHandler.sendNotFound(httpExchange); @@ -304,10 +285,7 @@ public void handle(HttpExchange httpExchange) throws IOException { String[] partsOfPath = path.split("/"); if (method.equals("GET")) { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, "Получен отсортированный список задач"); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(gson.toJson(taskManager.getPrioritizedTasks()).getBytes()); - } + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getPrioritizedTasks())); return; } else { BaseHttpHandler.sendNotFound(httpExchange); diff --git a/test/tracker/HttpTaskManagerTasksTest.java b/test/tracker/HttpTaskManagerTasksTest.java index 9a3c9b9..20c549a 100644 --- a/test/tracker/HttpTaskManagerTasksTest.java +++ b/test/tracker/HttpTaskManagerTasksTest.java @@ -1,12 +1,14 @@ package tracker; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.AfterEach; import tracker.controllers.InMemoryTaskManager; import tracker.controllers.TaskManager; import tracker.model.Epic; +import tracker.model.LocalDateAdapter; import tracker.model.Subtask; import tracker.model.Task; import tracker.server.HttpTaskServer; @@ -25,7 +27,10 @@ public class HttpTaskManagerTasksTest { TaskManager taskManager = new InMemoryTaskManager(); HttpTaskServer taskServer = new HttpTaskServer(8080, taskManager); - private static final Gson gson = new Gson(); + private static final Gson gson = new GsonBuilder() + .serializeNulls() + .registerTypeAdapter(LocalDateTime.class, new LocalDateAdapter()) + .create(); final long MINUTES_IN_DAY = 60 * 24; final LocalDateTime TASK_START_TIME = LocalDateTime.now(); @@ -41,9 +46,9 @@ public void shutDown() { @Test public void testTasks() throws IOException, InterruptedException { - Task task1 = new Task("Task 1", "Do task 1", taskManager.getTaskId(), MINUTES_IN_DAY, + Task task1 = new Task("Task 1", "Do task 1", 1, MINUTES_IN_DAY, TASK_START_TIME.minusDays(4)); - Task task2 = new Task("Task 2", "Do task 2", taskManager.getTaskId(), MINUTES_IN_DAY, + Task task2 = new Task("Task 2", "Do task 2", 2, MINUTES_IN_DAY, TASK_START_TIME.minusDays(3)); String task1Json = gson.toJson(task1); @@ -77,17 +82,18 @@ public void testTasks() throws IOException, InterruptedException { assertEquals("Task 2", tasksFromManager.get(1).getName(), "Некорректное имя задачи"); // 3. удаляем 1 задачу - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE().build(); + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/1")).DELETE() + .build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); tasksFromManager = taskManager.getTasks(); assertNotNull(tasksFromManager, "Список задач пуст"); assertEquals(1, tasksFromManager.size(), "Некорректное количество задач"); - assertEquals("Task 2", tasksFromManager.get(1).getName(), "Некорректное имя задачи"); + assertEquals("Task 2", tasksFromManager.get(0).getName(), "Некорректное имя задачи"); // 4. удаляем 2 задачу - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/" + task1.getId())).DELETE() + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/tasks/2")).DELETE() .build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); @@ -98,14 +104,14 @@ public void testTasks() throws IOException, InterruptedException { @Test public void checkEpicsAndSubtasks() throws IOException, InterruptedException { - Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", taskManager.getTaskId()); - Epic epic2 = new Epic("Epic 2", "Do all subtasks from epic 2", taskManager.getTaskId()); - Subtask subtask1 = new Subtask("Subtask 1", "Do subtask 1", taskManager.getTaskId(), epic1, - MINUTES_IN_DAY, TASK_START_TIME.minusDays(2)); - Subtask subtask2 = new Subtask("Subtask 2", "Do subtask 2", taskManager.getTaskId(), epic1, - MINUTES_IN_DAY, TASK_START_TIME.minusDays(1)); - Subtask subtask3 = new Subtask("Subtask 3", "Do subtask 3", taskManager.getTaskId(), epic2, - MINUTES_IN_DAY, TASK_START_TIME); + Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", 1); + Epic epic2 = new Epic("Epic 2", "Do all subtasks from epic 2", 2); + Subtask subtask1 = new Subtask("Subtask 1", "Do subtask 1", 3, epic1, MINUTES_IN_DAY, + TASK_START_TIME.minusDays(2)); + Subtask subtask2 = new Subtask("Subtask 2", "Do subtask 2", 4, epic1, MINUTES_IN_DAY, + TASK_START_TIME.minusDays(1)); + Subtask subtask3 = new Subtask("Subtask 3", "Do subtask 3", 5, epic2, MINUTES_IN_DAY, + TASK_START_TIME); String epic1Json = gson.toJson(epic1); String epic2Json = gson.toJson(epic2); @@ -136,7 +142,8 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { assertEquals("Epic 2", epicsFromManager.get(1).getName(), "Некорректное имя эпика"); // 2. Создаем подзадачи - HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask1Json)).build(); + request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask1Json)) + .build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); @@ -159,17 +166,17 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { assertEquals("Subtask 3", subtasksFromManager.get(2).getName(), "Некорректное имя подзадачи"); // 3. удаляем подзадачи - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask1.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/3")) .DELETE().build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask2.getId())) - .DELETE().build(); + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/4")) + .DELETE().build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/" + subtask3.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/subtasks/5")) .DELETE().build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); @@ -178,12 +185,12 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { assertEquals(0, subtasksFromManager.size(), "Некорректное количество задач"); // 4. удаляем эпики - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic1.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/1")) .DELETE().build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); - request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/" + epic2.getId())) + request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/epics/2")) .DELETE().build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); From d0e918ae88e73e3fa243eba6f80e9a58769e1cd0 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Mon, 4 Aug 2025 00:45:55 +0300 Subject: [PATCH 4/8] =?UTF-8?q?feature:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=209=D0=B3=D0=BE=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Main.java | 2 +- .../controllers/FileBackedTaskManager.java | 10 +-- .../controllers/InMemoryTaskManager.java | 12 ++- src/tracker/controllers/TaskManager.java | 8 +- src/tracker/server/BaseHttpHandler.java | 9 ++- src/tracker/server/HttpTaskServer.java | 75 +++++++++++-------- test/tracker/HttpTaskManagerTasksTest.java | 34 ++++++--- .../FileBackedTaskManagerTest.java | 4 +- .../InMemoryHistoryManagerTest.java | 2 +- test/tracker/controllers/TaskManagerTest.java | 6 +- test/tracker/model/SubtaskTest.java | 2 +- test/tracker/model/TaskTest.java | 2 +- 12 files changed, 98 insertions(+), 68 deletions(-) diff --git a/src/Main.java b/src/Main.java index a17bfa5..b3a2f0a 100644 --- a/src/Main.java +++ b/src/Main.java @@ -9,7 +9,7 @@ public class Main { - public static void main(String[] args) { + public static void main(String[] args) throws InterruptedException { final long MINUTES_IN_DAY = 60 * 24; final LocalDateTime TASK_START_TIME = LocalDateTime.now(); System.out.println("Поехали!"); diff --git a/src/tracker/controllers/FileBackedTaskManager.java b/src/tracker/controllers/FileBackedTaskManager.java index f4a8e7d..526f236 100644 --- a/src/tracker/controllers/FileBackedTaskManager.java +++ b/src/tracker/controllers/FileBackedTaskManager.java @@ -77,19 +77,19 @@ public static void main(String[] args) { System.out.println(fileBackedTasksManagerRestored.getHistory()); - } catch (IOException e) { + } catch (IOException | InterruptedException e) { System.out.println("Ошибка создания файла"); } } @Override - public void createTask(Task task) { + public void createTask(Task task) throws InterruptedException { super.createTask(task); save(); } @Override - public void createSubtask(Subtask subtask) { + public void createSubtask(Subtask subtask) throws InterruptedException { super.createSubtask(subtask); save(); } @@ -101,13 +101,13 @@ public void createEpic(Epic task) { } @Override - public void updateTask(Task task) { + public void updateTask(Task task) throws InterruptedException { super.updateTask(task); save(); } @Override - public void updateSubtask(Subtask task) { + public void updateSubtask(Subtask task) throws InterruptedException { super.updateSubtask(task); save(); } diff --git a/src/tracker/controllers/InMemoryTaskManager.java b/src/tracker/controllers/InMemoryTaskManager.java index 4c6e9c5..e5ee3b9 100644 --- a/src/tracker/controllers/InMemoryTaskManager.java +++ b/src/tracker/controllers/InMemoryTaskManager.java @@ -133,18 +133,19 @@ public ArrayList getEpicsSubtasks(int epicId) { // Создание. Сам объект должен передаваться в качестве параметра. @Override - public void createTask(Task task) { + public void createTask(Task task) throws InterruptedException { if (noIntersectionWithTasks(task)) { tasks.put(taskId, task); sortedTasks.add(task); taskId++; } else { System.out.println("Пересечение с текущими задачами"); + throw new InterruptedException(); } } @Override - public void createSubtask(Subtask task) { + public void createSubtask(Subtask task) throws InterruptedException { if (noIntersectionWithTasks(task)) { subtasks.put(taskId, task); sortedTasks.add(task); @@ -153,6 +154,7 @@ public void createSubtask(Subtask task) { taskId++; } else { System.out.println("Пересечение с текущими задачами."); + throw new InterruptedException(); } } @@ -164,7 +166,7 @@ public void createEpic(Epic task) { // Обновление. Новая версия объекта с верным идентификатором передаётся в виде параметра. @Override - public void updateTask(Task task) { + public void updateTask(Task task) throws InterruptedException { Task updatedTask = tasks.get(task.getId()); if (updatedTask == null) { System.out.println("Задача с id = " + task.getId() + " не найдена"); @@ -175,11 +177,12 @@ public void updateTask(Task task) { sortedTasks.add(task); } else { System.out.println("Пересечение с текущими задачами"); + throw new InterruptedException(); } } @Override - public void updateSubtask(Subtask task) { + public void updateSubtask(Subtask task) throws InterruptedException { Subtask updatedTask = subtasks.get(task.getId()); if (updatedTask == null) { System.out.println("Задача с id = " + task.getId() + " не найдена"); @@ -192,6 +195,7 @@ public void updateSubtask(Subtask task) { updateEpicEndTimeAndDuration(task.getEpic()); } else { System.out.println("Пересечение с текущими задачами"); + throw new InterruptedException(); } } diff --git a/src/tracker/controllers/TaskManager.java b/src/tracker/controllers/TaskManager.java index 71bfd44..34c5535 100644 --- a/src/tracker/controllers/TaskManager.java +++ b/src/tracker/controllers/TaskManager.java @@ -36,16 +36,16 @@ public interface TaskManager { ArrayList getEpicsSubtasks(int epicId); // Создание. Сам объект должен передаваться в качестве параметра. - void createTask(Task task); + void createTask(Task task) throws InterruptedException; - void createSubtask(Subtask task); + void createSubtask(Subtask task) throws InterruptedException; void createEpic(Epic task); // Обновление. Новая версия объекта с верным идентификатором передаётся в виде параметра. - void updateTask(Task task); + void updateTask(Task task) throws InterruptedException; - void updateSubtask(Subtask task); + void updateSubtask(Subtask task) throws InterruptedException; void updateEpicStatus(Epic epic); diff --git a/src/tracker/server/BaseHttpHandler.java b/src/tracker/server/BaseHttpHandler.java index c268bde..8d9cbd1 100644 --- a/src/tracker/server/BaseHttpHandler.java +++ b/src/tracker/server/BaseHttpHandler.java @@ -6,10 +6,10 @@ import java.nio.charset.StandardCharsets; public class BaseHttpHandler { - public static void sendText(HttpExchange httpExchange, String text) throws IOException { + public static void sendText(HttpExchange httpExchange, String text, int code) throws IOException { byte[] response = text.getBytes(StandardCharsets.UTF_8); httpExchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8"); - httpExchange.sendResponseHeaders(200, response.length); + httpExchange.sendResponseHeaders(code, response.length); httpExchange.getResponseBody().write(response); httpExchange.close(); } @@ -23,4 +23,9 @@ public static void sendHasOverlaps(HttpExchange httpExchange) throws IOException httpExchange.sendResponseHeaders(406, 0); httpExchange.close(); } + + public static void sendServerError(HttpExchange httpExchange) throws IOException { + httpExchange.sendResponseHeaders(500, 0); + httpExchange.close(); + } } diff --git a/src/tracker/server/HttpTaskServer.java b/src/tracker/server/HttpTaskServer.java index 2da0705..206d73b 100644 --- a/src/tracker/server/HttpTaskServer.java +++ b/src/tracker/server/HttpTaskServer.java @@ -35,7 +35,7 @@ public HttpTaskServer(int port, TaskManager taskManager) { .create(); } - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws IOException, InterruptedException { final long MINUTES_IN_DAY = 60 * 24; final LocalDateTime TASK_START_TIME = LocalDateTime.now(); TaskManager inMemoryTaskManager = Managers.getDefault(); @@ -90,7 +90,7 @@ public void handle(HttpExchange httpExchange) throws IOException { switch (method) { case "GET" -> { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getTasks())); + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getTasks()), 200); return; } else if (partsOfPath.length == 3) { int id = Integer.parseInt(partsOfPath[2]); @@ -98,10 +98,10 @@ public void handle(HttpExchange httpExchange) throws IOException { if (task == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); } } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } @@ -110,10 +110,14 @@ public void handle(HttpExchange httpExchange) throws IOException { InputStream inputStream = httpExchange.getRequestBody(); String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); Task task = gson.fromJson(body, Task.class); - taskManager.createTask(task); - BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); + try { + taskManager.createTask(task); + } catch (InterruptedException e) { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 201); } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } @@ -125,10 +129,10 @@ public void handle(HttpExchange httpExchange) throws IOException { BaseHttpHandler.sendNotFound(httpExchange); } else { taskManager.deleteTask(task); - BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); } } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } @@ -146,7 +150,7 @@ public void handle(HttpExchange httpExchange) throws IOException { switch (method) { case "GET" -> { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getSubtasks())); + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getSubtasks()), 200); return; } else if (partsOfPath.length == 3) { int id = Integer.parseInt(partsOfPath[2]); @@ -154,10 +158,10 @@ public void handle(HttpExchange httpExchange) throws IOException { if (task == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); } } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } @@ -166,10 +170,14 @@ public void handle(HttpExchange httpExchange) throws IOException { InputStream inputStream = httpExchange.getRequestBody(); String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); Subtask task = gson.fromJson(body, Subtask.class); - taskManager.createSubtask(task); - BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); + try { + taskManager.createSubtask(task); + } catch (InterruptedException e) { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 201); } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendHasOverlaps(httpExchange); } httpExchange.close(); } @@ -181,14 +189,14 @@ public void handle(HttpExchange httpExchange) throws IOException { BaseHttpHandler.sendNotFound(httpExchange); } else { taskManager.deleteSubtask(task); - BaseHttpHandler.sendText(httpExchange, gson.toJson(task)); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); } } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } - default -> BaseHttpHandler.sendNotFound(httpExchange); + default -> BaseHttpHandler.sendServerError(httpExchange); } } } @@ -202,7 +210,7 @@ public void handle(HttpExchange httpExchange) throws IOException { switch (method) { case "GET" -> { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpics())); + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpics()), 200); return; } else if (partsOfPath.length == 3) { int id = Integer.parseInt(partsOfPath[2]); @@ -210,7 +218,7 @@ public void handle(HttpExchange httpExchange) throws IOException { if (epic == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(epic)); + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 200); } } else if (partsOfPath.length == 4 && partsOfPath[3].equals("subtasks")) { int id = Integer.parseInt(partsOfPath[2]); @@ -218,10 +226,11 @@ public void handle(HttpExchange httpExchange) throws IOException { if (epic == null) { BaseHttpHandler.sendNotFound(httpExchange); } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpicsSubtasks(id))); + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpicsSubtasks(id)), + 200); } } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } @@ -231,9 +240,9 @@ public void handle(HttpExchange httpExchange) throws IOException { String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); Epic epic = gson.fromJson(body, Epic.class); taskManager.createEpic(epic); - BaseHttpHandler.sendText(httpExchange, gson.toJson(epic)); + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 201); } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } @@ -245,14 +254,14 @@ public void handle(HttpExchange httpExchange) throws IOException { BaseHttpHandler.sendNotFound(httpExchange); } else { taskManager.deleteEpic(epic); - BaseHttpHandler.sendText(httpExchange, gson.toJson(epic)); + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 200); } } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } - default -> BaseHttpHandler.sendNotFound(httpExchange); + default -> BaseHttpHandler.sendServerError(httpExchange); } } } @@ -265,14 +274,14 @@ public void handle(HttpExchange httpExchange) throws IOException { String[] partsOfPath = path.split("/"); if (method.equals("GET")) { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getHistory())); + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getHistory()), 200); return; } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } } } @@ -285,14 +294,14 @@ public void handle(HttpExchange httpExchange) throws IOException { String[] partsOfPath = path.split("/"); if (method.equals("GET")) { if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getPrioritizedTasks())); + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getPrioritizedTasks()), 200); return; } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } httpExchange.close(); } else { - BaseHttpHandler.sendNotFound(httpExchange); + BaseHttpHandler.sendServerError(httpExchange); } } } diff --git a/test/tracker/HttpTaskManagerTasksTest.java b/test/tracker/HttpTaskManagerTasksTest.java index 20c549a..2f929dd 100644 --- a/test/tracker/HttpTaskManagerTasksTest.java +++ b/test/tracker/HttpTaskManagerTasksTest.java @@ -49,7 +49,7 @@ public void testTasks() throws IOException, InterruptedException { Task task1 = new Task("Task 1", "Do task 1", 1, MINUTES_IN_DAY, TASK_START_TIME.minusDays(4)); Task task2 = new Task("Task 2", "Do task 2", 2, MINUTES_IN_DAY, - TASK_START_TIME.minusDays(3)); + TASK_START_TIME.minusDays(4)); String task1Json = gson.toJson(task1); String task2Json = gson.toJson(task2); @@ -58,12 +58,11 @@ public void testTasks() throws IOException, InterruptedException { HttpResponse response; HttpRequest request; + // 1. создаем 1 задачу HttpClient client = HttpClient.newHttpClient(); request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task1Json)).build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); - - // 1. создаем 1 задачу + assertEquals(201, response.statusCode()); List tasksFromManager = taskManager.getTasks(); assertNotNull(tasksFromManager, "Список задач пуст"); @@ -73,7 +72,13 @@ public void testTasks() throws IOException, InterruptedException { // 2. создаем 2 задачу request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task2Json)).build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + assertEquals(406, response.statusCode()); + + task2.setStartTime(TASK_START_TIME.minusDays(3)); + task2Json = gson.toJson(task2); + request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task2Json)).build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode()); tasksFromManager = taskManager.getTasks(); assertNotNull(tasksFromManager, "Список задач пуст"); @@ -111,7 +116,7 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { Subtask subtask2 = new Subtask("Subtask 2", "Do subtask 2", 4, epic1, MINUTES_IN_DAY, TASK_START_TIME.minusDays(1)); Subtask subtask3 = new Subtask("Subtask 3", "Do subtask 3", 5, epic2, MINUTES_IN_DAY, - TASK_START_TIME); + TASK_START_TIME.minusDays(1)); String epic1Json = gson.toJson(epic1); String epic2Json = gson.toJson(epic2); @@ -128,11 +133,11 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { HttpClient client = HttpClient.newHttpClient(); request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers.ofString(epic1Json)).build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + assertEquals(201, response.statusCode()); request = HttpRequest.newBuilder().uri(urlEpics).POST(HttpRequest.BodyPublishers.ofString(epic2Json)).build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + assertEquals(201, response.statusCode()); List epicsFromManager = taskManager.getEpics(); @@ -145,17 +150,24 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask1Json)) .build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + assertEquals(201, response.statusCode()); request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask2Json)). build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + assertEquals(201, response.statusCode()); request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask3Json)) .build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); - assertEquals(200, response.statusCode()); + assertEquals(406, response.statusCode()); + + subtask3.setStartTime(TASK_START_TIME); + subtask3Json = gson.toJson(subtask3); + request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask3Json)) + .build(); + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(201, response.statusCode()); List subtasksFromManager = taskManager.getSubtasks(); diff --git a/test/tracker/controllers/FileBackedTaskManagerTest.java b/test/tracker/controllers/FileBackedTaskManagerTest.java index 63e270a..317a05a 100644 --- a/test/tracker/controllers/FileBackedTaskManagerTest.java +++ b/test/tracker/controllers/FileBackedTaskManagerTest.java @@ -31,7 +31,7 @@ void initializeTask() { @Override @Test - void checkEpic() { + void checkEpic() throws InterruptedException { super.checkEpic(); } @@ -44,7 +44,7 @@ void checkImportFromEmptyFile() { } @Test - void checkImportFromFile() { + void checkImportFromFile() throws InterruptedException { Task task1 = new Task("task 1", "task 1", 1, Status.NEW, MINUTES_IN_DAY, TASK_START_TIME.minusDays(4)); Task task2 = new Task("task 2", "task 2", 2, Status.NEW, MINUTES_IN_DAY, diff --git a/test/tracker/controllers/InMemoryHistoryManagerTest.java b/test/tracker/controllers/InMemoryHistoryManagerTest.java index 1e883d4..7e5d3e4 100644 --- a/test/tracker/controllers/InMemoryHistoryManagerTest.java +++ b/test/tracker/controllers/InMemoryHistoryManagerTest.java @@ -20,7 +20,7 @@ void initializeTask() { taskManager = Managers.getDefault(); } @Test - void checkInMemoryHistoryManager() { + void checkInMemoryHistoryManager() throws InterruptedException { Task task1 = new Task("Task 1", "Do task 1", taskManager.getTaskId(), MINUTES_IN_DAY, TASK_START_TIME.minusDays(4)); taskManager.createTask(task1); diff --git a/test/tracker/controllers/TaskManagerTest.java b/test/tracker/controllers/TaskManagerTest.java index 1db1a53..8145637 100644 --- a/test/tracker/controllers/TaskManagerTest.java +++ b/test/tracker/controllers/TaskManagerTest.java @@ -17,7 +17,7 @@ abstract class TaskManagerTest { final LocalDateTime TASK_START_TIME = LocalDateTime.now(); @Test - void checkEpic() { + void checkEpic() throws InterruptedException { Task task1 = new Task("Task 1", "Do task 1", taskManager.getTaskId(), MINUTES_IN_DAY, TASK_START_TIME.minusDays(4)); taskManager.createTask(task1); @@ -48,7 +48,7 @@ void checkEpic() { } @Test - void checkEpicStatus() { + void checkEpicStatus() throws InterruptedException { // Все подзадачи со статусом NEW. Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", taskManager.getTaskId()); taskManager.createEpic(epic1); @@ -88,7 +88,7 @@ void checkEpicStatus() { } @Test - void checkTaskIntersection() { + void checkTaskIntersection() throws InterruptedException { // При наличии пересечения по времени выполнения задача не будет создана Task task1 = new Task("Task 1", "Do task 1", taskManager.getTaskId(), MINUTES_IN_DAY, TASK_START_TIME); diff --git a/test/tracker/model/SubtaskTest.java b/test/tracker/model/SubtaskTest.java index eb685ba..89a8f2f 100644 --- a/test/tracker/model/SubtaskTest.java +++ b/test/tracker/model/SubtaskTest.java @@ -20,7 +20,7 @@ void initializeTask() { } @Test - void checkSubtask() { + void checkSubtask() throws InterruptedException { Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", inMemoryTaskManager.getTaskId()); inMemoryTaskManager.createEpic(epic1); diff --git a/test/tracker/model/TaskTest.java b/test/tracker/model/TaskTest.java index 103526d..0177174 100644 --- a/test/tracker/model/TaskTest.java +++ b/test/tracker/model/TaskTest.java @@ -16,7 +16,7 @@ void initializeTask() { } @Test - void checkTask() { + void checkTask() throws InterruptedException { Task task1 = new Task("Task 1", "Do task 1", 1); inMemoryTaskManager.createTask(task1); Task task2 = new Task("Task 2", "Do task 2", 1); From fcf27b64e57b09663b2a061013db8190adc997c9 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Mon, 4 Aug 2025 00:49:33 +0300 Subject: [PATCH 5/8] =?UTF-8?q?feature:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=209=D0=B3=D0=BE=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/tracker/controllers/TaskManagerTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/tracker/controllers/TaskManagerTest.java b/test/tracker/controllers/TaskManagerTest.java index 8145637..d4fff28 100644 --- a/test/tracker/controllers/TaskManagerTest.java +++ b/test/tracker/controllers/TaskManagerTest.java @@ -95,10 +95,13 @@ void checkTaskIntersection() throws InterruptedException { taskManager.createTask(task1); Task task2 = new Task("Task 2", "Do task 2", taskManager.getTaskId(), MINUTES_IN_DAY, TASK_START_TIME); - taskManager.createTask(task2); - assertEquals(1, taskManager.getTaskById(task1.getId()).getId(), "Неверный Id"); - assertEquals(1, taskManager.getTasks().size(), "Неверное количество задач"); - task2.setStartTime(TASK_START_TIME.plusDays(1)); + try { + taskManager.createTask(task2); + } catch (InterruptedException e) { + assertEquals(1, taskManager.getTaskById(task1.getId()).getId(), "Неверный Id"); + assertEquals(1, taskManager.getTasks().size(), "Неверное количество задач"); + task2.setStartTime(TASK_START_TIME.plusDays(1)); + } taskManager.createTask(task2); assertEquals(2, taskManager.getTaskById(task2.getId()).getId(), "Неверный Id"); } From 39e81fe0010e2b60d6bb7c4bcb3ffbd4e3f956bc Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Thu, 7 Aug 2025 00:38:03 +0300 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{model => adapter}/LocalDateAdapter.java | 4 +- .../controllers/FileBackedTaskManager.java | 10 +- .../controllers/InMemoryTaskManager.java | 71 ++--- src/tracker/controllers/TaskManager.java | 8 +- src/tracker/exceptions/OverlapsException.java | 7 + .../{server => handler}/BaseHttpHandler.java | 17 +- src/tracker/handler/EpicsHandler.java | 82 ++++++ src/tracker/handler/HistoryHandler.java | 31 +++ src/tracker/handler/PrioritizedHandler.java | 31 +++ src/tracker/handler/SubtasksHandler.java | 93 +++++++ src/tracker/handler/TasksHandler.java | 88 ++++++ src/tracker/server/HttpTaskServer.java | 262 +----------------- test/tracker/HttpTaskManagerTasksTest.java | 70 ++--- test/tracker/controllers/TaskManagerTest.java | 7 +- 14 files changed, 443 insertions(+), 338 deletions(-) rename src/tracker/{model => adapter}/LocalDateAdapter.java (90%) create mode 100644 src/tracker/exceptions/OverlapsException.java rename src/tracker/{server => handler}/BaseHttpHandler.java (67%) create mode 100644 src/tracker/handler/EpicsHandler.java create mode 100644 src/tracker/handler/HistoryHandler.java create mode 100644 src/tracker/handler/PrioritizedHandler.java create mode 100644 src/tracker/handler/SubtasksHandler.java create mode 100644 src/tracker/handler/TasksHandler.java diff --git a/src/tracker/model/LocalDateAdapter.java b/src/tracker/adapter/LocalDateAdapter.java similarity index 90% rename from src/tracker/model/LocalDateAdapter.java rename to src/tracker/adapter/LocalDateAdapter.java index 9964f2a..976e3a5 100644 --- a/src/tracker/model/LocalDateAdapter.java +++ b/src/tracker/adapter/LocalDateAdapter.java @@ -1,4 +1,4 @@ -package tracker.model; +package tracker.adapter; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; @@ -9,7 +9,7 @@ import java.time.format.DateTimeFormatter; public class LocalDateAdapter extends TypeAdapter { - private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS"); + private static final DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE_TIME; @Override public void write(final JsonWriter jsonWriter, final LocalDateTime localDate) throws IOException { diff --git a/src/tracker/controllers/FileBackedTaskManager.java b/src/tracker/controllers/FileBackedTaskManager.java index 526f236..f4a8e7d 100644 --- a/src/tracker/controllers/FileBackedTaskManager.java +++ b/src/tracker/controllers/FileBackedTaskManager.java @@ -77,19 +77,19 @@ public static void main(String[] args) { System.out.println(fileBackedTasksManagerRestored.getHistory()); - } catch (IOException | InterruptedException e) { + } catch (IOException e) { System.out.println("Ошибка создания файла"); } } @Override - public void createTask(Task task) throws InterruptedException { + public void createTask(Task task) { super.createTask(task); save(); } @Override - public void createSubtask(Subtask subtask) throws InterruptedException { + public void createSubtask(Subtask subtask) { super.createSubtask(subtask); save(); } @@ -101,13 +101,13 @@ public void createEpic(Epic task) { } @Override - public void updateTask(Task task) throws InterruptedException { + public void updateTask(Task task) { super.updateTask(task); save(); } @Override - public void updateSubtask(Subtask task) throws InterruptedException { + public void updateSubtask(Subtask task) { super.updateSubtask(task); save(); } diff --git a/src/tracker/controllers/InMemoryTaskManager.java b/src/tracker/controllers/InMemoryTaskManager.java index e5ee3b9..794aaf3 100644 --- a/src/tracker/controllers/InMemoryTaskManager.java +++ b/src/tracker/controllers/InMemoryTaskManager.java @@ -1,5 +1,6 @@ package tracker.controllers; +import tracker.exceptions.OverlapsException; import tracker.model.Epic; import tracker.model.Status; import tracker.model.Subtask; @@ -133,29 +134,21 @@ public ArrayList getEpicsSubtasks(int epicId) { // Создание. Сам объект должен передаваться в качестве параметра. @Override - public void createTask(Task task) throws InterruptedException { - if (noIntersectionWithTasks(task)) { - tasks.put(taskId, task); - sortedTasks.add(task); - taskId++; - } else { - System.out.println("Пересечение с текущими задачами"); - throw new InterruptedException(); - } + public void createTask(Task task) { + hasIntersectionWithTasks(task); + tasks.put(taskId, task); + sortedTasks.add(task); + taskId++; } @Override - public void createSubtask(Subtask task) throws InterruptedException { - if (noIntersectionWithTasks(task)) { - subtasks.put(taskId, task); - sortedTasks.add(task); - updateEpicStatus(task.getEpic()); - updateEpicEndTimeAndDuration(task.getEpic()); - taskId++; - } else { - System.out.println("Пересечение с текущими задачами."); - throw new InterruptedException(); - } + public void createSubtask(Subtask task) { + hasIntersectionWithTasks(task); + subtasks.put(taskId, task); + sortedTasks.add(task); + updateEpicStatus(task.getEpic()); + updateEpicEndTimeAndDuration(task.getEpic()); + taskId++; } @Override @@ -166,37 +159,29 @@ public void createEpic(Epic task) { // Обновление. Новая версия объекта с верным идентификатором передаётся в виде параметра. @Override - public void updateTask(Task task) throws InterruptedException { + public void updateTask(Task task) { Task updatedTask = tasks.get(task.getId()); if (updatedTask == null) { System.out.println("Задача с id = " + task.getId() + " не найдена"); } - if (noIntersectionWithTasks(task)) { - sortedTasks.remove(updatedTask); - tasks.put(task.getId(), task); - sortedTasks.add(task); - } else { - System.out.println("Пересечение с текущими задачами"); - throw new InterruptedException(); - } + hasIntersectionWithTasks(task); + sortedTasks.remove(updatedTask); + tasks.put(task.getId(), task); + sortedTasks.add(task); } @Override - public void updateSubtask(Subtask task) throws InterruptedException { + public void updateSubtask(Subtask task) { Subtask updatedTask = subtasks.get(task.getId()); if (updatedTask == null) { System.out.println("Задача с id = " + task.getId() + " не найдена"); } - if (noIntersectionWithTasks(task)) { - sortedTasks.remove(updatedTask); - subtasks.put(task.getId(), task); - sortedTasks.add(task); - updateEpicStatus(task.getEpic()); - updateEpicEndTimeAndDuration(task.getEpic()); - } else { - System.out.println("Пересечение с текущими задачами"); - throw new InterruptedException(); - } + hasIntersectionWithTasks(task); + sortedTasks.remove(updatedTask); + subtasks.put(task.getId(), task); + sortedTasks.add(task); + updateEpicStatus(task.getEpic()); + updateEpicEndTimeAndDuration(task.getEpic()); } @Override @@ -307,12 +292,14 @@ private boolean intersectionChecked(T task1, T task2) { && (endTime1.isAfter(endTime2) || endTime1.isEqual(endTime2)); } - private boolean noIntersectionWithTasks(T task) { + private void hasIntersectionWithTasks(T task) { List intersectedTasks = sortedTasks.stream() .filter(currentTask -> !currentTask.equals(task)) .filter(currentTask -> intersectionChecked(task, currentTask)) .toList(); - return intersectedTasks.isEmpty(); + if (!intersectedTasks.isEmpty()) { + throw new OverlapsException("Есть пересечение с текущими задачами"); + } } } diff --git a/src/tracker/controllers/TaskManager.java b/src/tracker/controllers/TaskManager.java index 34c5535..71bfd44 100644 --- a/src/tracker/controllers/TaskManager.java +++ b/src/tracker/controllers/TaskManager.java @@ -36,16 +36,16 @@ public interface TaskManager { ArrayList getEpicsSubtasks(int epicId); // Создание. Сам объект должен передаваться в качестве параметра. - void createTask(Task task) throws InterruptedException; + void createTask(Task task); - void createSubtask(Subtask task) throws InterruptedException; + void createSubtask(Subtask task); void createEpic(Epic task); // Обновление. Новая версия объекта с верным идентификатором передаётся в виде параметра. - void updateTask(Task task) throws InterruptedException; + void updateTask(Task task); - void updateSubtask(Subtask task) throws InterruptedException; + void updateSubtask(Subtask task); void updateEpicStatus(Epic epic); diff --git a/src/tracker/exceptions/OverlapsException.java b/src/tracker/exceptions/OverlapsException.java new file mode 100644 index 0000000..887d7a0 --- /dev/null +++ b/src/tracker/exceptions/OverlapsException.java @@ -0,0 +1,7 @@ +package tracker.exceptions; + +public class OverlapsException extends RuntimeException { + public OverlapsException(final String message) { + super(message); + } +} diff --git a/src/tracker/server/BaseHttpHandler.java b/src/tracker/handler/BaseHttpHandler.java similarity index 67% rename from src/tracker/server/BaseHttpHandler.java rename to src/tracker/handler/BaseHttpHandler.java index 8d9cbd1..6614991 100644 --- a/src/tracker/server/BaseHttpHandler.java +++ b/src/tracker/handler/BaseHttpHandler.java @@ -1,11 +1,24 @@ -package tracker.server; +package tracker.handler; +import com.google.gson.Gson; import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import tracker.controllers.TaskManager; import java.io.IOException; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -public class BaseHttpHandler { +public abstract class BaseHttpHandler implements HttpHandler { + protected final Gson gson; + protected final TaskManager taskManager; + protected final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + + public BaseHttpHandler(Gson gson, TaskManager taskManager) { + this.gson = gson; + this.taskManager = taskManager; + } + public static void sendText(HttpExchange httpExchange, String text, int code) throws IOException { byte[] response = text.getBytes(StandardCharsets.UTF_8); httpExchange.getResponseHeaders().add("Content-Type", "application/json;charset=utf-8"); diff --git a/src/tracker/handler/EpicsHandler.java b/src/tracker/handler/EpicsHandler.java new file mode 100644 index 0000000..7df3b30 --- /dev/null +++ b/src/tracker/handler/EpicsHandler.java @@ -0,0 +1,82 @@ +package tracker.handler; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import tracker.controllers.TaskManager; +import tracker.model.Epic; + +import java.io.IOException; +import java.io.InputStream; + +public class EpicsHandler extends BaseHttpHandler{ + public EpicsHandler(Gson gson, TaskManager taskManager) { + super(gson, taskManager); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + switch (method) { + case "GET" -> { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpics()), 200); + return; + } else if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Epic epic = taskManager.getEpicById(id); + if (epic == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 200); + } + } else if (partsOfPath.length == 4 && partsOfPath[3].equals("subtasks")) { + int id = Integer.parseInt(partsOfPath[2]); + Epic epic = taskManager.getEpicById(id); + if (epic == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpicsSubtasks(id)), + 200); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + case "POST" -> { + if (partsOfPath.length == 2) { + InputStream inputStream = httpExchange.getRequestBody(); + String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + if (body.isEmpty()) { + BaseHttpHandler.sendServerError(httpExchange); + } else { + Epic epic = gson.fromJson(body, Epic.class); + taskManager.createEpic(epic); + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 201); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + case "DELETE" -> { + if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Epic epic = taskManager.getEpicById(id); + if (epic == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + taskManager.deleteEpic(epic); + BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 200); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + default -> BaseHttpHandler.sendServerError(httpExchange); + } + } +} diff --git a/src/tracker/handler/HistoryHandler.java b/src/tracker/handler/HistoryHandler.java new file mode 100644 index 0000000..f905b84 --- /dev/null +++ b/src/tracker/handler/HistoryHandler.java @@ -0,0 +1,31 @@ +package tracker.handler; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import tracker.controllers.TaskManager; + +import java.io.IOException; + +public class HistoryHandler extends BaseHttpHandler{ + public HistoryHandler(Gson gson, TaskManager taskManager) { + super(gson, taskManager); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + if (method.equals("GET")) { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getHistory()), 200); + return; + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + } +} diff --git a/src/tracker/handler/PrioritizedHandler.java b/src/tracker/handler/PrioritizedHandler.java new file mode 100644 index 0000000..51c1ad7 --- /dev/null +++ b/src/tracker/handler/PrioritizedHandler.java @@ -0,0 +1,31 @@ +package tracker.handler; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import tracker.controllers.TaskManager; + +import java.io.IOException; + +public class PrioritizedHandler extends BaseHttpHandler{ + public PrioritizedHandler(Gson gson, TaskManager taskManager) { + super(gson, taskManager); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + if (method.equals("GET")) { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getPrioritizedTasks()), 200); + return; + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + } +} diff --git a/src/tracker/handler/SubtasksHandler.java b/src/tracker/handler/SubtasksHandler.java new file mode 100644 index 0000000..9f1cff1 --- /dev/null +++ b/src/tracker/handler/SubtasksHandler.java @@ -0,0 +1,93 @@ +package tracker.handler; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import tracker.controllers.TaskManager; +import tracker.exceptions.OverlapsException; +import tracker.model.Subtask; + +import java.io.IOException; +import java.io.InputStream; + +public class SubtasksHandler extends BaseHttpHandler { + public SubtasksHandler(Gson gson, TaskManager taskManager) { + super(gson, taskManager); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + switch (method) { + case "GET" -> { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getSubtasks()), 200); + return; + } else if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Subtask task = taskManager.getSubtaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + case "POST" -> { + if (partsOfPath.length == 2) { + InputStream inputStream = httpExchange.getRequestBody(); + String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + Subtask task = gson.fromJson(body, Subtask.class); + if (body.isEmpty()) { + BaseHttpHandler.sendServerError(httpExchange); + } else { + if (task.getId() != 0) { + try { + taskManager.updateSubtask(task); + } catch (OverlapsException e) { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + } else { + try { + taskManager.createSubtask(new Subtask(task.getName(), task.getDescription(), + taskManager.getTaskId(), task.getStatus(), task.getEpic(), task.getDuration(), + task.getStartTime())); + } catch (OverlapsException e) { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + } + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 201); + } + try { + taskManager.createSubtask(task); + } catch (OverlapsException e) { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + } else { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + httpExchange.close(); + } + case "DELETE" -> { + if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Subtask task = taskManager.getSubtaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + taskManager.deleteSubtask(task); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + default -> BaseHttpHandler.sendServerError(httpExchange); + } + } +} diff --git a/src/tracker/handler/TasksHandler.java b/src/tracker/handler/TasksHandler.java new file mode 100644 index 0000000..9874851 --- /dev/null +++ b/src/tracker/handler/TasksHandler.java @@ -0,0 +1,88 @@ +package tracker.handler; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; +import tracker.controllers.TaskManager; +import tracker.exceptions.OverlapsException; +import tracker.model.Task; + +import java.io.IOException; +import java.io.InputStream; + +public class TasksHandler extends BaseHttpHandler { + public TasksHandler(Gson gson, TaskManager taskManager) { + super(gson, taskManager); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + String path = httpExchange.getRequestURI().getPath(); + String[] partsOfPath = path.split("/"); + switch (method) { + case "GET" -> { + if (partsOfPath.length == 2) { + BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getTasks()), 200); + return; + } else if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Task task = taskManager.getTaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + case "POST" -> { + if (partsOfPath.length == 2) { + InputStream inputStream = httpExchange.getRequestBody(); + String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + if (body.isEmpty()) { + BaseHttpHandler.sendServerError(httpExchange); + } else { + Task task = gson.fromJson(body, Task.class); + if (task.getId() != 0) { + try { + taskManager.updateTask(task); + } catch (OverlapsException e) { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + } else { + try { + taskManager.createTask(new Task(task.getName(), task.getDescription(), + taskManager.getTaskId(), task.getStatus(), task.getDuration(), + task.getStartTime())); + } catch (OverlapsException e) { + BaseHttpHandler.sendHasOverlaps(httpExchange); + } + } + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 201); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + case "DELETE" -> { + if (partsOfPath.length == 3) { + int id = Integer.parseInt(partsOfPath[2]); + Task task = taskManager.getTaskById(id); + if (task == null) { + BaseHttpHandler.sendNotFound(httpExchange); + } else { + taskManager.deleteTask(task); + BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); + } + } else { + BaseHttpHandler.sendServerError(httpExchange); + } + httpExchange.close(); + } + default -> BaseHttpHandler.sendNotFound(httpExchange); + } + } +} diff --git a/src/tracker/server/HttpTaskServer.java b/src/tracker/server/HttpTaskServer.java index 206d73b..1508e8e 100644 --- a/src/tracker/server/HttpTaskServer.java +++ b/src/tracker/server/HttpTaskServer.java @@ -1,41 +1,41 @@ package tracker.server; import com.google.gson.*; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import tracker.controllers.Managers; import tracker.controllers.TaskManager; +import tracker.handler.*; import tracker.model.Epic; -import tracker.model.LocalDateAdapter; +import tracker.adapter.LocalDateAdapter; import tracker.model.Subtask; import tracker.model.Task; import java.io.IOException; -import java.io.InputStream; import java.net.InetSocketAddress; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; public class HttpTaskServer { - private final int port; final TaskManager taskManager; - private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; - private static Gson gson; - private HttpServer httpServer; + private final HttpServer httpServer; - public HttpTaskServer(int port, TaskManager taskManager) { - this.port = port; + public HttpTaskServer(int port, TaskManager taskManager) throws IOException { this.taskManager = taskManager; - gson = new GsonBuilder() + Gson gson = new GsonBuilder() .serializeNulls() .registerTypeAdapter(LocalDateTime.class, new LocalDateAdapter()) .create(); + + httpServer = HttpServer.create(); + httpServer.bind(new InetSocketAddress(port), 0); + httpServer.createContext("/tasks", new TasksHandler(gson, taskManager)); + httpServer.createContext("/subtasks", new SubtasksHandler(gson, taskManager)); + httpServer.createContext("/epics", new EpicsHandler(gson, taskManager)); + httpServer.createContext("/history", new HistoryHandler(gson, taskManager)); + httpServer.createContext("/prioritized", new PrioritizedHandler(gson, taskManager)); } - public static void main(String[] args) throws IOException, InterruptedException { + public static void main(String[] args) throws IOException { final long MINUTES_IN_DAY = 60 * 24; final LocalDateTime TASK_START_TIME = LocalDateTime.now(); TaskManager inMemoryTaskManager = Managers.getDefault(); @@ -66,243 +66,11 @@ public static void main(String[] args) throws IOException, InterruptedException inMemoryTaskManager.createSubtask(subtask3); } - public void start() throws IOException { - httpServer = HttpServer.create(); - httpServer.bind(new InetSocketAddress(port), 0); - httpServer.createContext("/tasks", new TasksHandler()); - httpServer.createContext("/subtasks", new SubtasksHandler()); - httpServer.createContext("/epics", new EpicsHandler()); - httpServer.createContext("/history", new HistoryHandler()); - httpServer.createContext("/prioritized", new PrioritizedHandler()); + public void start() { httpServer.start(); } public void stop() { httpServer.stop(0); } - - class TasksHandler implements HttpHandler { - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String method = httpExchange.getRequestMethod(); - String path = httpExchange.getRequestURI().getPath(); - String[] partsOfPath = path.split("/"); - switch (method) { - case "GET" -> { - if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getTasks()), 200); - return; - } else if (partsOfPath.length == 3) { - int id = Integer.parseInt(partsOfPath[2]); - Task task = taskManager.getTaskById(id); - if (task == null) { - BaseHttpHandler.sendNotFound(httpExchange); - } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); - } - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - case "POST" -> { - if (partsOfPath.length == 2) { - InputStream inputStream = httpExchange.getRequestBody(); - String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); - Task task = gson.fromJson(body, Task.class); - try { - taskManager.createTask(task); - } catch (InterruptedException e) { - BaseHttpHandler.sendHasOverlaps(httpExchange); - } - BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 201); - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - case "DELETE" -> { - if (partsOfPath.length == 3) { - int id = Integer.parseInt(partsOfPath[2]); - Task task = taskManager.getTaskById(id); - if (task == null) { - BaseHttpHandler.sendNotFound(httpExchange); - } else { - taskManager.deleteTask(task); - BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); - } - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - default -> BaseHttpHandler.sendNotFound(httpExchange); - } - } - } - - class SubtasksHandler implements HttpHandler { - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String method = httpExchange.getRequestMethod(); - String path = httpExchange.getRequestURI().getPath(); - String[] partsOfPath = path.split("/"); - switch (method) { - case "GET" -> { - if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getSubtasks()), 200); - return; - } else if (partsOfPath.length == 3) { - int id = Integer.parseInt(partsOfPath[2]); - Subtask task = taskManager.getSubtaskById(id); - if (task == null) { - BaseHttpHandler.sendNotFound(httpExchange); - } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); - } - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - case "POST" -> { - if (partsOfPath.length == 2) { - InputStream inputStream = httpExchange.getRequestBody(); - String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); - Subtask task = gson.fromJson(body, Subtask.class); - try { - taskManager.createSubtask(task); - } catch (InterruptedException e) { - BaseHttpHandler.sendHasOverlaps(httpExchange); - } - BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 201); - } else { - BaseHttpHandler.sendHasOverlaps(httpExchange); - } - httpExchange.close(); - } - case "DELETE" -> { - if (partsOfPath.length == 3) { - int id = Integer.parseInt(partsOfPath[2]); - Subtask task = taskManager.getSubtaskById(id); - if (task == null) { - BaseHttpHandler.sendNotFound(httpExchange); - } else { - taskManager.deleteSubtask(task); - BaseHttpHandler.sendText(httpExchange, gson.toJson(task), 200); - } - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - default -> BaseHttpHandler.sendServerError(httpExchange); - } - } - } - - class EpicsHandler implements HttpHandler { - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String method = httpExchange.getRequestMethod(); - String path = httpExchange.getRequestURI().getPath(); - String[] partsOfPath = path.split("/"); - switch (method) { - case "GET" -> { - if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpics()), 200); - return; - } else if (partsOfPath.length == 3) { - int id = Integer.parseInt(partsOfPath[2]); - Epic epic = taskManager.getEpicById(id); - if (epic == null) { - BaseHttpHandler.sendNotFound(httpExchange); - } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 200); - } - } else if (partsOfPath.length == 4 && partsOfPath[3].equals("subtasks")) { - int id = Integer.parseInt(partsOfPath[2]); - Epic epic = taskManager.getEpicById(id); - if (epic == null) { - BaseHttpHandler.sendNotFound(httpExchange); - } else { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getEpicsSubtasks(id)), - 200); - } - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - case "POST" -> { - if (partsOfPath.length == 2) { - InputStream inputStream = httpExchange.getRequestBody(); - String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); - Epic epic = gson.fromJson(body, Epic.class); - taskManager.createEpic(epic); - BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 201); - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - case "DELETE" -> { - if (partsOfPath.length == 3) { - int id = Integer.parseInt(partsOfPath[2]); - Epic epic = taskManager.getEpicById(id); - if (epic == null) { - BaseHttpHandler.sendNotFound(httpExchange); - } else { - taskManager.deleteEpic(epic); - BaseHttpHandler.sendText(httpExchange, gson.toJson(epic), 200); - } - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } - default -> BaseHttpHandler.sendServerError(httpExchange); - } - } - } - - class HistoryHandler implements HttpHandler { - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String method = httpExchange.getRequestMethod(); - String path = httpExchange.getRequestURI().getPath(); - String[] partsOfPath = path.split("/"); - if (method.equals("GET")) { - if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getHistory()), 200); - return; - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - } - } - - class PrioritizedHandler implements HttpHandler { - @Override - public void handle(HttpExchange httpExchange) throws IOException { - String method = httpExchange.getRequestMethod(); - String path = httpExchange.getRequestURI().getPath(); - String[] partsOfPath = path.split("/"); - if (method.equals("GET")) { - if (partsOfPath.length == 2) { - BaseHttpHandler.sendText(httpExchange, gson.toJson(taskManager.getPrioritizedTasks()), 200); - return; - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - httpExchange.close(); - } else { - BaseHttpHandler.sendServerError(httpExchange); - } - } - } } diff --git a/test/tracker/HttpTaskManagerTasksTest.java b/test/tracker/HttpTaskManagerTasksTest.java index 2f929dd..a737518 100644 --- a/test/tracker/HttpTaskManagerTasksTest.java +++ b/test/tracker/HttpTaskManagerTasksTest.java @@ -1,14 +1,11 @@ package tracker; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.AfterEach; import tracker.controllers.InMemoryTaskManager; import tracker.controllers.TaskManager; import tracker.model.Epic; -import tracker.model.LocalDateAdapter; import tracker.model.Subtask; import tracker.model.Task; import tracker.server.HttpTaskServer; @@ -27,15 +24,15 @@ public class HttpTaskManagerTasksTest { TaskManager taskManager = new InMemoryTaskManager(); HttpTaskServer taskServer = new HttpTaskServer(8080, taskManager); - private static final Gson gson = new GsonBuilder() - .serializeNulls() - .registerTypeAdapter(LocalDateTime.class, new LocalDateAdapter()) - .create(); + final long MINUTES_IN_DAY = 60 * 24; final LocalDateTime TASK_START_TIME = LocalDateTime.now(); + public HttpTaskManagerTasksTest() throws IOException { + } + @BeforeEach - public void setUp() throws IOException { + public void setUp() { taskServer.start(); } @@ -46,13 +43,10 @@ public void shutDown() { @Test public void testTasks() throws IOException, InterruptedException { - Task task1 = new Task("Task 1", "Do task 1", 1, MINUTES_IN_DAY, - TASK_START_TIME.minusDays(4)); - Task task2 = new Task("Task 2", "Do task 2", 2, MINUTES_IN_DAY, - TASK_START_TIME.minusDays(4)); - - String task1Json = gson.toJson(task1); - String task2Json = gson.toJson(task2); + String task1Json = "{\"name\":\"Task 1\",\"description\":\"Do task 1\",\"status\":\"NEW\"" + + ",\"duration\":" + MINUTES_IN_DAY + ",\"startTime\": \"" + TASK_START_TIME.minusDays(4) + "\"}"; + String task2Json = "{\"name\":\"Task 2\",\"description\":\"Do task 2\",\"status\":\"NEW\"" + + ",\"duration\":" + MINUTES_IN_DAY + ",\"startTime\": \"" + TASK_START_TIME.minusDays(4) + "\"}"; URI urlTasks = URI.create("http://localhost:8080/tasks"); HttpResponse response; @@ -74,8 +68,8 @@ public void testTasks() throws IOException, InterruptedException { response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(406, response.statusCode()); - task2.setStartTime(TASK_START_TIME.minusDays(3)); - task2Json = gson.toJson(task2); + task2Json = "{\"name\":\"Task 2\",\"description\":\"Do task 2\",\"status\":\"NEW\"" + + ",\"duration\":" + MINUTES_IN_DAY + ",\"startTime\": \"" + TASK_START_TIME.minusDays(3) + "\"}"; request = HttpRequest.newBuilder().uri(urlTasks).POST(HttpRequest.BodyPublishers.ofString(task2Json)).build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(201, response.statusCode()); @@ -109,20 +103,27 @@ public void testTasks() throws IOException, InterruptedException { @Test public void checkEpicsAndSubtasks() throws IOException, InterruptedException { - Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", 1); - Epic epic2 = new Epic("Epic 2", "Do all subtasks from epic 2", 2); - Subtask subtask1 = new Subtask("Subtask 1", "Do subtask 1", 3, epic1, MINUTES_IN_DAY, - TASK_START_TIME.minusDays(2)); - Subtask subtask2 = new Subtask("Subtask 2", "Do subtask 2", 4, epic1, MINUTES_IN_DAY, - TASK_START_TIME.minusDays(1)); - Subtask subtask3 = new Subtask("Subtask 3", "Do subtask 3", 5, epic2, MINUTES_IN_DAY, - TASK_START_TIME.minusDays(1)); - - String epic1Json = gson.toJson(epic1); - String epic2Json = gson.toJson(epic2); - String subtask1Json = gson.toJson(subtask1); - String subtask2Json = gson.toJson(subtask2); - String subtask3Json = gson.toJson(subtask3); + String epic1Json = "{\"endTime\":\"1970-01-01T00:00:00\",\"emptyDateTime\":\"1970-01-01T00:00:00\"" + + ",\"name\":\"Epic 1\",\"description\":\"Do all subtasks from epic 1\",\"id\":1,\"status\":null" + + ",\"duration\":0,\"startTime\":\"1970-01-01T00:00:00\"}"; + String epic2Json = "{\"endTime\":\"1970-01-01T00:00:00\",\"emptyDateTime\":\"1970-01-01T00:00:00\"" + + ",\"name\":\"Epic 2\",\"description\":\"Do all subtasks from epic 2\",\"id\":2,\"status\":null" + + ",\"duration\":0,\"startTime\":\"1970-01-01T00:00:00\"}"; + String subtask1Json = "{\"epic\":{\"endTime\":\"1970-01-01T00:00:00\",\"emptyDateTime\":\"1970-01-01T00:00:00\"" + + ",\"name\":\"Epic 1\",\"description\":\"Do all subtasks from epic 1\",\"id\":1,\"status\":null" + + ",\"duration\":0,\"startTime\":\"1970-01-01T00:00:00\"},\"name\":\"Subtask 1\"" + + ",\"description\":\"Do subtask 1\",\"status\":\"NEW\",\"duration\":" + MINUTES_IN_DAY + + ",\"startTime\":\"" + TASK_START_TIME.minusDays(3) + "\"}"; + String subtask2Json = "{\"epic\":{\"endTime\":\"1970-01-01T00:00:00\",\"emptyDateTime\":\"1970-01-01T00:00:00\"" + + ",\"name\":\"Epic 1\",\"description\":\"Do all subtasks from epic 1\",\"id\":1,\"status\":null" + + ",\"duration\":0,\"startTime\":\"1970-01-01T00:00:00\"},\"name\":\"Subtask 2\"" + + ",\"description\":\"Do subtask 2\",\"status\":\"NEW\",\"duration\":" + MINUTES_IN_DAY + + ",\"startTime\":\"" + TASK_START_TIME.minusDays(2) + "\"}"; + String subtask3Json = "{\"epic\":{\"endTime\":\"1970-01-01T00:00:00\",\"emptyDateTime\":\"1970-01-01T00:00:00\"" + + ",\"name\":\"Epic 2\",\"description\":\"Do all subtasks from epic 2\",\"id\":2,\"status\":null" + + ",\"duration\":0,\"startTime\":\"1970-01-01T00:00:00\"},\"name\":\"Subtask 3\"" + + ",\"description\":\"Do subtask 3\",\"status\":\"NEW\",\"duration\":" + MINUTES_IN_DAY + + ",\"startTime\":\"" + TASK_START_TIME.minusDays(2) + "\"}"; URI urlEpics = URI.create("http://localhost:8080/epics"); URI urlSubtasks = URI.create("http://localhost:8080/subtasks"); @@ -162,8 +163,11 @@ public void checkEpicsAndSubtasks() throws IOException, InterruptedException { response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(406, response.statusCode()); - subtask3.setStartTime(TASK_START_TIME); - subtask3Json = gson.toJson(subtask3); + subtask3Json = "{\"epic\":{\"endTime\":\"1970-01-01T00:00:00\",\"emptyDateTime\":\"1970-01-01T00:00:00\"" + + ",\"name\":\"Epic 2\",\"description\":\"Do all subtasks from epic 2\",\"id\":2,\"status\":null" + + ",\"duration\":0,\"startTime\":\"1970-01-01T00:00:00\"},\"name\":\"Subtask 3\"" + + ",\"description\":\"Do subtask 3\",\"status\":\"NEW\",\"duration\":" + MINUTES_IN_DAY + + ",\"startTime\":\"" + TASK_START_TIME.minusDays(1) + "\"}"; request = HttpRequest.newBuilder().uri(urlSubtasks).POST(HttpRequest.BodyPublishers.ofString(subtask3Json)) .build(); response = client.send(request, HttpResponse.BodyHandlers.ofString()); diff --git a/test/tracker/controllers/TaskManagerTest.java b/test/tracker/controllers/TaskManagerTest.java index d4fff28..1383f47 100644 --- a/test/tracker/controllers/TaskManagerTest.java +++ b/test/tracker/controllers/TaskManagerTest.java @@ -1,6 +1,7 @@ package tracker.controllers; import org.junit.jupiter.api.Test; +import tracker.exceptions.OverlapsException; import tracker.model.Epic; import tracker.model.Status; import tracker.model.Subtask; @@ -48,7 +49,7 @@ void checkEpic() throws InterruptedException { } @Test - void checkEpicStatus() throws InterruptedException { + void checkEpicStatus() throws OverlapsException { // Все подзадачи со статусом NEW. Epic epic1 = new Epic("Epic 1", "Do all subtasks from epic 1", taskManager.getTaskId()); taskManager.createEpic(epic1); @@ -88,7 +89,7 @@ void checkEpicStatus() throws InterruptedException { } @Test - void checkTaskIntersection() throws InterruptedException { + void checkTaskIntersection() throws OverlapsException { // При наличии пересечения по времени выполнения задача не будет создана Task task1 = new Task("Task 1", "Do task 1", taskManager.getTaskId(), MINUTES_IN_DAY, TASK_START_TIME); @@ -97,7 +98,7 @@ void checkTaskIntersection() throws InterruptedException { TASK_START_TIME); try { taskManager.createTask(task2); - } catch (InterruptedException e) { + } catch (OverlapsException e) { assertEquals(1, taskManager.getTaskById(task1.getId()).getId(), "Неверный Id"); assertEquals(1, taskManager.getTasks().size(), "Неверное количество задач"); task2.setStartTime(TASK_START_TIME.plusDays(1)); From f82ce0103252e20b2cb7379dccac05ad74308579 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Thu, 7 Aug 2025 00:39:21 +0300 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tracker/handler/EpicsHandler.java | 2 +- src/tracker/handler/HistoryHandler.java | 2 +- src/tracker/handler/PrioritizedHandler.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tracker/handler/EpicsHandler.java b/src/tracker/handler/EpicsHandler.java index 7df3b30..25bdca3 100644 --- a/src/tracker/handler/EpicsHandler.java +++ b/src/tracker/handler/EpicsHandler.java @@ -8,7 +8,7 @@ import java.io.IOException; import java.io.InputStream; -public class EpicsHandler extends BaseHttpHandler{ +public class EpicsHandler extends BaseHttpHandler { public EpicsHandler(Gson gson, TaskManager taskManager) { super(gson, taskManager); } diff --git a/src/tracker/handler/HistoryHandler.java b/src/tracker/handler/HistoryHandler.java index f905b84..d863443 100644 --- a/src/tracker/handler/HistoryHandler.java +++ b/src/tracker/handler/HistoryHandler.java @@ -6,7 +6,7 @@ import java.io.IOException; -public class HistoryHandler extends BaseHttpHandler{ +public class HistoryHandler extends BaseHttpHandler { public HistoryHandler(Gson gson, TaskManager taskManager) { super(gson, taskManager); } diff --git a/src/tracker/handler/PrioritizedHandler.java b/src/tracker/handler/PrioritizedHandler.java index 51c1ad7..3615b4d 100644 --- a/src/tracker/handler/PrioritizedHandler.java +++ b/src/tracker/handler/PrioritizedHandler.java @@ -6,7 +6,7 @@ import java.io.IOException; -public class PrioritizedHandler extends BaseHttpHandler{ +public class PrioritizedHandler extends BaseHttpHandler { public PrioritizedHandler(Gson gson, TaskManager taskManager) { super(gson, taskManager); } From 761800179d0c28f261cb3b1d7b3a5ff8f310da33 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedorov Date: Thu, 7 Aug 2025 00:45:42 +0300 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tracker/handler/BaseHttpHandler.java | 2 +- src/tracker/handler/EpicsHandler.java | 2 +- src/tracker/handler/SubtasksHandler.java | 2 +- src/tracker/handler/TasksHandler.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tracker/handler/BaseHttpHandler.java b/src/tracker/handler/BaseHttpHandler.java index 6614991..c3a310d 100644 --- a/src/tracker/handler/BaseHttpHandler.java +++ b/src/tracker/handler/BaseHttpHandler.java @@ -12,7 +12,7 @@ public abstract class BaseHttpHandler implements HttpHandler { protected final Gson gson; protected final TaskManager taskManager; - protected final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + protected final Charset charset = StandardCharsets.UTF_8; public BaseHttpHandler(Gson gson, TaskManager taskManager) { this.gson = gson; diff --git a/src/tracker/handler/EpicsHandler.java b/src/tracker/handler/EpicsHandler.java index 25bdca3..5b450fa 100644 --- a/src/tracker/handler/EpicsHandler.java +++ b/src/tracker/handler/EpicsHandler.java @@ -48,7 +48,7 @@ public void handle(HttpExchange httpExchange) throws IOException { case "POST" -> { if (partsOfPath.length == 2) { InputStream inputStream = httpExchange.getRequestBody(); - String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + String body = new String(inputStream.readAllBytes(), charset); if (body.isEmpty()) { BaseHttpHandler.sendServerError(httpExchange); } else { diff --git a/src/tracker/handler/SubtasksHandler.java b/src/tracker/handler/SubtasksHandler.java index 9f1cff1..0016dcb 100644 --- a/src/tracker/handler/SubtasksHandler.java +++ b/src/tracker/handler/SubtasksHandler.java @@ -40,7 +40,7 @@ public void handle(HttpExchange httpExchange) throws IOException { case "POST" -> { if (partsOfPath.length == 2) { InputStream inputStream = httpExchange.getRequestBody(); - String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + String body = new String(inputStream.readAllBytes(), charset); Subtask task = gson.fromJson(body, Subtask.class); if (body.isEmpty()) { BaseHttpHandler.sendServerError(httpExchange); diff --git a/src/tracker/handler/TasksHandler.java b/src/tracker/handler/TasksHandler.java index 9874851..0f08596 100644 --- a/src/tracker/handler/TasksHandler.java +++ b/src/tracker/handler/TasksHandler.java @@ -40,7 +40,7 @@ public void handle(HttpExchange httpExchange) throws IOException { case "POST" -> { if (partsOfPath.length == 2) { InputStream inputStream = httpExchange.getRequestBody(); - String body = new String(inputStream.readAllBytes(), DEFAULT_CHARSET); + String body = new String(inputStream.readAllBytes(), charset); if (body.isEmpty()) { BaseHttpHandler.sendServerError(httpExchange); } else {