feature/credentials-schema-updates (#180)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/180 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
package net.hostsharing.hsadminng.credentials;
|
||||
|
||||
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
|
||||
import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration;
|
||||
import net.hostsharing.hsadminng.config.MessageTranslator;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRbacRepository;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
|
||||
import org.hamcrest.CustomMatcher;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest(HsCredentialsController.class)
|
||||
@Import({ StrictMapper.class, JsonObjectMapperConfiguration.class, DisableSecurityConfig.class, MessageTranslator.class })
|
||||
@ActiveProfiles("test")
|
||||
class HsCredentialsControllerRestTest {
|
||||
|
||||
@Autowired
|
||||
MockMvc mockMvc;
|
||||
|
||||
@MockitoBean
|
||||
Context contextMock;
|
||||
|
||||
@Autowired
|
||||
@SuppressWarnings("unused") // not used in test, but in controller class
|
||||
StrictMapper mapper;
|
||||
|
||||
@MockitoBean
|
||||
EntityManagerWrapper em;
|
||||
|
||||
@MockitoBean
|
||||
EntityManagerFactory emf;
|
||||
|
||||
@MockitoBean
|
||||
HsOfficePersonRbacRepository personRbacRepo;
|
||||
|
||||
@MockitoBean
|
||||
HsCredentialsContextRbacRepository loginContextRbacRepo;
|
||||
|
||||
@MockitoBean
|
||||
HsCredentialsRepository credentialsRepo;
|
||||
|
||||
@Test
|
||||
void patchCredentialsUsed() throws Exception {
|
||||
|
||||
// given
|
||||
final var givenCredentialsUuid = UUID.randomUUID();
|
||||
when(credentialsRepo.findByUuid(givenCredentialsUuid)).thenReturn(Optional.of(
|
||||
HsCredentialsEntity.builder()
|
||||
.uuid(givenCredentialsUuid)
|
||||
.lastUsed(null)
|
||||
.onboardingToken("fake-onboarding-token")
|
||||
.build()
|
||||
));
|
||||
when(credentialsRepo.save(any())).thenAnswer(invocation ->
|
||||
invocation.getArgument(0)
|
||||
);
|
||||
|
||||
// when
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.post("/api/hs/credentials/credentials/%{credentialsUuid}/used"
|
||||
.replace("%{credentialsUuid}", givenCredentialsUuid.toString()))
|
||||
.header("Authorization", "Bearer superuser-alex@hostsharing.net")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(print())
|
||||
|
||||
// then
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath(
|
||||
"$", lenientlyEquals("""
|
||||
{
|
||||
"uuid": "%{credentialsUuid}",
|
||||
"onboardingToken": null
|
||||
}
|
||||
""".replace("%{credentialsUuid}", givenCredentialsUuid.toString())
|
||||
)))
|
||||
.andExpect(jsonPath("$.lastUsed").value(new CustomMatcher<String>("lastUsed should have recent timestamp") {
|
||||
|
||||
@Override
|
||||
public boolean matches(final Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
final var lastUsed = ZonedDateTime.parse(o.toString(), DateTimeFormatter.ISO_DATE_TIME)
|
||||
.toLocalDateTime();
|
||||
return lastUsed.isAfter(LocalDateTime.now().minusMinutes(1)) &&
|
||||
lastUsed.isBefore(LocalDateTime.now());
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -33,13 +33,13 @@ class HsCredentialsEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
|
||||
private static final Boolean INITIAL_ACTIVE = true;
|
||||
private static final String INITIAL_EMAIL_ADDRESS = "initial@example.com";
|
||||
private static final String INITIAL_TWO_FACTOR_AUTH = "initial_2fa";
|
||||
private static final String INITIAL_TOTP_SECRET = "initial_2fa";
|
||||
private static final String INITIAL_SMS_NUMBER = "initial_sms";
|
||||
private static final String INITIAL_PHONE_PASSWORD = "initial_phone_pw";
|
||||
|
||||
private static final Boolean PATCHED_ACTIVE = false;
|
||||
private static final String PATCHED_EMAIL_ADDRESS = "patched@example.com";
|
||||
private static final String PATCHED_TWO_FACTOR_AUTH = "patched_2fa";
|
||||
private static final String PATCHED_TOTP_SECRET = "patched_2fa";
|
||||
private static final String PATCHED_SMS_NUMBER = "patched_sms";
|
||||
private static final String PATCHED_PHONE_PASSWORD = "patched_phone_pw";
|
||||
|
||||
@@ -102,7 +102,7 @@ class HsCredentialsEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
entity.setUuid(INITIAL_CREDENTIALS_UUID);
|
||||
entity.setActive(INITIAL_ACTIVE);
|
||||
entity.setEmailAddress(INITIAL_EMAIL_ADDRESS);
|
||||
entity.setTwoFactorAuth(INITIAL_TWO_FACTOR_AUTH);
|
||||
entity.setTotpSecret(INITIAL_TOTP_SECRET);
|
||||
entity.setSmsNumber(INITIAL_SMS_NUMBER);
|
||||
entity.setPhonePassword(INITIAL_PHONE_PASSWORD);
|
||||
// Ensure loginContexts is a mutable set for the patcher
|
||||
@@ -137,11 +137,11 @@ class HsCredentialsEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
HsCredentialsEntity::setEmailAddress,
|
||||
PATCHED_EMAIL_ADDRESS),
|
||||
new JsonNullableProperty<>(
|
||||
"twoFactorAuth",
|
||||
CredentialsPatchResource::setTwoFactorAuth,
|
||||
PATCHED_TWO_FACTOR_AUTH,
|
||||
HsCredentialsEntity::setTwoFactorAuth,
|
||||
PATCHED_TWO_FACTOR_AUTH),
|
||||
"totpSecret",
|
||||
CredentialsPatchResource::setTotpSecret,
|
||||
PATCHED_TOTP_SECRET,
|
||||
HsCredentialsEntity::setTotpSecret,
|
||||
PATCHED_TOTP_SECRET),
|
||||
new JsonNullableProperty<>(
|
||||
"smsNumber",
|
||||
CredentialsPatchResource::setSmsNumber,
|
||||
|
||||
@@ -138,7 +138,7 @@ public class ImportHostingAssets extends CsvDataImport {
|
||||
@Autowired
|
||||
LiquibaseMigration liquibase;
|
||||
|
||||
@Value("${HSADMINNG_OFFICE_DATA_SQL_FILE:/db/released-only-office-schema-with-import-test-data.sql}")
|
||||
@Value("${HSADMINNG_OFFICE_DATA_SQL_FILE:/db/released-only-prod-schema-with-import-test-data.sql}")
|
||||
String officeSchemaAndDataSqlFile;
|
||||
|
||||
@Test
|
||||
|
||||
@@ -24,9 +24,9 @@ import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TE
|
||||
* <p>The test works as follows:</p>
|
||||
*
|
||||
* <ol>
|
||||
* <li>the database is initialized by `db/released-only-office-schema-with-test-data.sql` from the test-resources</li>
|
||||
* <li>the current Liquibase-migrations (only-office but with-test-data) are performed</li>
|
||||
* <li>a new dump is written to `db/released-only-office-schema-with-test-data.sql` in the build-directory</li>
|
||||
* <li>the database is initialized by `db/released-only-prod-schema-with-test-data.sql` from the test-resources</li>
|
||||
* <li>the current Liquibase-migrations (only-prod-schema but with-test-data) are performed</li>
|
||||
* <li>a new dump is written to `db/released-only-prod-schema-with-test-data.sql` in the build-directory</li>
|
||||
* <li>an extra Liquibase-changeset (liquibase-migration-test) is applied</li>
|
||||
* <li>it's asserted that the extra changeset got applied</li>
|
||||
* </ol>
|
||||
@@ -43,7 +43,7 @@ import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TE
|
||||
@DirtiesContext
|
||||
@ActiveProfiles("liquibase-migration-test")
|
||||
@Import(LiquibaseConfig.class)
|
||||
@Sql(value = "/db/released-only-office-schema-with-test-data.sql", executionPhase = BEFORE_TEST_CLASS) // release-schema
|
||||
@Sql(value = "/db/released-only-prod-schema-with-test-data.sql", executionPhase = BEFORE_TEST_CLASS) // release-schema
|
||||
public class LiquibaseCompatibilityIntegrationTest {
|
||||
|
||||
private static final String EXPECTED_CHANGESET_ONLY_AFTER_NEW_MIGRATION = "hs-global-liquibase-migration-test";
|
||||
@@ -62,8 +62,8 @@ public class LiquibaseCompatibilityIntegrationTest {
|
||||
EXPECTED_LIQUIBASE_CHANGELOGS_IN_PROD_SCHEMA_DUMP, EXPECTED_CHANGESET_ONLY_AFTER_NEW_MIGRATION);
|
||||
|
||||
// run the current migrations and dump the result to the build-directory
|
||||
liquibase.runWithContexts("only-office", "with-test-data");
|
||||
PostgresTestcontainer.dump(jdbcUrl, new File("build/db/released-only-office-schema-with-test-data.sql"));
|
||||
liquibase.runWithContexts("only-prod-schema", "with-test-data");
|
||||
PostgresTestcontainer.dump(jdbcUrl, new File("build/db/released-only-prod-schema-with-test-data.sql"));
|
||||
|
||||
// then add another migration and assert if it was applied
|
||||
liquibase.runWithContexts("liquibase-migration-test");
|
||||
|
||||
Reference in New Issue
Block a user