Public Access
Added new tests fixed some problem
This commit is contained in:
1 parent
14a4ccfb87
commit
20402eb7c4
32 files changed
+11119
-77
No files matched your search
+10713
File diff suppressed because it is too large.
Load diff
@@ -105,6 +105,11 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package auth_service.configuration.security;
|
||||
|
||||
import auth_service.domain.login.service.TokenGenerator;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -12,7 +13,7 @@ import java.util.Date;
|
||||
* Service responsible for generating and validating JSON Web Tokens (JWT).
|
||||
*/
|
||||
@Service
|
||||
public class JwtService {
|
||||
public class JwtService implements TokenGenerator {
|
||||
|
||||
// Token validity: 24 hours in milliseconds
|
||||
private static final long JWT_EXPIRATION_MS = 86400000;
|
||||
@@ -24,10 +25,10 @@ public class JwtService {
|
||||
|
||||
/**
|
||||
* Generates a secure JWT for the authenticated user.
|
||||
* * @param user The authenticated user entity
|
||||
*
|
||||
* @return A signed JWT string
|
||||
*/
|
||||
@Override
|
||||
public String generateToken(String userId, String email) {
|
||||
return Jwts.builder()
|
||||
.subject(email)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package auth_service.domain.login.controller;
|
||||
|
||||
import auth_service.configuration.security.JwtService;
|
||||
import auth_service.domain.login.controller.dto.request.LoginRequest;
|
||||
import auth_service.domain.login.controller.dto.response.LoginResponse;
|
||||
import auth_service.domain.login.controller.mapper.ApiMapper;
|
||||
@@ -22,12 +21,11 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class LoginController {
|
||||
|
||||
private final LoginService loginService;
|
||||
private final JwtService jwtService;
|
||||
|
||||
/**
|
||||
* Authenticates a user based on email and password.
|
||||
* * @param request The login credentials
|
||||
*
|
||||
* @param request The login credentials
|
||||
* @return HTTP 200 on success, HTTP 401 on failure
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
@@ -35,8 +33,7 @@ public class LoginController {
|
||||
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
|
||||
|
||||
var user = ApiMapper.toModel(request);
|
||||
var authenticatedUser = loginService.login(user);
|
||||
var token = jwtService.generateToken(authenticatedUser.getId() + "", authenticatedUser.getEmail());
|
||||
var token = loginService.login(user);
|
||||
return ResponseEntity.ok(new LoginResponse("Login successful", token));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package auth_service.domain.login.controller;
|
||||
|
||||
import auth_service.domain.login.controller.dto.response.ErrorResponse;
|
||||
import auth_service.shared.controller.dto.response.ErrorResponse;
|
||||
import auth_service.domain.login.exception.InvalidCredentialsException;
|
||||
import auth_service.domain.login.exception.UserNotFoundException;
|
||||
import lombok.NonNull;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package auth_service.domain.login.controller.dto.response;
|
||||
|
||||
public record ErrorResponse(String code, String message) {
|
||||
}
|
||||
@@ -15,19 +15,21 @@ import org.springframework.stereotype.Service;
|
||||
public class LoginService {
|
||||
private final MinimalUserRepository minimalUserRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final TokenGenerator tokenGenerator;
|
||||
|
||||
/**
|
||||
* Authenticates a user based on email and raw password.
|
||||
* Authenticates a user and returns a token.
|
||||
*
|
||||
* @return The authenticated User model
|
||||
* @return The generated token
|
||||
*/
|
||||
public User login(User userToLogin) {
|
||||
var foundUser = minimalUserRepository.findByEmail(userToLogin.getEmail()).orElseThrow(() -> new UserNotFoundException("User not found with given email"));
|
||||
public String login(User userToLogin) {
|
||||
var foundUser = minimalUserRepository.findByEmail(userToLogin.getEmail())
|
||||
.orElseThrow(() -> new UserNotFoundException("User not found with given email"));
|
||||
var loginSuccessful = passwordEncoder.matches(userToLogin.getPassword(), foundUser.getPassword());
|
||||
if (!loginSuccessful) {
|
||||
throw new InvalidCredentialsException("Invalid credentials");
|
||||
}
|
||||
minimalUserRepository.updateLoginDate(foundUser.getId());
|
||||
return foundUser;
|
||||
return tokenGenerator.generateToken(String.valueOf(foundUser.getId()), foundUser.getEmail());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package auth_service.domain.login.service;
|
||||
|
||||
/**
|
||||
* Port interface for token generation.
|
||||
* Decouples the login service from specific token implementations (e.g. JWT).
|
||||
*/
|
||||
public interface TokenGenerator {
|
||||
/**
|
||||
* Generates a token for the given user.
|
||||
*
|
||||
* @param userId The unique identifier of the user.
|
||||
* @param email The email address of the user.
|
||||
* @return The generated token string.
|
||||
*/
|
||||
String generateToken(String userId, String email);
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package auth_service.domain.registration.controller;
|
||||
|
||||
import auth_service.domain.registration.controller.dto.response.ErrorResponse;
|
||||
import auth_service.shared.controller.dto.response.ErrorResponse;
|
||||
import auth_service.domain.registration.exception.EmailAlreadyInUseException;
|
||||
import auth_service.domain.registration.exception.InvalidInvitationCodeException;
|
||||
import auth_service.domain.registration.exception.SteamIdAlreadyRegisteredException;
|
||||
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
package auth_service.domain.registration.controller.dto.response;
|
||||
|
||||
public record ErrorResponse(String code, String message) {
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
package auth_service.domain.registration.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CodeValidationService {
|
||||
|
||||
private static final String RANDOM_INVITATION_CODE = "test-invite-code";
|
||||
@Value("${auth.registration.invitation-code}")
|
||||
private String invitationCode;
|
||||
|
||||
public boolean isCodeValid(String code) {
|
||||
if (code == null || code.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return code.equals(RANDOM_INVITATION_CODE);
|
||||
return code.equals(invitationCode);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package auth_service.domain.user.controller;
|
||||
|
||||
import auth_service.domain.user.controller.dto.response.ErrorResponse;
|
||||
import auth_service.shared.controller.dto.response.ErrorResponse;
|
||||
import auth_service.domain.user.exception.UserNotFoundException;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package auth_service.domain.user.controller.dto.response;
|
||||
|
||||
public record ErrorResponse(String code, String message) {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package auth_service.shared.controller.dto.response;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
/**
|
||||
* Shared error response record for all domains.
|
||||
*
|
||||
* @param code A machine-readable error code.
|
||||
* @param message A human-readable error message.
|
||||
*/
|
||||
public record ErrorResponse(@NonNull String code, @NonNull String message) {
|
||||
}
|
||||
@@ -51,3 +51,8 @@ app:
|
||||
cors:
|
||||
# Production default: strictly allow only the frontend domain
|
||||
allowed-origins: "https://tbp.andreas-dahm.eu"
|
||||
|
||||
# Registration settings
|
||||
auth:
|
||||
registration:
|
||||
invitation-code: ${AUTH_INVITATION_CODE}
|
||||
@@ -1,25 +1,9 @@
|
||||
package auth_service;
|
||||
|
||||
import auth_service.shared.test.AbstractIntegrationTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
@SpringBootTest
|
||||
@Testcontainers
|
||||
class AuthServiceApplicationTests {
|
||||
|
||||
/**
|
||||
* Define the PostgreSQL container.
|
||||
*
|
||||
* @ServiceConnection automatically configures the application properties
|
||||
* (URL, username, password) for this specific container.
|
||||
*/
|
||||
@Container
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17.9");
|
||||
class AuthServiceApplicationTests extends AbstractIntegrationTest {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package auth_service.architecture;
|
||||
|
||||
import auth_service.shared.test.AbstractArchitectureTest;
|
||||
import com.tngtech.archunit.core.importer.ImportOption;
|
||||
import com.tngtech.archunit.junit.AnalyzeClasses;
|
||||
import com.tngtech.archunit.junit.ArchTest;
|
||||
@@ -14,7 +15,7 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
||||
* Analyzes all classes in the 'auth_service' package, ignoring test classes.
|
||||
*/
|
||||
@AnalyzeClasses(packages = "auth_service", importOptions = ImportOption.DoNotIncludeTests.class)
|
||||
class ArchitectureTest {
|
||||
class ArchitectureTest extends AbstractArchitectureTest {
|
||||
|
||||
// ===================================================================================
|
||||
// 1. DOMAIN INDEPENDENCE (Slices)
|
||||
@@ -75,6 +76,24 @@ class ArchitectureTest {
|
||||
.should().dependOnClassesThat().resideInAPackage("..persistence..")
|
||||
.because("Controllers must delegate to Services and should not access Persistence directly.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule persistence_should_not_depend_on_controllers = noClasses()
|
||||
.that().resideInAPackage("..persistence..")
|
||||
.should().dependOnClassesThat().resideInAPackage("..controller..")
|
||||
.because("Persistence layer must be independent of the Web/Controller layer.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule exceptions_should_be_isolated = noClasses()
|
||||
.that().resideInAPackage("..exception..")
|
||||
.should().dependOnClassesThat().resideInAnyPackage("..controller..", "..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..")
|
||||
.should().dependOnClassesThat().resideInAPackage("auth_service.configuration..")
|
||||
.because("Domain logic should not depend on Spring configuration classes.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule services_should_be_annotated = classes()
|
||||
.that().resideInAPackage("..service..")
|
||||
@@ -82,6 +101,16 @@ class ArchitectureTest {
|
||||
.should().beAnnotatedWith(org.springframework.stereotype.Service.class)
|
||||
.because("Classes named *Service should be registered as Spring @Service beans.");
|
||||
|
||||
// ===================================================================================
|
||||
// 5. SHARED PACKAGE RULES
|
||||
// ===================================================================================
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule shared_should_not_depend_on_domains = noClasses()
|
||||
.that().resideInAPackage("auth_service.shared..")
|
||||
.should().dependOnClassesThat().resideInAPackage("auth_service.domain..")
|
||||
.because("Shared classes should be independent of specific domains.");
|
||||
|
||||
@ArchTest
|
||||
static final ArchRule controllers_should_be_annotated = classes()
|
||||
.that().resideInAPackage("..controller..")
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package auth_service.configuration.security;
|
||||
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -12,8 +11,7 @@ import static org.mockito.Mockito.when;
|
||||
/**
|
||||
* Tests for JwtService.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class JwtServiceTest {
|
||||
class JwtServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private JwtConfig jwtConfig;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package auth_service.domain.login.controller;
|
||||
|
||||
import auth_service.configuration.security.JwtAuthenticationFilter;
|
||||
import auth_service.configuration.security.JwtService;
|
||||
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;
|
||||
@@ -28,7 +28,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@WebMvcTest(LoginController.class)
|
||||
@AutoConfigureMockMvc(addFilters = false) // Skip security filters for simple controller test
|
||||
@AutoConfigureJsonTesters
|
||||
class LoginControllerTest {
|
||||
class LoginControllerTest extends AbstractWebMvcTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
@@ -36,9 +36,6 @@ class LoginControllerTest {
|
||||
@MockitoBean
|
||||
private LoginService loginService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtService jwtService;
|
||||
|
||||
@MockitoBean
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter; // Needed because it's used in SecurityConfig
|
||||
|
||||
@@ -49,9 +46,7 @@ class LoginControllerTest {
|
||||
void login_Success() throws Exception {
|
||||
// Arrange
|
||||
var request = new LoginRequest("test@example.com", "password");
|
||||
var authenticatedUser = User.builder().id(815L).email("test@example.com").build();
|
||||
when(loginService.login(any(User.class))).thenReturn(authenticatedUser);
|
||||
when(jwtService.generateToken("815", "test@example.com")).thenReturn("mock-token");
|
||||
when(loginService.login(any(User.class))).thenReturn("mock-token");
|
||||
|
||||
// Act & Assert
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package auth_service.domain.login.persistence;
|
||||
|
||||
import auth_service.domain.login.persistence.entities.MinimalUserEntity;
|
||||
import auth_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@Import(MinimalUserRepositoryImpl.class)
|
||||
class MinimalUserRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Autowired
|
||||
private MinimalUserRepository minimalUserRepository;
|
||||
|
||||
@Autowired
|
||||
private TestEntityManager entityManager;
|
||||
|
||||
@Test
|
||||
void findByEmail_Success() {
|
||||
// Arrange
|
||||
var email = "minimal@example.com";
|
||||
var entity = MinimalUserEntity.builder()
|
||||
.email(email)
|
||||
.password("password")
|
||||
.enabled(true)
|
||||
.build();
|
||||
entityManager.persist(entity);
|
||||
entityManager.flush();
|
||||
|
||||
// Act
|
||||
var result = minimalUserRepository.findByEmail(email);
|
||||
|
||||
// Assert
|
||||
assertTrue(result.isPresent());
|
||||
assertEquals(email, result.get().getEmail());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateLoginDate_Success() {
|
||||
// Arrange
|
||||
var entity = MinimalUserEntity.builder()
|
||||
.email("login@example.com")
|
||||
.password("password")
|
||||
.enabled(true)
|
||||
.build();
|
||||
entity = entityManager.persist(entity);
|
||||
entityManager.flush();
|
||||
|
||||
// Act
|
||||
minimalUserRepository.updateLoginDate(entity.getId());
|
||||
entityManager.clear(); // Clear cache to force reload from DB
|
||||
|
||||
// Assert
|
||||
var updated = entityManager.find(MinimalUserEntity.class, entity.getId());
|
||||
assertNotNull(updated.getLastLoginDate());
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,11 @@ 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.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -21,8 +20,7 @@ import static org.mockito.Mockito.when;
|
||||
/**
|
||||
* Tests for LoginService.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LoginServiceTest {
|
||||
class LoginServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private MinimalUserRepository minimalUserRepository;
|
||||
@@ -30,6 +28,9 @@ class LoginServiceTest {
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private TokenGenerator tokenGenerator;
|
||||
|
||||
@InjectMocks
|
||||
private LoginService loginService;
|
||||
|
||||
@@ -47,17 +48,19 @@ class LoginServiceTest {
|
||||
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(dbUser, result);
|
||||
assertEquals("mock-token", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ import auth_service.domain.registration.controller.dto.request.RegistrationReque
|
||||
import auth_service.domain.registration.exception.EmailAlreadyInUseException;
|
||||
import auth_service.domain.registration.model.Registration;
|
||||
import auth_service.domain.registration.service.RegistrationService;
|
||||
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;
|
||||
@@ -28,7 +29,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@WebMvcTest(RegistrationController.class)
|
||||
@AutoConfigureMockMvc(addFilters = false) // Skip security filters for simple controller test
|
||||
@AutoConfigureJsonTesters
|
||||
class RegistrationControllerTest {
|
||||
class RegistrationControllerTest extends AbstractWebMvcTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package auth_service.domain.registration.persistence;
|
||||
|
||||
import auth_service.domain.registration.model.Registration;
|
||||
import auth_service.domain.registration.persistence.entities.RegisteredUserEntity;
|
||||
import auth_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@Import(RegisteredUserRepositoryImpl.class)
|
||||
class RegisteredUserRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Autowired
|
||||
private RegisteredUserRepository registeredUserRepository;
|
||||
|
||||
@Autowired
|
||||
private TestEntityManager entityManager;
|
||||
|
||||
@Test
|
||||
void existsByEmail_Success() {
|
||||
// Arrange
|
||||
var email = "exists@example.com";
|
||||
var entity = RegisteredUserEntity.builder()
|
||||
.email(email)
|
||||
.password("password")
|
||||
.enabled(true)
|
||||
.steamId(111L)
|
||||
.registrationDate(java.time.LocalDateTime.now())
|
||||
.build();
|
||||
entityManager.persist(entity);
|
||||
entityManager.flush();
|
||||
|
||||
// Act & Assert
|
||||
assertTrue(registeredUserRepository.existsByEmail(email));
|
||||
assertFalse(registeredUserRepository.existsByEmail("other@example.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsBySteamId_Success() {
|
||||
// Arrange
|
||||
var steamId = 222L;
|
||||
var entity = RegisteredUserEntity.builder()
|
||||
.email("steam@example.com")
|
||||
.password("password")
|
||||
.enabled(true)
|
||||
.steamId(steamId)
|
||||
.registrationDate(java.time.LocalDateTime.now())
|
||||
.build();
|
||||
entityManager.persist(entity);
|
||||
entityManager.flush();
|
||||
|
||||
// Act & Assert
|
||||
assertTrue(registeredUserRepository.existsBySteamId(steamId));
|
||||
assertFalse(registeredUserRepository.existsBySteamId(333L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void save_Success() {
|
||||
// Arrange
|
||||
var registration = Registration.builder()
|
||||
.email("save@example.com")
|
||||
.encryptedPassword("hashed")
|
||||
.steamId(444L)
|
||||
.build();
|
||||
|
||||
// Act
|
||||
long id = registeredUserRepository.save(registration);
|
||||
|
||||
// Assert
|
||||
assertTrue(id > 0);
|
||||
var saved = entityManager.find(RegisteredUserEntity.class, id);
|
||||
assertNotNull(saved);
|
||||
assertEquals("save@example.com", saved.getEmail());
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,11 @@ 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.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -21,8 +20,7 @@ import static org.mockito.Mockito.*;
|
||||
/**
|
||||
* Tests for RegistrationService.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RegistrationServiceTest {
|
||||
class RegistrationServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private CodeValidationService codeValidationService;
|
||||
|
||||
@@ -8,6 +8,7 @@ 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;
|
||||
@@ -34,7 +35,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@WebMvcTest(UserController.class)
|
||||
@AutoConfigureMockMvc(addFilters = false)
|
||||
@AutoConfigureJsonTesters
|
||||
class UserControllerTest {
|
||||
class UserControllerTest extends AbstractWebMvcTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package auth_service.domain.user.persistence;
|
||||
|
||||
import auth_service.domain.user.model.UserSettings;
|
||||
import auth_service.domain.user.persistence.entities.UserEntity;
|
||||
import auth_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@Import(UserRepositoryImpl.class)
|
||||
class UserRepositoryTest extends AbstractPersistenceTest {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private TestEntityManager entityManager;
|
||||
|
||||
@Test
|
||||
void findByEmail_Success() {
|
||||
// Arrange
|
||||
var email = "test@example.com";
|
||||
var userEntity = UserEntity.builder()
|
||||
.email(email)
|
||||
.password("password")
|
||||
.enabled(true)
|
||||
.steamId(123456L)
|
||||
.registrationDate(LocalDateTime.now())
|
||||
.build();
|
||||
entityManager.persist(userEntity);
|
||||
entityManager.flush();
|
||||
|
||||
// Act
|
||||
var result = userRepository.findByEmail(email);
|
||||
|
||||
// Assert
|
||||
assertTrue(result.isPresent());
|
||||
assertEquals(email, result.get().getEmail());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateSettings_Success() {
|
||||
// Arrange
|
||||
var email = "settings@example.com";
|
||||
var userEntity = UserEntity.builder()
|
||||
.email(email)
|
||||
.password("password")
|
||||
.enabled(true)
|
||||
.steamId(123456L)
|
||||
.registrationDate(LocalDateTime.now())
|
||||
.build();
|
||||
userEntity = entityManager.persist(userEntity);
|
||||
entityManager.flush();
|
||||
|
||||
var settings = UserSettings.builder()
|
||||
.language("de")
|
||||
.theme("dark")
|
||||
.build();
|
||||
|
||||
// Act
|
||||
var updated = userRepository.updateSettings(userEntity.getId(), 654321L, settings);
|
||||
|
||||
// Assert
|
||||
assertTrue(updated);
|
||||
var updatedUser = entityManager.find(UserEntity.class, userEntity.getId());
|
||||
assertEquals(654321L, updatedUser.getSteamId());
|
||||
assertNotNull(updatedUser.getSettings());
|
||||
assertEquals("de", updatedUser.getSettings().getLanguage());
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,10 @@ 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.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -19,8 +18,7 @@ import static org.mockito.Mockito.*;
|
||||
/**
|
||||
* Tests for UserService.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class UserServiceTest {
|
||||
class UserServiceTest extends AbstractUnitTest {
|
||||
|
||||
@Mock
|
||||
private UserRepository userRepository;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package auth_service.shared.test;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
|
||||
/**
|
||||
* Base class for ArchUnit tests.
|
||||
*/
|
||||
@Tag("ArchitectureTest")
|
||||
public abstract class AbstractArchitectureTest {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package auth_service.shared.test;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
/**
|
||||
* Base class for integration tests.
|
||||
* Full Spring context with Testcontainers.
|
||||
*/
|
||||
@Tag("IntegrationTest")
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@Testcontainers
|
||||
public abstract class AbstractIntegrationTest {
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17-alpine");
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package auth_service.shared.test;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
/**
|
||||
* Base class for persistence tests.
|
||||
* Slices only the persistence layer with Testcontainers.
|
||||
*/
|
||||
@Tag("PersistenceTest")
|
||||
@DataJpaTest
|
||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
||||
@Testcontainers
|
||||
public abstract class AbstractPersistenceTest {
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17-alpine");
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package auth_service.shared.test;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
* Base class for unit tests.
|
||||
* Isolated from Spring context.
|
||||
*/
|
||||
@Tag("UnitTest")
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public abstract class AbstractUnitTest {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package auth_service.shared.test;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
|
||||
/**
|
||||
* Base class for WebMvc tests.
|
||||
* Slices the web layer.
|
||||
*/
|
||||
@Tag("WebMvcTest")
|
||||
@WebMvcTest
|
||||
public abstract class AbstractWebMvcTest {
|
||||
}
|
||||
Reference in new issue
Block a user