Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
- **Tests**: Application and territory seed filters assert a smaller result than the unfiltered list. `internal` on territory 2 omits `SITMUN - Externa protegida`. `internal` on application 5 returns only `Provincia A` ([#312](https://github.com/sitmun/sitmun-backend-core/issues/312)).
- **Tests**: A JDBC URL `jdbc:h2:mem:testdb;MODE=NOT_A_MODE` is rejected with an SQLException that names the unknown mode. `POST /api/connections/test` returns HTTP 400 for that URL. `GET /api/connections/{id}/test` no longer repeats the same rejection ([#314](https://github.com/sitmun/sitmun-backend-core/issues/314)).
- **Tests**: Database connection, role, territory, territory group type, and user repository tests use MockMvc on the shared context. They no longer boot an embedded server ([#316](https://github.com/sitmun/sitmun-backend-core/issues/316)).
- **Tests**: `UserChecksServiceTest` calls `getWarnings` without a Spring context. `JsonWebTokenServiceTest` loads only `JsonWebTokenService` with a fixed clock. `SpatialReferenceSystemTest`, `UserPositionBusinessLogicTest`, and `UserPositionRepositoryDataRestTest` reuse an existing suite context. Password reset, MIA render security, language change, task literal enrollment, and database connection tests name why their context stays unique ([#315](https://github.com/sitmun/sitmun-backend-core/issues/315)).

### Security

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
import org.sitmun.domain.database.DatabaseConnection;
import org.sitmun.domain.database.DatabaseConnectionRepository;
import org.sitmun.test.BaseTest;
import org.sitmun.test.UniqueContext;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.bean.override.mockito.MockitoBean;

@DisplayName("Database connection controller test")
@UniqueContext(
"The connection repository is mocked so GET test can load a driver class the code list would reject on insert.")
class DatabaseConnectionControllerTest extends BaseTest {

@MockitoBean private DatabaseConnectionRepository repository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
import org.sitmun.administration.dto.MissingTranslationDto;
import org.sitmun.administration.service.DefaultLanguageChangeService;
import org.sitmun.test.BaseTest;
import org.sitmun.test.UniqueContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

@AutoConfigureMockMvc
@UniqueContext(
"The language-change service is mocked so preview and apply return a fixed body or a conflict without changing the default language.")
class DefaultLanguageChangeControllerTest extends BaseTest {

@Autowired private MockMvc mockMvc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
import org.sitmun.infrastructure.persistence.type.i18n.LiteralTranslationValueRepository;
import org.sitmun.test.BaseTest;
import org.sitmun.test.URIConstants;
import org.sitmun.test.UniqueContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import org.springframework.transaction.annotation.Transactional;

@DisplayName("Task Data REST literal enrollment")
@UniqueContext(
"The ensure service is a spy that throws for one create and runs the real enroll path for the other.")
class TaskLiteralEnrollmentDataRestTest extends BaseTest {

@Autowired private TaskRepository taskRepository;
Expand Down
65 changes: 36 additions & 29 deletions src/test/java/org/sitmun/domain/user/UserChecksServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,55 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.sitmun.domain.territory.Territory;
import org.sitmun.domain.user.configuration.UserConfiguration;
import org.sitmun.domain.user.configuration.UserConfigurationRepository;
import org.sitmun.domain.user.position.UserPosition;
import org.sitmun.domain.user.position.UserPositionRepository;
import org.sitmun.infrastructure.security.core.SecurityConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

@SpringBootTest
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@DisplayName("UserChecksService Test")
class UserChecksServiceTest {

@MockitoBean private UserConfigurationRepository userConfigurationRepository;
@Mock private UserConfigurationRepository userConfigurationRepository;

@MockitoBean private UserPositionRepository userPositionRepository;
@Mock private UserPositionRepository userPositionRepository;

@Autowired private UserChecksService userChecksService;
@InjectMocks private UserChecksService userChecksService;

@BeforeEach
void authenticateAsAdmin() {
authenticate("ADMIN");
}

@AfterEach
void clearAuthentication() {
SecurityContextHolder.clearContext();
}

private static void authenticate(String... roles) {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
SecurityContextHolder.getContext()
.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "n/a", authorities));
}

private static User mockCheckableUser(String username, boolean passwordSet) {
User user = mock(User.class);
Expand All @@ -41,10 +68,9 @@ private static User mockCheckableUser(String username, boolean passwordSet) {
}

@Test
@WithMockUser(roles = {"USER", "PUBLIC", "PROXY"})
@DisplayName("When user is not admin, getWarnings returns null")
void getWarningsWhenUserIsNotAdminReturnsNull() {
// Arrange
authenticate("USER", "PUBLIC", "PROXY");
User user = mock(User.class);

// Act
Expand All @@ -56,7 +82,6 @@ void getWarningsWhenUserIsNotAdminReturnsNull() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName(
"When user is admin, getWarnings returns a warning if any position is missing name or organization")
void getWarningsWhenPositionDetailsAreMissingAddsWarning() {
Expand Down Expand Up @@ -89,7 +114,6 @@ void getWarningsWhenPositionDetailsAreMissingAddsWarning() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName(
"When user is admin, getWarnings returns a warning if the user has no positions for a territory in an user configuration")
void getWarningsWhenRoleWithoutPositionAddsWarning() {
Expand All @@ -113,7 +137,6 @@ void getWarningsWhenRoleWithoutPositionAddsWarning() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName(
"When user is admin, getWarnings returns a warning if the user has no user configuration")
void getWarningsWhenNoUserConfigurationPresentAddsWarning() {
Expand All @@ -131,7 +154,6 @@ void getWarningsWhenNoUserConfigurationPresentAddsWarning() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When user has no password, no-password warning is added")
void getWarningsWhenNoPasswordAddsWarning() {
User user = mockCheckableUser("testUser", false);
Expand All @@ -146,7 +168,6 @@ void getWarningsWhenNoPasswordAddsWarning() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When built-in admin user has no passwordSet, no-password warning is skipped")
void getWarningsWhenBuiltInAdminSkipsNoPasswordWarning() {
User user = mockCheckableUser("admin", false);
Expand All @@ -161,7 +182,6 @@ void getWarningsWhenBuiltInAdminSkipsNoPasswordWarning() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When built-in admin user has no roles, no-roles warning is skipped")
void getWarningsWhenBuiltInAdminSkipsNoRolesWarning() {
User user = mockCheckableUser("admin", true);
Expand All @@ -176,7 +196,6 @@ void getWarningsWhenBuiltInAdminSkipsNoRolesWarning() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When built-in admin has roles without positions, position warnings are skipped")
void getWarningsWhenBuiltInAdminSkipsRoleWithoutPositionWarning() {
User user = mockCheckableUser("admin", true);
Expand All @@ -196,7 +215,6 @@ void getWarningsWhenBuiltInAdminSkipsRoleWithoutPositionWarning() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When user is public user, role and position checks are skipped")
void getWarningsWhenPublicUserSkipsPositionChecks() {
// Arrange
Expand All @@ -215,7 +233,6 @@ void getWarningsWhenPublicUserSkipsPositionChecks() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When user is public user, enforce position checks are skipped")
void getWarningsWhenPublicUserSkipsEnforcePositionChecks() {
// Arrange
Expand All @@ -239,28 +256,24 @@ void getWarningsWhenPublicUserSkipsEnforcePositionChecks() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When position has blank organization, warning is added")
void getWarningsWhenPositionHasBlankOrganizationAddsWarning() {
assertPositionWarningWhen("Name", " ");
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When position has blank name, warning is added")
void getWarningsWhenPositionHasBlankNameAddsWarning() {
assertPositionWarningWhen("", "Org");
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When position has blank email only, no position-details warning")
void getWarningsWhenPositionHasBlankEmailOnlyNoPositionWarning() {
assertNoPositionDetailsWarningWhen("Name", "Org", null, "");
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When position has blank type only, no position-details warning")
void getWarningsWhenPositionHasBlankTypeOnlyNoPositionWarning() {
assertNoPositionDetailsWarningWhen("Name", "Org", "email@example.com", null);
Expand Down Expand Up @@ -313,7 +326,6 @@ private void assertNoPositionDetailsWarningWhen(
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When user has multiple issues, multiple warnings are returned")
void getWarningsWhenMultipleIssuesReturnsMultipleWarnings() {
// Arrange
Expand Down Expand Up @@ -349,7 +361,6 @@ void getWarningsWhenMultipleIssuesReturnsMultipleWarnings() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When createdDate is after expirationDate, inverted-interval warning is added")
void getWarningsWhenCreatedDateAfterExpirationDateAddsInvertedIntervalWarning() {
User user = mockCheckableUser("testUser", true);
Expand All @@ -375,7 +386,6 @@ void getWarningsWhenCreatedDateAfterExpirationDateAddsInvertedIntervalWarning()
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When createdDate or expirationDate is null, inverted-interval warning is not added")
void getWarningsWhenOpenIntervalNoInvertedWarning() {
User user = mockCheckableUser("testUser", true);
Expand Down Expand Up @@ -409,7 +419,6 @@ private static Date atStartOfDay(int dayOffset) {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When user has valid positions, no position warnings are returned")
void getWarningsWhenValidPositionsNoPositionWarnings() {
// Arrange
Expand Down Expand Up @@ -437,14 +446,12 @@ void getWarningsWhenValidPositionsNoPositionWarnings() {
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When position has name and organization only, no position-details warning")
void getWarningsWhenNameAndOrganizationPresentNoPositionWarningDespiteBlankEmailAndType() {
assertNoPositionDetailsWarningWhen("Valid Name", "Valid Org", null, null);
}

@Test
@WithMockUser(roles = "ADMIN")
@DisplayName("When user has positions for all territories, no role-without-position warning")
void getWarningsWhenPositionsForAllTerritoriesNoRoleWarning() {
// Arrange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,19 @@
import org.sitmun.domain.user.User;
import org.sitmun.domain.user.UserRepository;
import org.sitmun.domain.user.configuration.UserConfiguration;
import org.sitmun.infrastructure.persistence.type.i18n.I18nTestConfiguration;
import org.sitmun.infrastructure.security.core.SecurityConstants;
import org.sitmun.test.BaseTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.transaction.annotation.Transactional;

/**
* Tests for UserPositionBusinessLogic. Positions for a user are updated (created) when
* UserConfiguration is saved (via UserConfigurationEventHandler), not when a user is retrieved with
* a projection; projections are read-only.
*/
@DataJpaTest
@Import({UserPositionBusinessLogic.class, I18nTestConfiguration.class})
@DisplayName("User Position Business Logic JPA Test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserPositionBusinessLogicTest {
@Transactional
class UserPositionBusinessLogicTest extends BaseTest {

@Autowired private UserPositionBusinessLogic userPositionBusinessLogic;

Expand Down Expand Up @@ -225,13 +216,4 @@ void nullTerritoryDoesNotThrow() {
() -> userPositionBusinessLogic.createUserPositionIfNotExists(configWithNullTerritory))
.doesNotThrowAnyException();
}

@TestConfiguration
static class Configuration {
@Bean
@Primary
TaskExecutor taskExecutor() {
return new SyncTaskExecutor();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,21 @@
import org.sitmun.domain.user.User;
import org.sitmun.domain.user.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc;
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.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;

@SpringBootTest
@AutoConfigureWebMvc
@AutoConfigureMockMvc
@Transactional(rollbackFor = Exception.class)
@DisplayName("User Position Repository Data REST Test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@WithMockUser(roles = "ADMIN")
class UserPositionRepositoryDataRestTest {

@Autowired private WebApplicationContext webApplicationContext;
@Autowired private MockMvc mockMvc;

@Autowired private UserPositionRepository userPositionRepository;

Expand All @@ -49,7 +47,6 @@ class UserPositionRepositoryDataRestTest {

@Autowired private TerritoryTypeRepository territoryTypeRepository;

private MockMvc mockMvc;
private User user;
private Territory territory;
private Role role;
Expand All @@ -58,8 +55,6 @@ class UserPositionRepositoryDataRestTest {

@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();

// Create test territory type
territoryType =
TerritoryType.builder()
Expand Down
Loading
Loading