Public Access
Refactor package structure: domain -> modules
Move domain packages into a new modules.* hierarchy and rename controller packages to api.* across login, registration, and user modules. Update package declarations and imports (including shared.api DTOs and JwtService -> modules login TokenGenerator), adjust tests and persistence/mapper paths accordingly, and apply minor formatting fixes (missing EOF newlines). This reorganizes the project to better separate API surface and module boundaries.
This commit is contained in:
1 parent
3fcba271a6
commit
2a5839b736
73 files changed
+574
-569
No files matched your search
@@ -10,4 +10,4 @@ class AuthServiceApplicationTests extends AbstractIntegrationTest {
|
||||
// If the context fails to load (e.g. Flyway migration fails or beans are missing),
|
||||
// this test will fail automatically. No explicit assertions needed.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,31 +11,31 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
||||
|
||||
/**
|
||||
* ArchUnit tests to enforce Clean Architecture and package boundaries.
|
||||
* ArchUnit tests to enforce Hexagonal Architecture and package boundaries.
|
||||
* Analyzes all classes in the 'auth_service' package, ignoring test classes.
|
||||
*/
|
||||
@AnalyzeClasses(packages = "auth_service", importOptions = ImportOption.DoNotIncludeTests.class)
|
||||
class ArchitectureTest extends AbstractArchitectureTest {
|
||||
|
||||
// ===================================================================================
|
||||
// 1. DOMAIN INDEPENDENCE (Slices)
|
||||
// 1. MODULE INDEPENDENCE (Slices)
|
||||
// ===================================================================================
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule domains_should_not_depend_on_each_other = SlicesRuleDefinition.slices()
|
||||
.matching("auth_service.domain.(*)..")
|
||||
static final ArchRule modules_should_not_depend_on_each_other = SlicesRuleDefinition.slices()
|
||||
.matching("auth_service.modules.(*)..")
|
||||
.should().notDependOnEachOther()
|
||||
.because("Domains (e.g. login, user) should be strictly isolated and independent.");
|
||||
.because("Modules (e.g. login, user) should be strictly isolated and independent.");
|
||||
|
||||
// ===================================================================================
|
||||
// 2. CLEAN ARCHITECTURE DEPENDENCY DIRECTION (Inside out)
|
||||
// 2. HEXAGONAL ARCHITECTURE DEPENDENCY DIRECTION (Inside out)
|
||||
// ===================================================================================
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule domain_core_should_not_depend_on_outside = noClasses()
|
||||
.that().resideInAnyPackage("..model..", "..service..")
|
||||
.should().dependOnClassesThat().resideInAnyPackage("..controller..", "..persistence.entities..", "..persistence.mapper..")
|
||||
.because("Domain core (Models, Services) must not depend on Web/Controller or Persistence details.");
|
||||
.should().dependOnClassesThat().resideInAnyPackage("..api..", "..persistence.entities..", "..persistence.mapper..")
|
||||
.because("Domain core (Models, Services) must not depend on API or Persistence details.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule persistence_interfaces_belong_to_domain = classes()
|
||||
@@ -49,16 +49,16 @@ class ArchitectureTest extends AbstractArchitectureTest {
|
||||
// ===================================================================================
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule dtos_should_only_be_used_in_controllers = classes()
|
||||
.that().resideInAPackage("..controller.dto..")
|
||||
.should().onlyBeAccessed().byAnyPackage("..controller..")
|
||||
.because("DTOs are Web/API concerns and must not leak into Services or Persistence.");
|
||||
static final ArchRule dtos_should_only_be_used_in_api = classes()
|
||||
.that().resideInAPackage("..api.dto..")
|
||||
.should().onlyBeAccessed().byAnyPackage("..api..")
|
||||
.because("DTOs are API concerns and must not leak into Services or Persistence.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule entities_should_only_be_used_in_persistence = classes()
|
||||
.that().resideInAPackage("..persistence.entities..")
|
||||
.should().onlyBeAccessed().byAnyPackage("..persistence..")
|
||||
.because("Database Entities must not leak into the Domain Core or Controllers.");
|
||||
.because("Database Entities must not leak into the Domain Core or APIs.");
|
||||
|
||||
// ===================================================================================
|
||||
// 4. ADDITIONAL BEST PRACTICES
|
||||
@@ -71,28 +71,28 @@ class ArchitectureTest extends AbstractArchitectureTest {
|
||||
.because("Cyclic dependencies make the code unmaintainable and tightly coupled.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule controllers_should_only_call_services = noClasses()
|
||||
.that().resideInAPackage("..controller..")
|
||||
static final ArchRule apis_should_only_call_services = noClasses()
|
||||
.that().resideInAPackage("..api..")
|
||||
.should().dependOnClassesThat().resideInAPackage("..persistence..")
|
||||
.because("Controllers must delegate to Services and should not access Persistence directly.");
|
||||
.because("APIs must delegate to Services and should not access Persistence directly.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule persistence_should_not_depend_on_controllers = noClasses()
|
||||
static final ArchRule persistence_should_not_depend_on_apis = noClasses()
|
||||
.that().resideInAPackage("..persistence..")
|
||||
.should().dependOnClassesThat().resideInAPackage("..controller..")
|
||||
.because("Persistence layer must be independent of the Web/Controller layer.");
|
||||
.should().dependOnClassesThat().resideInAPackage("..api..")
|
||||
.because("Persistence layer must be independent of the API layer.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule exceptions_should_be_isolated = noClasses()
|
||||
.that().resideInAPackage("..exception..")
|
||||
.should().dependOnClassesThat().resideInAnyPackage("..controller..", "..persistence.entities..")
|
||||
.should().dependOnClassesThat().resideInAnyPackage("..api..", "..persistence.entities..")
|
||||
.because("Exceptions should be part of the domain core and independent of infrastructure details.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule configuration_should_not_be_accessed_by_domain = noClasses()
|
||||
.that().resideInAnyPackage("..domain..")
|
||||
static final ArchRule configuration_should_not_be_accessed_by_modules = noClasses()
|
||||
.that().resideInAnyPackage("..modules..")
|
||||
.should().dependOnClassesThat().resideInAPackage("auth_service.configuration..")
|
||||
.because("Domain logic should not depend on Spring configuration classes.");
|
||||
.because("Module logic should not depend on global Spring configuration classes.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule services_should_be_annotated = classes()
|
||||
@@ -106,17 +106,17 @@ class ArchitectureTest extends AbstractArchitectureTest {
|
||||
// ===================================================================================
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule shared_should_not_depend_on_domains = noClasses()
|
||||
static final ArchRule shared_should_not_depend_on_modules = noClasses()
|
||||
.that().resideInAPackage("auth_service.shared..")
|
||||
.should().dependOnClassesThat().resideInAPackage("auth_service.domain..")
|
||||
.because("Shared classes should be independent of specific domains.");
|
||||
.should().dependOnClassesThat().resideInAPackage("auth_service.modules..")
|
||||
.because("Shared classes should be independent of specific modules.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule controllers_should_be_annotated = classes()
|
||||
.that().resideInAPackage("..controller..")
|
||||
static final ArchRule apis_should_be_annotated = classes()
|
||||
.that().resideInAPackage("..api..")
|
||||
.and().haveSimpleNameEndingWith("Controller")
|
||||
.should().beAnnotatedWith(org.springframework.web.bind.annotation.RestController.class)
|
||||
.orShould().beAnnotatedWith(org.springframework.web.bind.annotation.ControllerAdvice.class)
|
||||
.orShould().beAnnotatedWith(org.springframework.web.bind.annotation.RestControllerAdvice.class)
|
||||
.because("Classes named *Controller should be registered as Spring @RestController or @ControllerAdvice or @RestControllerAdvice beans.");
|
||||
}
|
||||
.because("Classes in 'api' package should be registered as Spring @RestController or @ControllerAdvice or @RestControllerAdvice beans.");
|
||||
}
|
||||
@@ -91,4 +91,4 @@ class JwtServiceTest extends AbstractUnitTest {
|
||||
// Assert
|
||||
assertFalse(isValid);
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
-72
@@ -1,72 +1,72 @@
|
||||
package auth_service.domain.login.controller;
|
||||
|
||||
import auth_service.configuration.security.JwtAuthenticationFilter;
|
||||
import auth_service.domain.login.controller.dto.request.LoginRequest;
|
||||
import auth_service.domain.login.exception.InvalidCredentialsException;
|
||||
import auth_service.domain.login.model.User;
|
||||
import auth_service.domain.login.service.LoginService;
|
||||
import auth_service.shared.test.AbstractWebMvcTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
|
||||
import org.springframework.boot.test.json.JacksonTester;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for LoginController.
|
||||
*/
|
||||
@WebMvcTest(LoginController.class)
|
||||
@AutoConfigureMockMvc(addFilters = false) // Skip security filters for simple controller test
|
||||
@AutoConfigureJsonTesters
|
||||
class LoginControllerTest extends AbstractWebMvcTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockitoBean
|
||||
private LoginService loginService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter; // Needed because it's used in SecurityConfig
|
||||
|
||||
@Autowired
|
||||
private JacksonTester<LoginRequest> loginRequestJson;
|
||||
|
||||
@Test
|
||||
void login_Success() throws Exception {
|
||||
// Arrange
|
||||
var request = new LoginRequest("test@example.com", "password");
|
||||
when(loginService.login(any(User.class))).thenReturn("mock-token");
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(loginRequestJson.write(request).getJson()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.message").value("Login successful"))
|
||||
.andExpect(jsonPath("$.token").value("mock-token"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_Failure() throws Exception {
|
||||
// Arrange
|
||||
var request = new LoginRequest("test@example.com", "wrong-password");
|
||||
when(loginService.login(any(User.class))).thenThrow(new InvalidCredentialsException("Invalid credentials"));
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(loginRequestJson.write(request).getJson()))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
}
|
||||
package auth_service.modules.login.api;
|
||||
|
||||
import auth_service.configuration.security.JwtAuthenticationFilter;
|
||||
import auth_service.modules.login.api.dto.request.LoginRequest;
|
||||
import auth_service.modules.login.exception.InvalidCredentialsException;
|
||||
import auth_service.modules.login.model.User;
|
||||
import auth_service.modules.login.service.LoginService;
|
||||
import auth_service.shared.test.AbstractWebMvcTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
|
||||
import org.springframework.boot.test.json.JacksonTester;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests for LoginController.
|
||||
*/
|
||||
@WebMvcTest(LoginController.class)
|
||||
@AutoConfigureMockMvc(addFilters = false) // Skip security filters for simple controller test
|
||||
@AutoConfigureJsonTesters
|
||||
class LoginControllerTest extends AbstractWebMvcTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockitoBean
|
||||
private LoginService loginService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter; // Needed because it's used in SecurityConfig
|
||||
|
||||
@Autowired
|
||||
private JacksonTester<LoginRequest> loginRequestJson;
|
||||
|
||||
@Test
|
||||
void login_Success() throws Exception {
|
||||
// Arrange
|
||||
var request = new LoginRequest("test@example.com", "password");
|
||||
when(loginService.login(any(User.class))).thenReturn("mock-token");
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(loginRequestJson.write(request).getJson()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.message").value("Login successful"))
|
||||
.andExpect(jsonPath("$.token").value("mock-token"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_Failure() throws Exception {
|
||||
// Arrange
|
||||
var request = new LoginRequest("test@example.com", "wrong-password");
|
||||
when(loginService.login(any(User.class))).thenThrow(new InvalidCredentialsException("Invalid credentials"));
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(loginRequestJson.write(request).getJson()))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
package auth_service.domain.login.persistence;
|
||||
package auth_service.modules.login.persistence;
|
||||
|
||||
import auth_service.domain.login.persistence.entities.MinimalUserEntity;
|
||||
import auth_service.modules.login.persistence.entities.MinimalUserEntity;
|
||||
import auth_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -57,4 +57,4 @@ class MinimalUserRepositoryTest extends AbstractPersistenceTest {
|
||||
var updated = entityManager.find(MinimalUserEntity.class, entity.getId());
|
||||
assertNotNull(updated.getLastLoginDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
+88
-88
@@ -1,88 +1,88 @@
|
||||
package auth_service.domain.login.service;
|
||||
|
||||
import auth_service.domain.login.exception.InvalidCredentialsException;
|
||||
import auth_service.domain.login.exception.UserNotFoundException;
|
||||
import auth_service.domain.login.model.User;
|
||||
import auth_service.domain.login.persistence.MinimalUserRepository;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for LoginService.
|
||||
*/
|
||||
class LoginServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private MinimalUserRepository minimalUserRepository;
|
||||
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private TokenGenerator tokenGenerator;
|
||||
|
||||
@InjectMocks
|
||||
private LoginService loginService;
|
||||
|
||||
private User user;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
user = User.builder()
|
||||
.email("test@example.com")
|
||||
.password("password")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_Success() {
|
||||
// Arrange
|
||||
var dbUser = User.builder()
|
||||
.id(815L)
|
||||
.email("test@example.com")
|
||||
.password("encodedPassword")
|
||||
.build();
|
||||
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.of(dbUser));
|
||||
when(passwordEncoder.matches(user.getPassword(), dbUser.getPassword())).thenReturn(true);
|
||||
when(tokenGenerator.generateToken("815", "test@example.com")).thenReturn("mock-token");
|
||||
|
||||
// Act
|
||||
var result = loginService.login(user);
|
||||
|
||||
// Assert
|
||||
assertEquals("mock-token", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_UserNotFound() {
|
||||
// Arrange
|
||||
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.empty());
|
||||
|
||||
// Act & Assert
|
||||
assertThrows(UserNotFoundException.class, () -> loginService.login(user));
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_InvalidCredentials() {
|
||||
// Arrange
|
||||
var dbUser = User.builder()
|
||||
.email("test@example.com")
|
||||
.password("encodedPassword")
|
||||
.build();
|
||||
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.of(dbUser));
|
||||
when(passwordEncoder.matches(user.getPassword(), dbUser.getPassword())).thenReturn(false);
|
||||
|
||||
// Act & Assert
|
||||
assertThrows(InvalidCredentialsException.class, () -> loginService.login(user));
|
||||
}
|
||||
}
|
||||
package auth_service.modules.login.service;
|
||||
|
||||
import auth_service.modules.login.exception.InvalidCredentialsException;
|
||||
import auth_service.modules.login.exception.UserNotFoundException;
|
||||
import auth_service.modules.login.model.User;
|
||||
import auth_service.modules.login.persistence.MinimalUserRepository;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for LoginService.
|
||||
*/
|
||||
class LoginServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private MinimalUserRepository minimalUserRepository;
|
||||
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private TokenGenerator tokenGenerator;
|
||||
|
||||
@InjectMocks
|
||||
private LoginService loginService;
|
||||
|
||||
private User user;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
user = User.builder()
|
||||
.email("test@example.com")
|
||||
.password("password")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_Success() {
|
||||
// Arrange
|
||||
var dbUser = User.builder()
|
||||
.id(815L)
|
||||
.email("test@example.com")
|
||||
.password("encodedPassword")
|
||||
.build();
|
||||
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.of(dbUser));
|
||||
when(passwordEncoder.matches(user.getPassword(), dbUser.getPassword())).thenReturn(true);
|
||||
when(tokenGenerator.generateToken("815", "test@example.com")).thenReturn("mock-token");
|
||||
|
||||
// Act
|
||||
var result = loginService.login(user);
|
||||
|
||||
// Assert
|
||||
assertEquals("mock-token", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_UserNotFound() {
|
||||
// Arrange
|
||||
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.empty());
|
||||
|
||||
// Act & Assert
|
||||
assertThrows(UserNotFoundException.class, () -> loginService.login(user));
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_InvalidCredentials() {
|
||||
// Arrange
|
||||
var dbUser = User.builder()
|
||||
.email("test@example.com")
|
||||
.password("encodedPassword")
|
||||
.build();
|
||||
when(minimalUserRepository.findByEmail(user.getEmail())).thenReturn(Optional.of(dbUser));
|
||||
when(passwordEncoder.matches(user.getPassword(), dbUser.getPassword())).thenReturn(false);
|
||||
|
||||
// Act & Assert
|
||||
assertThrows(InvalidCredentialsException.class, () -> loginService.login(user));
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
package auth_service.domain.registration.controller;
|
||||
package auth_service.modules.registration.api;
|
||||
|
||||
import auth_service.configuration.security.JwtAuthenticationFilter;
|
||||
import auth_service.configuration.security.JwtService;
|
||||
import auth_service.domain.registration.controller.dto.request.RegistrationRequest;
|
||||
import auth_service.domain.registration.exception.EmailAlreadyInUseException;
|
||||
import auth_service.domain.registration.model.Registration;
|
||||
import auth_service.domain.registration.service.RegistrationService;
|
||||
import auth_service.modules.registration.api.dto.request.RegistrationRequest;
|
||||
import auth_service.modules.registration.exception.EmailAlreadyInUseException;
|
||||
import auth_service.modules.registration.model.Registration;
|
||||
import auth_service.modules.registration.service.RegistrationService;
|
||||
import auth_service.shared.test.AbstractWebMvcTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -91,4 +91,4 @@ class RegistrationControllerTest extends AbstractWebMvcTest {
|
||||
.content(registrationRequestJson.write(request).getJson()))
|
||||
.andExpect(status().isBadRequest()); // Adjust status based on your @ExceptionHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
package auth_service.domain.registration.persistence;
|
||||
package auth_service.modules.registration.persistence;
|
||||
|
||||
import auth_service.domain.registration.model.Registration;
|
||||
import auth_service.domain.registration.persistence.entities.RegisteredUserEntity;
|
||||
import auth_service.modules.registration.model.Registration;
|
||||
import auth_service.modules.registration.persistence.entities.RegisteredUserEntity;
|
||||
import auth_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -75,4 +75,4 @@ class RegisteredUserRepositoryTest extends AbstractPersistenceTest {
|
||||
assertNotNull(saved);
|
||||
assertEquals("save@example.com", saved.getEmail());
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -1,10 +1,10 @@
|
||||
package auth_service.domain.registration.service;
|
||||
package auth_service.modules.registration.service;
|
||||
|
||||
import auth_service.domain.registration.exception.EmailAlreadyInUseException;
|
||||
import auth_service.domain.registration.exception.InvalidInvitationCodeException;
|
||||
import auth_service.domain.registration.exception.SteamIdAlreadyRegisteredException;
|
||||
import auth_service.domain.registration.model.Registration;
|
||||
import auth_service.domain.registration.persistence.RegisteredUserRepository;
|
||||
import auth_service.modules.registration.exception.EmailAlreadyInUseException;
|
||||
import auth_service.modules.registration.exception.InvalidInvitationCodeException;
|
||||
import auth_service.modules.registration.exception.SteamIdAlreadyRegisteredException;
|
||||
import auth_service.modules.registration.model.Registration;
|
||||
import auth_service.modules.registration.persistence.RegisteredUserRepository;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -103,4 +103,4 @@ class RegistrationServiceTest extends AbstractUnitTest {
|
||||
|
||||
verify(registeredUserRepository, never()).save(any());
|
||||
}
|
||||
}
|
||||
}
|
||||
+113
-113
@@ -1,113 +1,113 @@
|
||||
package auth_service.domain.user.controller;
|
||||
|
||||
import auth_service.configuration.security.JwtAuthenticationFilter;
|
||||
import auth_service.configuration.security.JwtService;
|
||||
import auth_service.shared.security.UserPrincipal;
|
||||
import auth_service.domain.user.controller.dto.request.UserSettingsRequest;
|
||||
import auth_service.domain.user.exception.UserNotFoundException;
|
||||
import auth_service.domain.user.model.User;
|
||||
import auth_service.domain.user.model.UserSettings;
|
||||
import auth_service.domain.user.service.UserService;
|
||||
import auth_service.shared.test.AbstractWebMvcTest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
|
||||
import org.springframework.boot.test.json.JacksonTester;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest(UserController.class)
|
||||
@AutoConfigureMockMvc(addFilters = false)
|
||||
@AutoConfigureJsonTesters
|
||||
class UserControllerTest extends AbstractWebMvcTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockitoBean
|
||||
private UserService userService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtService jwtService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
@Autowired
|
||||
private JacksonTester<UserSettingsRequest> userSettingsRequestJson;
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCurrentUserV1_Success() throws Exception {
|
||||
// Arrange
|
||||
var email = "test@example.com";
|
||||
var settings = UserSettings.builder().language("en").theme("dark").build();
|
||||
var user = User.builder().email(email).settings(settings).build();
|
||||
var principal = new UserPrincipal("1", email);
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(principal, null, Collections.emptyList())
|
||||
);
|
||||
when(userService.getUserByEmail(email)).thenReturn(user);
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(get("/api/users/me")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.email").value(email));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCurrentUserV1_NotFound() throws Exception {
|
||||
// Arrange
|
||||
var email = "notfound@example.com";
|
||||
var principal = new UserPrincipal("1", email);
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(principal, null, Collections.emptyList())
|
||||
);
|
||||
when(userService.getUserByEmail(email)).thenThrow(new UserNotFoundException("User not found"));
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(get("/api/users/me")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateUserSettings_Success() throws Exception {
|
||||
// Arrange
|
||||
var email = "test@example.com";
|
||||
var principal = new UserPrincipal("1", email);
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(principal, null, Collections.emptyList())
|
||||
);
|
||||
var request = new UserSettingsRequest(true, "en", 123456789L);
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(put("/api/users/settings")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(userSettingsRequestJson.write(request).getJson()))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(userService).updateUserSettings(eq(1L), eq(123456789L), any());
|
||||
}
|
||||
}
|
||||
package auth_service.modules.user.api;
|
||||
|
||||
import auth_service.configuration.security.JwtAuthenticationFilter;
|
||||
import auth_service.configuration.security.JwtService;
|
||||
import auth_service.shared.security.UserPrincipal;
|
||||
import auth_service.modules.user.api.dto.request.UserSettingsRequest;
|
||||
import auth_service.modules.user.exception.UserNotFoundException;
|
||||
import auth_service.modules.user.model.User;
|
||||
import auth_service.modules.user.model.UserSettings;
|
||||
import auth_service.modules.user.service.UserService;
|
||||
import auth_service.shared.test.AbstractWebMvcTest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
|
||||
import org.springframework.boot.test.json.JacksonTester;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest(UserController.class)
|
||||
@AutoConfigureMockMvc(addFilters = false)
|
||||
@AutoConfigureJsonTesters
|
||||
class UserControllerTest extends AbstractWebMvcTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockitoBean
|
||||
private UserService userService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtService jwtService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
@Autowired
|
||||
private JacksonTester<UserSettingsRequest> userSettingsRequestJson;
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCurrentUserV1_Success() throws Exception {
|
||||
// Arrange
|
||||
var email = "test@example.com";
|
||||
var settings = UserSettings.builder().language("en").theme("dark").build();
|
||||
var user = User.builder().email(email).settings(settings).build();
|
||||
var principal = new UserPrincipal("1", email);
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(principal, null, Collections.emptyList())
|
||||
);
|
||||
when(userService.getUserByEmail(email)).thenReturn(user);
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(get("/api/users/me")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.email").value(email));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCurrentUserV1_NotFound() throws Exception {
|
||||
// Arrange
|
||||
var email = "notfound@example.com";
|
||||
var principal = new UserPrincipal("1", email);
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(principal, null, Collections.emptyList())
|
||||
);
|
||||
when(userService.getUserByEmail(email)).thenThrow(new UserNotFoundException("User not found"));
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(get("/api/users/me")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateUserSettings_Success() throws Exception {
|
||||
// Arrange
|
||||
var email = "test@example.com";
|
||||
var principal = new UserPrincipal("1", email);
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(principal, null, Collections.emptyList())
|
||||
);
|
||||
var request = new UserSettingsRequest(true, "en", 123456789L);
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(put("/api/users/settings")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(userSettingsRequestJson.write(request).getJson()))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(userService).updateUserSettings(eq(1L), eq(123456789L), any());
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
package auth_service.domain.user.persistence;
|
||||
package auth_service.modules.user.persistence;
|
||||
|
||||
import auth_service.domain.user.model.UserSettings;
|
||||
import auth_service.domain.user.persistence.entities.UserEntity;
|
||||
import auth_service.modules.user.model.UserSettings;
|
||||
import auth_service.modules.user.persistence.entities.UserEntity;
|
||||
import auth_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -73,4 +73,4 @@ class UserRepositoryTest extends AbstractPersistenceTest {
|
||||
assertNotNull(updatedUser.getSettings());
|
||||
assertEquals("de", updatedUser.getSettings().getLanguage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
-67
@@ -1,67 +1,67 @@
|
||||
package auth_service.domain.user.service;
|
||||
|
||||
import auth_service.domain.user.exception.UserNotFoundException;
|
||||
import auth_service.domain.user.model.User;
|
||||
import auth_service.domain.user.model.UserSettings;
|
||||
import auth_service.domain.user.persistence.UserRepository;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Tests for UserService.
|
||||
*/
|
||||
class UserServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private UserRepository userRepository;
|
||||
|
||||
@InjectMocks
|
||||
private UserService userService;
|
||||
|
||||
@Test
|
||||
void getUserByEmail_Success() {
|
||||
// Arrange
|
||||
var email = "test@example.com";
|
||||
var user = User.builder().email(email).build();
|
||||
when(userRepository.findByEmail(email)).thenReturn(Optional.of(user));
|
||||
|
||||
// Act
|
||||
var result = userService.getUserByEmail(email);
|
||||
|
||||
// Assert
|
||||
assertEquals(user, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserByEmail_NotFound() {
|
||||
// Arrange
|
||||
var email = "notfound@example.com";
|
||||
when(userRepository.findByEmail(email)).thenReturn(Optional.empty());
|
||||
|
||||
// Act & Assert
|
||||
assertThrows(UserNotFoundException.class, () -> userService.getUserByEmail(email));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateUserSettings_Success() {
|
||||
// Arrange
|
||||
long userId = 1L;
|
||||
long steamId = 123456789L;
|
||||
var userSettings = UserSettings.builder().language("en").build();
|
||||
when(userRepository.updateSettings(userId, steamId, userSettings)).thenReturn(true);
|
||||
|
||||
// Act
|
||||
userService.updateUserSettings(userId, steamId, userSettings);
|
||||
|
||||
// Assert
|
||||
verify(userRepository, times(1)).updateSettings(userId, steamId, userSettings);
|
||||
}
|
||||
}
|
||||
package auth_service.modules.user.service;
|
||||
|
||||
import auth_service.modules.user.exception.UserNotFoundException;
|
||||
import auth_service.modules.user.model.User;
|
||||
import auth_service.modules.user.model.UserSettings;
|
||||
import auth_service.modules.user.persistence.UserRepository;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Tests for UserService.
|
||||
*/
|
||||
class UserServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private UserRepository userRepository;
|
||||
|
||||
@InjectMocks
|
||||
private UserService userService;
|
||||
|
||||
@Test
|
||||
void getUserByEmail_Success() {
|
||||
// Arrange
|
||||
var email = "test@example.com";
|
||||
var user = User.builder().email(email).build();
|
||||
when(userRepository.findByEmail(email)).thenReturn(Optional.of(user));
|
||||
|
||||
// Act
|
||||
var result = userService.getUserByEmail(email);
|
||||
|
||||
// Assert
|
||||
assertEquals(user, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserByEmail_NotFound() {
|
||||
// Arrange
|
||||
var email = "notfound@example.com";
|
||||
when(userRepository.findByEmail(email)).thenReturn(Optional.empty());
|
||||
|
||||
// Act & Assert
|
||||
assertThrows(UserNotFoundException.class, () -> userService.getUserByEmail(email));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateUserSettings_Success() {
|
||||
// Arrange
|
||||
long userId = 1L;
|
||||
long steamId = 123456789L;
|
||||
var userSettings = UserSettings.builder().language("en").build();
|
||||
when(userRepository.updateSettings(userId, steamId, userSettings)).thenReturn(true);
|
||||
|
||||
// Act
|
||||
userService.updateUserSettings(userId, steamId, userSettings);
|
||||
|
||||
// Assert
|
||||
verify(userRepository, times(1)).updateSettings(userId, steamId, userSettings);
|
||||
}
|
||||
}
|
||||
@@ -8,3 +8,4 @@ import org.junit.jupiter.api.Tag;
|
||||
@Tag("ArchitectureTest")
|
||||
public abstract class AbstractArchitectureTest {
|
||||
}
|
||||
|
||||
@@ -22,3 +22,4 @@ public abstract class AbstractIntegrationTest {
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17-alpine");
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ public abstract class AbstractPersistenceTest {
|
||||
@Container
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17-alpine");
|
||||
}
|
||||
}
|
||||
@@ -12,3 +12,4 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public abstract class AbstractUnitTest {
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@ import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
@Tag("WebMvcTest")
|
||||
@WebMvcTest
|
||||
public abstract class AbstractWebMvcTest {
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user