From d72b5b48e1bff804174bc36d5d52fbfec95794d1 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:41:12 +0200 Subject: [PATCH 01/23] Update project to Java 21, Spring Boot 4.0.2, and add new test dependencies --- pom.xml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 6058c82..0d1ce1c 100644 --- a/pom.xml +++ b/pom.xml @@ -8,14 +8,14 @@ 1.0.0 war Simple-Invoicing - Final Project — Spring Boot Advanced — May 2024 + Final Project – Spring Boot Advanced – May 2024 - 17 - 17 + 21 + 21 UTF-8 - 17 - 3.5.7 + 21 + 4.0.2 3.2.6 2.3.2 9.5.0 @@ -91,6 +91,16 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-webmvc-test + test + + + org.springframework.boot + spring-boot-starter-data-jpa-test + test + org.springframework.security spring-security-test From f13da7b840537fa86f402a946d108a45150da925 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:41:31 +0200 Subject: [PATCH 02/23] Update system properties to require Java 21 --- system.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system.properties b/system.properties index 0dc726c..ec9df9a 100644 --- a/system.properties +++ b/system.properties @@ -1 +1 @@ -java.runtime.version=17 \ No newline at end of file +java.runtime.version=21 \ No newline at end of file From 919e5fd86e5cdffcb7d93f391f10246b4be7af96 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:41:48 +0200 Subject: [PATCH 03/23] Update Dockerfile to use Java 21 alpine image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8f4201f..5680209 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:17-jdk-alpine +FROM eclipse-temurin:21-jdk-alpine WORKDIR /app From ceeb76b1f80a3dc32b8526b88ac12f0aca5201d4 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:42:55 +0200 Subject: [PATCH 04/23] Restrict /log/** to ROOT role and update static resource matchers --- .../softuni/invoice/config/SecurityConfiguration.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java b/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java index bafc390..1d2753b 100644 --- a/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java +++ b/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java @@ -1,7 +1,6 @@ package bg.softuni.invoice.config; import lombok.AllArgsConstructor; -import org.springframework.boot.autoconfigure.security.servlet.PathRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationProvider; @@ -34,9 +33,16 @@ public SecurityFilterChain configureSecurity(HttpSecurity httpSecurity) throws E .csrf(csrf -> csrf.csrfTokenRepository(csrfTokenRepository())) .authorizeHttpRequests(auth -> auth .requestMatchers("/").permitAll() - .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() + .requestMatchers( + "/css/**", + "/js/**", + "/images/**", + "/webjars/**", + "/favicon.ico" + ).permitAll() .requestMatchers("/actuator/health").permitAll() .requestMatchers("/user/register", "/user/login").anonymous() + .requestMatchers("/log/**").hasRole("ROOT") .anyRequest().authenticated() ) .formLogin(form -> form From 0dc55df6bb6ecfb2919ef6452c80d205b2da4b95 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:43:47 +0200 Subject: [PATCH 05/23] Fix import for PathRequest to match Spring Boot 4 changes --- .../bg/softuni/invoice/web/interceptor/LoggingInterceptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bg/softuni/invoice/web/interceptor/LoggingInterceptor.java b/src/main/java/bg/softuni/invoice/web/interceptor/LoggingInterceptor.java index 37edd70..95ad581 100644 --- a/src/main/java/bg/softuni/invoice/web/interceptor/LoggingInterceptor.java +++ b/src/main/java/bg/softuni/invoice/web/interceptor/LoggingInterceptor.java @@ -7,7 +7,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; -import org.springframework.boot.autoconfigure.security.servlet.PathRequest; +import org.springframework.boot.security.autoconfigure.web.servlet.PathRequest; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; From bfd34905492ae27ab8269490779090a20486f2c4 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:44:29 +0200 Subject: [PATCH 06/23] Refactor HomeController to improve authentication check using Authentication instead of Principal --- .../invoice/web/controller/HomeController.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/bg/softuni/invoice/web/controller/HomeController.java b/src/main/java/bg/softuni/invoice/web/controller/HomeController.java index aca6ecc..7f271e5 100644 --- a/src/main/java/bg/softuni/invoice/web/controller/HomeController.java +++ b/src/main/java/bg/softuni/invoice/web/controller/HomeController.java @@ -2,19 +2,23 @@ import bg.softuni.invoice.web.annotation.PageTitle; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; -import java.security.Principal; - @Controller public class HomeController { @GetMapping("/") @PageTitle("invoices") - public String index(Principal principal) { + public String index(Authentication authentication) { + + boolean isLoggedIn = authentication != null + && authentication.isAuthenticated() + && !(authentication instanceof AnonymousAuthenticationToken); - if (principal != null) { + if (isLoggedIn) { return "home/home"; } From 07b968bf854df3795ea68ca793bbe30f3d73958b Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:44:59 +0200 Subject: [PATCH 07/23] Replace ROLE_ROOT with ROOT in PreAuthorize annotations for consistency --- .../softuni/invoice/web/controller/UserController.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/bg/softuni/invoice/web/controller/UserController.java b/src/main/java/bg/softuni/invoice/web/controller/UserController.java index bf7cc84..2354429 100644 --- a/src/main/java/bg/softuni/invoice/web/controller/UserController.java +++ b/src/main/java/bg/softuni/invoice/web/controller/UserController.java @@ -149,7 +149,7 @@ public String profileConfirm(@Valid @GetMapping("/all") @PageTitle("User all") - @PreAuthorize("hasRole('ROLE_ROOT')") + @PreAuthorize("hasRole('ROOT')") public String allUsers(Model model) { List users = this.userService.getAllUsers() @@ -172,7 +172,7 @@ public String allUsers(Model model) { } @PostMapping("/set-admin/{id}") - @PreAuthorize("hasRole('ROLE_ROOT')") + @PreAuthorize("hasRole('ROOT')") public String setAdminRole(@PathVariable String id) { this.userService.setAdmin(id); @@ -180,7 +180,7 @@ public String setAdminRole(@PathVariable String id) { } @PostMapping("/set-user/{id}") - @PreAuthorize("hasRole('ROLE_ROOT')") + @PreAuthorize("hasRole('ROOT')") public String setUserRole(@PathVariable String id) { this.userService.setUser(id); @@ -188,7 +188,7 @@ public String setUserRole(@PathVariable String id) { } @PostMapping("/set-enabled/{id}") - @PreAuthorize("hasRole('ROLE_ROOT')") + @PreAuthorize("hasRole('ROOT')") public String setEnabled(@PathVariable String id) { this.userService.setUserEnabled(id); @@ -196,7 +196,7 @@ public String setEnabled(@PathVariable String id) { } @PostMapping("/set-disabled/{id}") - @PreAuthorize("hasRole('ROLE_ROOT')") + @PreAuthorize("hasRole('ROOT')") public String setDisabled(@PathVariable String id) { this.userService.setUserDisabled(id); From 617c01e620add6495d6c9bb0fa90e967f6827ee8 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:25:25 +0200 Subject: [PATCH 08/23] Remove unnecessary @Async and @EnableAsync annotations from ScheduleService interface --- .../java/bg/softuni/invoice/service/ScheduleService.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/bg/softuni/invoice/service/ScheduleService.java b/src/main/java/bg/softuni/invoice/service/ScheduleService.java index bb519a1..31dea1e 100644 --- a/src/main/java/bg/softuni/invoice/service/ScheduleService.java +++ b/src/main/java/bg/softuni/invoice/service/ScheduleService.java @@ -1,14 +1,8 @@ package bg.softuni.invoice.service; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.EnableAsync; - -@EnableAsync public interface ScheduleService { - - @Async void deleteLogs(); - @Async void changeStatus(); } + From e7e3ef4840a934ec117216ef07a44e4fe22885d4 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sat, 14 Feb 2026 05:55:52 +0200 Subject: [PATCH 09/23] Fix incorrect import to use correct DataJpaTest annotation --- .../bg/softuni/invoice/repository/CompanyRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/bg/softuni/invoice/repository/CompanyRepositoryTest.java b/src/test/java/bg/softuni/invoice/repository/CompanyRepositoryTest.java index 452b94a..c1c0629 100644 --- a/src/test/java/bg/softuni/invoice/repository/CompanyRepositoryTest.java +++ b/src/test/java/bg/softuni/invoice/repository/CompanyRepositoryTest.java @@ -7,7 +7,7 @@ import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest; import java.util.List; import java.util.Optional; From b15a55a7731c3ecaa98f706f711189576d3bb91c Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sat, 14 Feb 2026 05:56:04 +0200 Subject: [PATCH 10/23] Fix incorrect import in UserRepositoryTest --- .../java/bg/softuni/invoice/repository/UserRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/bg/softuni/invoice/repository/UserRepositoryTest.java b/src/test/java/bg/softuni/invoice/repository/UserRepositoryTest.java index 9ba4089..d82d89c 100644 --- a/src/test/java/bg/softuni/invoice/repository/UserRepositoryTest.java +++ b/src/test/java/bg/softuni/invoice/repository/UserRepositoryTest.java @@ -4,7 +4,7 @@ import jakarta.persistence.EntityManager; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest; import java.util.Optional; From dd631903130879fdf4122d9b0a122bbb711647ca Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sat, 14 Feb 2026 05:59:17 +0200 Subject: [PATCH 11/23] Fix incorrect import to use correct DataJpaTest annotation --- .../java/bg/softuni/invoice/repository/RoleRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/bg/softuni/invoice/repository/RoleRepositoryTest.java b/src/test/java/bg/softuni/invoice/repository/RoleRepositoryTest.java index 7770348..4cf667e 100644 --- a/src/test/java/bg/softuni/invoice/repository/RoleRepositoryTest.java +++ b/src/test/java/bg/softuni/invoice/repository/RoleRepositoryTest.java @@ -4,7 +4,7 @@ import jakarta.persistence.EntityManager; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest; import java.util.Optional; From a3e2d2925cf48b6a34b6f3b0130425c2256869f5 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sat, 14 Feb 2026 06:01:40 +0200 Subject: [PATCH 12/23] Fix incorrect import in LogRepositoryTest --- .../java/bg/softuni/invoice/repository/LogRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/bg/softuni/invoice/repository/LogRepositoryTest.java b/src/test/java/bg/softuni/invoice/repository/LogRepositoryTest.java index 060f377..7119912 100644 --- a/src/test/java/bg/softuni/invoice/repository/LogRepositoryTest.java +++ b/src/test/java/bg/softuni/invoice/repository/LogRepositoryTest.java @@ -5,7 +5,7 @@ import jakarta.persistence.EntityManager; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest; import java.time.LocalDateTime; import java.util.List; From d3bbe1db71d9319f050bf5e7ecb54b6c243ba7ec Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sun, 15 Feb 2026 05:45:11 +0200 Subject: [PATCH 13/23] Fix incorrect import to use correct DataJpaTest annotation --- .../java/bg/softuni/invoice/repository/ItemRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/bg/softuni/invoice/repository/ItemRepositoryTest.java b/src/test/java/bg/softuni/invoice/repository/ItemRepositoryTest.java index 3fd08c5..da8a911 100644 --- a/src/test/java/bg/softuni/invoice/repository/ItemRepositoryTest.java +++ b/src/test/java/bg/softuni/invoice/repository/ItemRepositoryTest.java @@ -5,7 +5,7 @@ import jakarta.persistence.EntityManager; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest; import java.math.BigDecimal; import java.util.Optional; From 35d3b1a3a48c3cee2e12bf74e1e46ddbc56c86e5 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sun, 15 Feb 2026 05:48:03 +0200 Subject: [PATCH 14/23] Fix incorrect import in InvoiceRepositoryTest --- .../bg/softuni/invoice/repository/InvoiceRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java b/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java index 50cb51d..69525ba 100644 --- a/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java +++ b/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest; import java.math.BigDecimal; import java.time.LocalDate; From 2f1f7c29adcc40e9611a603726cd25888eff8147 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sun, 15 Feb 2026 05:52:50 +0200 Subject: [PATCH 15/23] Fix incorrect annotation in CompanyControllerTest and replace WithMockUser with MockMvc user setup --- .../web/controller/CompanyControllerTest.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/test/java/bg/softuni/invoice/web/controller/CompanyControllerTest.java b/src/test/java/bg/softuni/invoice/web/controller/CompanyControllerTest.java index 37f7147..4b5be1a 100644 --- a/src/test/java/bg/softuni/invoice/web/controller/CompanyControllerTest.java +++ b/src/test/java/bg/softuni/invoice/web/controller/CompanyControllerTest.java @@ -10,18 +10,20 @@ import org.mockito.Mockito; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.flash; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -@WebMvcTest(CompanyController.class) +@SpringBootTest +@AutoConfigureMockMvc class CompanyControllerTest { @Autowired @@ -43,7 +45,6 @@ class CompanyControllerTest { private ItemService itemService; @Test - @WithMockUser(roles = {"ADMIN"}) void testAddConfirm_withValidInput_shouldRedirectToAll() throws Exception { CompanyAddBindingModel validModel = new CompanyAddBindingModel(); validModel.setName("Valid Name"); @@ -59,7 +60,7 @@ void testAddConfirm_withValidInput_shouldRedirectToAll() throws Exception { Mockito.when(companyService.getCompanyByUniqueIdentifier(validModel.getUniqueIdentifier())).thenReturn(null); Mockito.when(modelMapper.map(validModel, CompanyServiceModel.class)).thenReturn(serviceModel); - mockMvc.perform(post("/company/add") + mockMvc.perform(post("/company/add").with(user("test-admin").roles("ADMIN")) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .with(csrf()) .param("name", validModel.getName()) @@ -69,7 +70,6 @@ void testAddConfirm_withValidInput_shouldRedirectToAll() throws Exception { } @Test - @WithMockUser(roles = {"ADMIN"}) void testAddConfirm_withNameConflict_shouldRedirectToAdd() throws Exception { CompanyAddBindingModel conflictingModel = new CompanyAddBindingModel(); conflictingModel.setName("Existing Company"); @@ -81,7 +81,7 @@ void testAddConfirm_withNameConflict_shouldRedirectToAdd() throws Exception { Mockito.when(companyService.getCompanyByName(conflictingModel.getName())).thenReturn(conflictingServiceModel); - mockMvc.perform(post("/company/add") + mockMvc.perform(post("/company/add").with(user("test-admin").roles("ADMIN")) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .with(csrf()) .param("name", conflictingModel.getName()) @@ -93,7 +93,6 @@ void testAddConfirm_withNameConflict_shouldRedirectToAdd() throws Exception { } @Test - @WithMockUser(roles = {"ADMIN"}) void testAddConfirm_withUniqueIdentifierConflict_shouldRedirectToAdd() throws Exception { CompanyAddBindingModel conflictingModel = new CompanyAddBindingModel(); conflictingModel.setName("New Company"); @@ -106,7 +105,7 @@ void testAddConfirm_withUniqueIdentifierConflict_shouldRedirectToAdd() throws Ex Mockito.when(companyService.getCompanyByName(conflictingModel.getName())).thenReturn(null); Mockito.when(companyService.getCompanyByUniqueIdentifier(conflictingModel.getUniqueIdentifier())).thenReturn(conflictingServiceModel); - mockMvc.perform(post("/company/add") + mockMvc.perform(post("/company/add").with(user("test-admin").roles("ADMIN")) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .with(csrf()) .param("name", conflictingModel.getName()) @@ -118,9 +117,8 @@ void testAddConfirm_withUniqueIdentifierConflict_shouldRedirectToAdd() throws Ex } @Test - @WithMockUser(roles = {"ADMIN"}) void testAddConfirm_withValidationErrors_shouldRedirectToAdd() throws Exception { - mockMvc.perform(post("/company/add") + mockMvc.perform(post("/company/add").with(user("test-admin").roles("ADMIN")) .contentType(MediaType.APPLICATION_FORM_URLENCODED) .with(csrf()) .param("name", "") From 7db1700568deca115d2806c649ea9f44744e5ed2 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Sun, 15 Feb 2026 05:56:54 +0200 Subject: [PATCH 16/23] Fix incorrect imports and assertions --- .../invoice/web/error/GlobalExceptionHandlerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/bg/softuni/invoice/web/error/GlobalExceptionHandlerTest.java b/src/test/java/bg/softuni/invoice/web/error/GlobalExceptionHandlerTest.java index 5278194..b5dfcc5 100644 --- a/src/test/java/bg/softuni/invoice/web/error/GlobalExceptionHandlerTest.java +++ b/src/test/java/bg/softuni/invoice/web/error/GlobalExceptionHandlerTest.java @@ -2,8 +2,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MockMvc; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; @@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @@ -28,7 +28,7 @@ class GlobalExceptionHandlerTest { void handleAllErrors_whenFailureUrl_redirectsToLoginPage() throws Exception { mockMvc.perform(get("/a-nonexistent-url")) .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrlPattern("**/user/login")); + .andExpect(redirectedUrl("/user/login")); } @Test From 73e3f8ab523e66b6c8a6b008a3f132639abec767 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Mon, 16 Feb 2026 05:57:19 +0200 Subject: [PATCH 17/23] Remove redundant exception declaration from configureSecurity method --- .../java/bg/softuni/invoice/config/SecurityConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java b/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java index 1d2753b..50a52d8 100644 --- a/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java +++ b/src/main/java/bg/softuni/invoice/config/SecurityConfiguration.java @@ -27,7 +27,7 @@ public class SecurityConfiguration { private final BCryptPasswordEncoder bCryptPasswordEncoder; @Bean - public SecurityFilterChain configureSecurity(HttpSecurity httpSecurity) throws Exception { + public SecurityFilterChain configureSecurity(HttpSecurity httpSecurity) { httpSecurity .cors(AbstractHttpConfigurer::disable) .csrf(csrf -> csrf.csrfTokenRepository(csrfTokenRepository())) From df74baa95b5a15f05eee010804c7c6cb0d0e7e03 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Mon, 16 Feb 2026 05:58:16 +0200 Subject: [PATCH 18/23] Fix assertion method in InvoiceRepositoryTest --- .../bg/softuni/invoice/repository/InvoiceRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java b/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java index 69525ba..523ff34 100644 --- a/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java +++ b/src/test/java/bg/softuni/invoice/repository/InvoiceRepositoryTest.java @@ -84,7 +84,7 @@ void testGetAllByUser_withDifferentUser_returnsOnlyRelevantInvoices() { List resultForUser2 = invoiceRepository.getAllByUser(user2); assertThat(resultForUser1).hasSize(1); - assertThat(resultForUser1.get(0).getTotalValue()).isEqualByComparingTo("200.00"); + assertThat(resultForUser1.getFirst().getTotalValue()).isEqualByComparingTo("200.00"); assertThat(resultForUser2).isEmpty(); } From a40b3a10457eb6ac102ade603f51b043164edd24 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Mon, 16 Feb 2026 06:01:58 +0200 Subject: [PATCH 19/23] Fix incorrect imports and replace WithMockUser with MockMvc user setup --- .../controller/UserControllerTest.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) rename src/test/java/bg/softuni/invoice/{ => web}/controller/UserControllerTest.java (83%) diff --git a/src/test/java/bg/softuni/invoice/controller/UserControllerTest.java b/src/test/java/bg/softuni/invoice/web/controller/UserControllerTest.java similarity index 83% rename from src/test/java/bg/softuni/invoice/controller/UserControllerTest.java rename to src/test/java/bg/softuni/invoice/web/controller/UserControllerTest.java index 185b69d..b7a5449 100644 --- a/src/test/java/bg/softuni/invoice/controller/UserControllerTest.java +++ b/src/test/java/bg/softuni/invoice/web/controller/UserControllerTest.java @@ -1,4 +1,4 @@ -package bg.softuni.invoice.controller; +package bg.softuni.invoice.web.controller; import bg.softuni.invoice.repository.UserRepository; import bg.softuni.invoice.service.RoleService; @@ -6,12 +6,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; @@ -45,10 +45,9 @@ void login_shouldReturnCorrectView() throws Exception { } @Test - @WithMockUser void login_withLoggedInUserShouldReturnErrorView() throws Exception { this.mockMvc - .perform(get("/user/login")) + .perform(get("/user/login").with(user("test-user").roles("USER"))) .andExpect(status().is4xxClientError()) .andExpect(forwardedUrl("/error")); } @@ -64,7 +63,8 @@ void register_shouldReturnCorrectView() throws Exception { @Test void register_registerSuccessfullyRedirect() throws Exception { this.mockMvc - .perform(post("/user/register").with(csrf()) + .perform(post("/user/register") + .with(csrf()) .param("username", "admin@admin.com") .param("firstName", "Admin") .param("lastName", "Admin") @@ -80,7 +80,8 @@ void register_registerSuccessfullyRedirect() throws Exception { @Test void register_whenBindingResultHasErrorsRedirect() throws Exception { this.mockMvc - .perform(post("/user/register").with(csrf()) + .perform(post("/user/register") + .with(csrf()) .param("username", "") .param("firstName", "") .param("lastName", "") @@ -95,7 +96,8 @@ void register_whenBindingResultHasErrorsRedirect() throws Exception { void register_whenUsernameAlreadyExistsRedirect() throws Exception { this.mockMvc - .perform(post("/user/register").with(csrf()) + .perform(post("/user/register") + .with(csrf()) .param("username", "admin@admin.com") .param("firstName", "Admin") .param("lastName", "Admin") @@ -104,7 +106,8 @@ void register_whenUsernameAlreadyExistsRedirect() throws Exception { ); this.mockMvc - .perform(post("/user/register").with(csrf()) + .perform(post("/user/register") + .with(csrf()) .param("username", "admin@admin.com") .param("firstName", "Test") .param("lastName", "Test") @@ -116,30 +119,26 @@ void register_whenUsernameAlreadyExistsRedirect() throws Exception { } @Test - @WithMockUser void register_withLoggedInUserShouldReturnErrorView() throws Exception { this.mockMvc - .perform(get("/user/register").with(csrf())) + .perform(get("/user/register").with(user("test-user").roles("USER"))) .andExpect(status().is4xxClientError()) .andExpect(forwardedUrl("/error")); } @Test - @WithMockUser(roles = "ROOT") void all_withLoggedInRootUserShouldReturnCorrectView() throws Exception { this.mockMvc - .perform(get("/user/all").with(csrf())) + .perform(get("/user/all").with(user("test-root").roles("ROOT"))) .andExpect(model().attributeExists("users")) .andExpect(model().attributeExists("comparator")) .andExpect(view().name("user/all")); } @Test - @WithMockUser(roles = "ADMIN") void all_withLoggedInAdminOrUserShouldReturnCorrectViewAdmin() throws Exception { this.mockMvc - .perform(get("/user/all").with(csrf())) + .perform(get("/user/all").with(user("test-admin").roles("ADMIN"))) .andExpect(view().name("error")); } - } From f1923cfb7795c42d632b00671e3f4edb5167755a Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Mon, 16 Feb 2026 06:07:43 +0200 Subject: [PATCH 20/23] Fix incorrect imports and adjust LogControllerTest to replace WithMockUser with MockMvc user setup --- .../{ => web}/controller/LogControllerTest.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) rename src/test/java/bg/softuni/invoice/{ => web}/controller/LogControllerTest.java (64%) diff --git a/src/test/java/bg/softuni/invoice/controller/LogControllerTest.java b/src/test/java/bg/softuni/invoice/web/controller/LogControllerTest.java similarity index 64% rename from src/test/java/bg/softuni/invoice/controller/LogControllerTest.java rename to src/test/java/bg/softuni/invoice/web/controller/LogControllerTest.java index e7ae2a6..81ac88a 100644 --- a/src/test/java/bg/softuni/invoice/controller/LogControllerTest.java +++ b/src/test/java/bg/softuni/invoice/web/controller/LogControllerTest.java @@ -1,17 +1,16 @@ -package bg.softuni.invoice.controller; +package bg.softuni.invoice.web.controller; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; - @SpringBootTest @AutoConfigureMockMvc class LogControllerTest { @@ -20,10 +19,10 @@ class LogControllerTest { private MockMvc mockMvc; @Test - @WithMockUser(roles = {"ROOT"}) void all_shouldReturnCorrectView() throws Exception { this.mockMvc - .perform(get("/log/all").with(csrf())) + .perform(get("/log/all").with(user("test-root").roles("ROOT"))) + .andExpect(status().isOk()) .andExpect(view().name("log/all")); } -} \ No newline at end of file +} From a1bd77de38f70b51d4ba525e2febe567186f6fff Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Tue, 17 Feb 2026 05:03:32 +0200 Subject: [PATCH 21/23] Fix incorrect imports in HomeControllerTest and replace WithMockUser with MockMvc user setup --- .../controller/HomeControllerTest.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) rename src/test/java/bg/softuni/invoice/{ => web}/controller/HomeControllerTest.java (73%) diff --git a/src/test/java/bg/softuni/invoice/controller/HomeControllerTest.java b/src/test/java/bg/softuni/invoice/web/controller/HomeControllerTest.java similarity index 73% rename from src/test/java/bg/softuni/invoice/controller/HomeControllerTest.java rename to src/test/java/bg/softuni/invoice/web/controller/HomeControllerTest.java index 4ca8c47..23fa6c2 100644 --- a/src/test/java/bg/softuni/invoice/controller/HomeControllerTest.java +++ b/src/test/java/bg/softuni/invoice/web/controller/HomeControllerTest.java @@ -1,18 +1,16 @@ -package bg.softuni.invoice.controller; +package bg.softuni.invoice.web.controller; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; - @SpringBootTest @AutoConfigureMockMvc class HomeControllerTest { @@ -24,22 +22,22 @@ class HomeControllerTest { void index_shouldReturnCorrectView() throws Exception { this.mockMvc .perform(get("/")) + .andExpect(status().isOk()) .andExpect(view().name("home/index")); } @Test - @WithMockUser void index_withAuthenticatedUserShouldReturnCorrectView() throws Exception { this.mockMvc - .perform(get("/")) + .perform(get("/").with(user("test-user").roles("USER"))) + .andExpect(status().isOk()) .andExpect(view().name("home/home")); } @Test - @WithMockUser() void home_shouldReturnCorrectView() throws Exception { this.mockMvc - .perform(get("/home").with(csrf())) + .perform(get("/home").with(user("test-user").roles("USER"))) .andExpect(status().is3xxRedirection()) .andExpect(view().name("redirect:/invoice/all")); } @@ -48,14 +46,15 @@ void home_shouldReturnCorrectView() throws Exception { void index_withNullPrincipal_shouldReturnIndexView() throws Exception { this.mockMvc .perform(get("/")) + .andExpect(status().isOk()) .andExpect(view().name("home/index")); } @Test - @WithMockUser void index_withAuthenticatedPrincipal_shouldReturnHomeView() throws Exception { this.mockMvc - .perform(get("/")) + .perform(get("/").with(user("test-user").roles("USER"))) + .andExpect(status().isOk()) .andExpect(view().name("home/home")); } } From e7d65d72573bc3be81a7573d177d51a6d7df5530 Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Tue, 17 Feb 2026 05:07:37 +0200 Subject: [PATCH 22/23] Update GitHub Actions workflow to use JDK 21 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76e32f5..1065820 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,10 +13,10 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'zulu' - name: Cache SonarQube packages uses: actions/cache@v4 From 9b67d4bd434f89b1c7f87db45165ba386ad76aab Mon Sep 17 00:00:00 2001 From: mark79-github <52877024+mark79-github@users.noreply.github.com> Date: Tue, 17 Feb 2026 05:21:57 +0200 Subject: [PATCH 23/23] Update dependency versions in pom.xml --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 0d1ce1c..2423941 100644 --- a/pom.xml +++ b/pom.xml @@ -18,11 +18,11 @@ 4.0.2 3.2.6 2.3.2 - 9.5.0 - 42.7.8 + 9.6.0 + 42.7.10 3.20.0 0.8.14 - 3.14.1 + 3.15.0 1.18.42 mark79-github