From c2988aa13cdc18edc9bc7e204f01e7fb373f60bb Mon Sep 17 00:00:00 2001 From: Kirill Topchy Date: Thu, 9 Oct 2025 14:19:06 +0300 Subject: [PATCH 1/6] Greetings feature implemented --- .../features/greeting/GreetingController.java | 24 +++++++++++++++++++ .../features/greeting/GreetingService.java | 23 ++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java create mode 100644 src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java new file mode 100644 index 0000000..30ac8d8 --- /dev/null +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java @@ -0,0 +1,24 @@ +package lv.ctco.springboottemplate.features.greeting; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/greeting") +@Tag(name = "Greeting Controller", description = "Greeting related endpoints") +public class GreetingController { + private final GreetingService greetingService; + + public GreetingController(GreetingService greetingService) { + this.greetingService = greetingService; + } + + @GetMapping + @Operation(summary = "Get greeting message") + public String getGreeting() { + return greetingService.greet(); + } +} diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java new file mode 100644 index 0000000..20fafda --- /dev/null +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java @@ -0,0 +1,23 @@ +package lv.ctco.springboottemplate.features.greeting; + +import lv.ctco.springboottemplate.features.todo.TodoService; +import org.springframework.stereotype.Service; + +@Service +public class GreetingService { + private final TodoService todoService; + + public GreetingService(TodoService todoService) { + this.todoService = todoService; + } + + public String greet() { + var activeTodos = todoService + .getAllTodos() + .stream() + .filter(todo -> !todo.completed()) + .toList(); + + return "Hello from Spring! You have " + activeTodos.size() + " open tasks."; + } +} From 1a715bfe643534e53f1641c9b84dd2119b8de11e Mon Sep 17 00:00:00 2001 From: Kirill Topchy Date: Thu, 9 Oct 2025 14:22:50 +0300 Subject: [PATCH 2/6] Unit tests fixed to use local mongoDB instance instead of test container in docker --- .../GreetingServiceIntegrationTest.java | 32 +++++++++---------- .../todo/TodoServiceIntegrationTest.java | 25 +++++---------- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java index eda5f13..6695b95 100644 --- a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java +++ b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java @@ -1,32 +1,33 @@ package lv.ctco.springboottemplate.features.greeting; +import lv.ctco.springboottemplate.features.todo.Todo; +import lv.ctco.springboottemplate.features.todo.TodoRepository; import lv.ctco.springboottemplate.features.todo.TodoService; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.TestConstructor; -import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; /** - * Integration test for {@link GreetingService}. - * - *

This test verifies that GreetingService correctly interacts with {@link TodoService} and - * reflects the number of open (not completed) todos in the message. + * Integration test for {@link GreetingService} without Testcontainers. * - *

Initially marked {@link Disabled} to be enabled by the developer after implementation. + *

This test uses a locally running MongoDB instance (expected at mongodb://localhost:27017/tododb). + * If you prefer an embedded/in-memory Mongo, add flapdoodle dependency and remove the dynamic property below. */ @SpringBootTest -@Disabled("Enable after implementing GreetingService using TodoService") -@Testcontainers @TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) class GreetingServiceIntegrationTest { - /* - - @Container static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:6.0.8"); - + // Point Spring Data Mongo to a locally running MongoDB instead of using Testcontainers @DynamicPropertySource - static void setProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + static void mongoProps(DynamicPropertyRegistry registry) { + registry.add("spring.data.mongodb.uri", () -> "mongodb://localhost:27017/tododb"); } private final TodoService todoService; @@ -94,5 +95,4 @@ void should_ignore_null_todos_or_null_completed_flags() { // then assertThat(message).contains("1 open task"); } - */ } diff --git a/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java b/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java index 7a98397..70aaa42 100644 --- a/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java +++ b/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java @@ -1,39 +1,30 @@ package lv.ctco.springboottemplate.features.todo; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; -import org.springframework.test.context.TestConstructor; -import org.testcontainers.containers.MongoDBContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest -@Testcontainers -@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) class TodoServiceIntegrationTest { - @Container static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:6.0.8"); - @DynamicPropertySource static void setProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); + registry.add("spring.data.mongodb.uri", () -> "mongodb://localhost:27017/tododb"); } + @Autowired private TodoRepository todoRepository; + @Autowired private TodoService todoService; - public TodoServiceIntegrationTest(TodoRepository todoRepository, TodoService todoService) { - this.todoRepository = todoRepository; - this.todoService = todoService; - } - @BeforeEach void setup() { todoRepository.deleteAll(); From 1fdc6c5e610d503c3517b298adec0b7b791b6216 Mon Sep 17 00:00:00 2001 From: Kirill Topchy Date: Mon, 13 Oct 2025 18:39:12 +0300 Subject: [PATCH 3/6] PR comments fix --- .../features/greeting/GreetingService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java index 20fafda..e432afc 100644 --- a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java @@ -12,12 +12,12 @@ public GreetingService(TodoService todoService) { } public String greet() { - var activeTodos = todoService + var activeTodosCount = todoService .getAllTodos() .stream() .filter(todo -> !todo.completed()) - .toList(); + .count(); - return "Hello from Spring! You have " + activeTodos.size() + " open tasks."; + return String.format("Hello from Spring! You have %d open tasks.", activeTodosCount); } } From 4405ac8b8441d3a0cd4c9d890a1681c9314750d5 Mon Sep 17 00:00:00 2001 From: Kirill Topchy Date: Mon, 13 Oct 2025 18:59:47 +0300 Subject: [PATCH 4/6] fix formating issues --- .../features/greeting/GreetingController.java | 18 ++++++++-------- .../features/greeting/GreetingService.java | 21 ++++++++----------- .../GreetingServiceIntegrationTest.java | 5 +++-- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java index 30ac8d8..ed6b5b5 100644 --- a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java @@ -10,15 +10,15 @@ @RequestMapping("/api/greeting") @Tag(name = "Greeting Controller", description = "Greeting related endpoints") public class GreetingController { - private final GreetingService greetingService; + private final GreetingService greetingService; - public GreetingController(GreetingService greetingService) { - this.greetingService = greetingService; - } + public GreetingController(GreetingService greetingService) { + this.greetingService = greetingService; + } - @GetMapping - @Operation(summary = "Get greeting message") - public String getGreeting() { - return greetingService.greet(); - } + @GetMapping + @Operation(summary = "Get greeting message") + public String getGreeting() { + return greetingService.greet(); + } } diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java index e432afc..71a9f37 100644 --- a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java @@ -5,19 +5,16 @@ @Service public class GreetingService { - private final TodoService todoService; + private final TodoService todoService; - public GreetingService(TodoService todoService) { - this.todoService = todoService; - } + public GreetingService(TodoService todoService) { + this.todoService = todoService; + } - public String greet() { - var activeTodosCount = todoService - .getAllTodos() - .stream() - .filter(todo -> !todo.completed()) - .count(); + public String greet() { + var activeTodosCount = + todoService.getAllTodos().stream().filter(todo -> !todo.completed()).count(); - return String.format("Hello from Spring! You have %d open tasks.", activeTodosCount); - } + return String.format("Hello from Spring! You have %d open tasks.", activeTodosCount); + } } diff --git a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java index 6695b95..849bd5f 100644 --- a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java +++ b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java @@ -17,8 +17,9 @@ /** * Integration test for {@link GreetingService} without Testcontainers. * - *

This test uses a locally running MongoDB instance (expected at mongodb://localhost:27017/tododb). - * If you prefer an embedded/in-memory Mongo, add flapdoodle dependency and remove the dynamic property below. + *

This test uses a locally running MongoDB instance (expected at + * mongodb://localhost:27017/tododb). If you prefer an embedded/in-memory Mongo, add flapdoodle + * dependency and remove the dynamic property below. */ @SpringBootTest @TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) From 037749d397173b25ff76dd95232a4e0d57f2d4e4 Mon Sep 17 00:00:00 2001 From: Kirill Topchy Date: Mon, 13 Oct 2025 18:59:47 +0300 Subject: [PATCH 5/6] fix formating issues --- .../features/greeting/GreetingController.java | 18 ++++++++-------- .../features/greeting/GreetingService.java | 21 ++++++++----------- .../GreetingServiceIntegrationTest.java | 5 +++-- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java index 30ac8d8..ed6b5b5 100644 --- a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingController.java @@ -10,15 +10,15 @@ @RequestMapping("/api/greeting") @Tag(name = "Greeting Controller", description = "Greeting related endpoints") public class GreetingController { - private final GreetingService greetingService; + private final GreetingService greetingService; - public GreetingController(GreetingService greetingService) { - this.greetingService = greetingService; - } + public GreetingController(GreetingService greetingService) { + this.greetingService = greetingService; + } - @GetMapping - @Operation(summary = "Get greeting message") - public String getGreeting() { - return greetingService.greet(); - } + @GetMapping + @Operation(summary = "Get greeting message") + public String getGreeting() { + return greetingService.greet(); + } } diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java index e432afc..71a9f37 100644 --- a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java @@ -5,19 +5,16 @@ @Service public class GreetingService { - private final TodoService todoService; + private final TodoService todoService; - public GreetingService(TodoService todoService) { - this.todoService = todoService; - } + public GreetingService(TodoService todoService) { + this.todoService = todoService; + } - public String greet() { - var activeTodosCount = todoService - .getAllTodos() - .stream() - .filter(todo -> !todo.completed()) - .count(); + public String greet() { + var activeTodosCount = + todoService.getAllTodos().stream().filter(todo -> !todo.completed()).count(); - return String.format("Hello from Spring! You have %d open tasks.", activeTodosCount); - } + return String.format("Hello from Spring! You have %d open tasks.", activeTodosCount); + } } diff --git a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java index 6695b95..849bd5f 100644 --- a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java +++ b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java @@ -17,8 +17,9 @@ /** * Integration test for {@link GreetingService} without Testcontainers. * - *

This test uses a locally running MongoDB instance (expected at mongodb://localhost:27017/tododb). - * If you prefer an embedded/in-memory Mongo, add flapdoodle dependency and remove the dynamic property below. + *

This test uses a locally running MongoDB instance (expected at + * mongodb://localhost:27017/tododb). If you prefer an embedded/in-memory Mongo, add flapdoodle + * dependency and remove the dynamic property below. */ @SpringBootTest @TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) From 750da217714095eb9a317441fe5dfab89bf83702 Mon Sep 17 00:00:00 2001 From: Kirill Topchy Date: Mon, 13 Oct 2025 19:22:53 +0300 Subject: [PATCH 6/6] fix formating again................. --- .../features/greeting/GreetingService.java | 2 +- .../features/greeting/GreetingServiceIntegrationTest.java | 4 ++-- .../features/todo/TodoServiceIntegrationTest.java | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java index 71a9f37..2d5770a 100644 --- a/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java +++ b/src/main/java/lv/ctco/springboottemplate/features/greeting/GreetingService.java @@ -12,7 +12,7 @@ public GreetingService(TodoService todoService) { } public String greet() { - var activeTodosCount = + long activeTodosCount = todoService.getAllTodos().stream().filter(todo -> !todo.completed()).count(); return String.format("Hello from Spring! You have %d open tasks.", activeTodosCount); diff --git a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java index 849bd5f..ddcc817 100644 --- a/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java +++ b/src/test/java/lv/ctco/springboottemplate/features/greeting/GreetingServiceIntegrationTest.java @@ -76,10 +76,10 @@ void should_return_zero_open_tasks_message_if_none_exist() { @Test void should_work_with_no_todos_at_all() { // when - String message = greetingService.greet(); + String msg = greetingService.greet(); // then - assertThat(message).contains("Hello").contains("0 open tasks"); + assertThat(msg).contains("Hello").contains("0 open tasks"); } @Test diff --git a/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java b/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java index 155c443..27436db 100644 --- a/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java +++ b/src/test/java/lv/ctco/springboottemplate/features/todo/TodoServiceIntegrationTest.java @@ -40,11 +40,11 @@ void shouldCreateAndRetrieveTodo() { // when todoService.createTodo(title, description, completed, createdBy); - List allTodos = todoService.getAllTodos(); + List todos = todoService.getAllTodos(); // then - assertThat(allTodos).hasSize(1); - Todo todo = allTodos.getFirst(); + assertThat(todos).hasSize(1); + Todo todo = todos.getFirst(); assertThat(todo.id()).isNotNull(); assertThat(todo.title()).isEqualTo(title);