From 289df2f1e3ab28e2ab4699b7218fdc34aadc6755 Mon Sep 17 00:00:00 2001 From: Patrick Hobusch Date: Tue, 24 Feb 2026 13:22:48 +0800 Subject: [PATCH] Add Crowd integration tests for session config, trusted proxies and mail server --- .github/workflows/ci.yaml | 6 + .../AbstractMailServerProtocolModel.java | 2 + ...bstractMailServerSmtpResourceFuncTest.java | 28 +++-- .../commons/rest/HttpRequestHelper.java | 2 + .../model/util/MailServerSmtpModelUtil.java | 2 + .../rest/MailServerSmtpResourceFuncTest.java | 19 ++++ .../rest/SessionConfigResourceFuncTest.java | 80 ++++++++++++++ .../rest/TrustedProxiesResourceFuncTest.java | 103 ++++++++++++++++++ 8 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/MailServerSmtpResourceFuncTest.java create mode 100644 crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/SessionConfigResourceFuncTest.java create mode 100644 crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/TrustedProxiesResourceFuncTest.java diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b23110d9..325e61b2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -74,6 +74,12 @@ jobs: - crowd - jira + services: + greenmail: + image: greenmail/standalone:2.1.2 + ports: + - 3025:3025 + steps: - name: Checkout code uses: actions/checkout@v6 diff --git a/commons/src/main/java/com/deftdevs/bootstrapi/commons/model/AbstractMailServerProtocolModel.java b/commons/src/main/java/com/deftdevs/bootstrapi/commons/model/AbstractMailServerProtocolModel.java index 7de5e717..d55b0e73 100644 --- a/commons/src/main/java/com/deftdevs/bootstrapi/commons/model/AbstractMailServerProtocolModel.java +++ b/commons/src/main/java/com/deftdevs/bootstrapi/commons/model/AbstractMailServerProtocolModel.java @@ -1,6 +1,7 @@ package com.deftdevs.bootstrapi.commons.model; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -65,6 +66,7 @@ public void setPort( * * @param port the port */ + @JsonProperty public void setPort( final String port) { diff --git a/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/AbstractMailServerSmtpResourceFuncTest.java b/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/AbstractMailServerSmtpResourceFuncTest.java index cb47c190..0f536e3e 100644 --- a/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/AbstractMailServerSmtpResourceFuncTest.java +++ b/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/AbstractMailServerSmtpResourceFuncTest.java @@ -3,7 +3,10 @@ import com.deftdevs.bootstrapi.commons.constants.BootstrAPI; import com.deftdevs.bootstrapi.commons.model.MailServerSmtpModel; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.Response; @@ -12,30 +15,41 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public abstract class AbstractMailServerSmtpResourceFuncTest { private final ObjectMapper objectMapper = new ObjectMapper(); @Test - void testGetMailServerImap() throws Exception { + @Order(1) + void testGetMailServerSmtpNotConfigured() throws Exception { final HttpResponse mailServerSmtpResponse = HttpRequestHelper.builder(BootstrAPI.MAIL_SERVER + "/" + BootstrAPI.MAIL_SERVER_SMTP) .request(); - assertEquals(Response.Status.OK.getStatusCode(), mailServerSmtpResponse.statusCode()); - - final MailServerSmtpModel mailServerSmtpModel = objectMapper.readValue(mailServerSmtpResponse.body(), MailServerSmtpModel.class); - assertNotNull(mailServerSmtpModel); + assertEquals(Response.Status.NO_CONTENT.getStatusCode(), mailServerSmtpResponse.statusCode()); } @Test - void testSetMailServerImap() throws Exception { + @Order(2) + void testSetMailServerSmtp() throws Exception { final HttpResponse mailServerSmtpResponse = HttpRequestHelper.builder(BootstrAPI.MAIL_SERVER + "/" + BootstrAPI.MAIL_SERVER_SMTP) .request(HttpMethod.PUT, getExampleModel()); - assertEquals(Response.Status.OK.getStatusCode(), mailServerSmtpResponse.statusCode()); + assertEquals(Response.Status.OK.getStatusCode(), mailServerSmtpResponse.statusCode(), mailServerSmtpResponse.body()); final MailServerSmtpModel mailServerSmtpModel = objectMapper.readValue(mailServerSmtpResponse.body(), MailServerSmtpModel.class); assertMailServerModelAgainstExample(mailServerSmtpModel); } + @Test + @Order(3) + void testGetMailServerSmtp() throws Exception { + final HttpResponse mailServerSmtpResponse = HttpRequestHelper.builder(BootstrAPI.MAIL_SERVER + "/" + BootstrAPI.MAIL_SERVER_SMTP) + .request(); + assertEquals(Response.Status.OK.getStatusCode(), mailServerSmtpResponse.statusCode(), mailServerSmtpResponse.body()); + + final MailServerSmtpModel mailServerSmtpModel = objectMapper.readValue(mailServerSmtpResponse.body(), MailServerSmtpModel.class); + assertNotNull(mailServerSmtpModel); + } + @Test public void testGetMailServerSmtpUnauthenticated() throws Exception { final HttpResponse mailServerSmtpResponse = HttpRequestHelper.builder(BootstrAPI.MAIL_SERVER + "/" + BootstrAPI.MAIL_SERVER_SMTP) diff --git a/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/HttpRequestHelper.java b/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/HttpRequestHelper.java index 4f82807c..498707cf 100644 --- a/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/HttpRequestHelper.java +++ b/commons/src/test/java/it/com/deftdevs/bootstrapi/commons/rest/HttpRequestHelper.java @@ -91,6 +91,8 @@ public HttpResponse request( requestBuilder.header("Accept", acceptMediaType); } + requestBuilder.header("X-Atlassian-Token", "no-check"); + if (username != null && password != null) { requestBuilder.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((String.format("%s:%s", username, password)).getBytes())); diff --git a/crowd/src/main/java/com/deftdevs/bootstrapi/crowd/model/util/MailServerSmtpModelUtil.java b/crowd/src/main/java/com/deftdevs/bootstrapi/crowd/model/util/MailServerSmtpModelUtil.java index c886dcdb..6bb50ea1 100644 --- a/crowd/src/main/java/com/deftdevs/bootstrapi/crowd/model/util/MailServerSmtpModelUtil.java +++ b/crowd/src/main/java/com/deftdevs/bootstrapi/crowd/model/util/MailServerSmtpModelUtil.java @@ -80,6 +80,8 @@ public static MailConfiguration toMailConfiguration( if (mailServerSmtpModel.getAdminContact() != null) { mailConfigurationBuilder.setNotificationEmails(Collections.singletonList(mailServerSmtpModel.getAdminContact())); + } else { + mailConfigurationBuilder.setNotificationEmails(Collections.emptyList()); } if (mailServerSmtpModel.getFrom() != null) { diff --git a/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/MailServerSmtpResourceFuncTest.java b/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/MailServerSmtpResourceFuncTest.java new file mode 100644 index 00000000..8e3bc96d --- /dev/null +++ b/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/MailServerSmtpResourceFuncTest.java @@ -0,0 +1,19 @@ +package it.com.deftdevs.bootstrapi.crowd.rest; + +import com.deftdevs.bootstrapi.commons.model.MailServerSmtpModel; +import it.com.deftdevs.bootstrapi.commons.rest.AbstractMailServerSmtpResourceFuncTest; + +public class MailServerSmtpResourceFuncTest extends AbstractMailServerSmtpResourceFuncTest { + + @Override + protected MailServerSmtpModel getExampleModel() { + return MailServerSmtpModel.builder() + .from("test@example.com") + .prefix("[Test]") + .host("localhost") + .port(3025) + .useTls(false) + .timeout(5000L) + .build(); + } +} diff --git a/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/SessionConfigResourceFuncTest.java b/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/SessionConfigResourceFuncTest.java new file mode 100644 index 00000000..241022fc --- /dev/null +++ b/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/SessionConfigResourceFuncTest.java @@ -0,0 +1,80 @@ +package it.com.deftdevs.bootstrapi.crowd.rest; + +import com.deftdevs.bootstrapi.crowd.model.SessionConfigModel; +import com.deftdevs.bootstrapi.crowd.rest.api.SessionConfigResource; +import com.fasterxml.jackson.databind.ObjectMapper; +import it.com.deftdevs.bootstrapi.commons.rest.HttpRequestHelper; +import org.junit.jupiter.api.Test; + +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.Response; +import java.net.http.HttpResponse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class SessionConfigResourceFuncTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testGetSessionConfig() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(SessionConfigResource.SESSION_CONFIG) + .request(); + assertEquals(Response.Status.OK.getStatusCode(), response.statusCode()); + + final SessionConfigModel sessionConfigModel = objectMapper.readValue(response.body(), SessionConfigModel.class); + assertNotNull(sessionConfigModel); + assertNotNull(sessionConfigModel.getSessionTimeoutInMinutes()); + assertNotNull(sessionConfigModel.getRequireConsistentClientIP()); + } + + @Test + void testSetSessionConfig() throws Exception { + final SessionConfigModel exampleModel = SessionConfigModel.EXAMPLE_2; + + final HttpResponse response = HttpRequestHelper.builder(SessionConfigResource.SESSION_CONFIG) + .request(HttpMethod.PUT, exampleModel); + assertEquals(Response.Status.OK.getStatusCode(), response.statusCode()); + + final SessionConfigModel sessionConfigModel = objectMapper.readValue(response.body(), SessionConfigModel.class); + assertEquals(exampleModel.getSessionTimeoutInMinutes(), sessionConfigModel.getSessionTimeoutInMinutes()); + assertEquals(exampleModel.getRequireConsistentClientIP(), sessionConfigModel.getRequireConsistentClientIP()); + } + + @Test + void testGetSessionConfigUnauthenticated() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(SessionConfigResource.SESSION_CONFIG) + .username("wrong") + .password("password") + .request(); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.statusCode()); + } + + @Test + void testSetSessionConfigUnauthenticated() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(SessionConfigResource.SESSION_CONFIG) + .username("wrong") + .password("password") + .request(HttpMethod.PUT, SessionConfigModel.EXAMPLE_2); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.statusCode()); + } + + @Test + void testGetSessionConfigUnauthorized() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(SessionConfigResource.SESSION_CONFIG) + .username("user") + .password("user") + .request(); + assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.statusCode()); + } + + @Test + void testSetSessionConfigUnauthorized() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(SessionConfigResource.SESSION_CONFIG) + .username("user") + .password("user") + .request(HttpMethod.PUT, SessionConfigModel.EXAMPLE_2); + assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.statusCode()); + } +} diff --git a/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/TrustedProxiesResourceFuncTest.java b/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/TrustedProxiesResourceFuncTest.java new file mode 100644 index 00000000..48cdb626 --- /dev/null +++ b/crowd/src/test/java/it/com/deftdevs/bootstrapi/crowd/rest/TrustedProxiesResourceFuncTest.java @@ -0,0 +1,103 @@ +package it.com.deftdevs.bootstrapi.crowd.rest; + +import com.deftdevs.bootstrapi.crowd.rest.api.TrustedProxiesResource; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import it.com.deftdevs.bootstrapi.commons.rest.HttpRequestHelper; +import org.junit.jupiter.api.Test; + +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.net.http.HttpResponse; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class TrustedProxiesResourceFuncTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testGetTrustedProxies() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .request(); + assertEquals(Response.Status.OK.getStatusCode(), response.statusCode()); + + final List trustedProxies = objectMapper.readValue(response.body(), new TypeReference>() {}); + assertNotNull(trustedProxies); + } + + @Test + void testSetTrustedProxies() throws Exception { + final List proxies = List.of("10.0.0.1", "10.0.0.2"); + + final HttpResponse response = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .request(HttpMethod.PUT, proxies); + assertEquals(Response.Status.OK.getStatusCode(), response.statusCode()); + + final List resultProxies = objectMapper.readValue(response.body(), new TypeReference>() {}); + assertEquals(proxies, resultProxies); + } + + @Test + void testAddAndRemoveTrustedProxy() throws Exception { + // Set empty list first + HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .request(HttpMethod.PUT, List.of()); + + // Add a proxy + final HttpResponse addResponse = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .contentMediaType(MediaType.TEXT_PLAIN) + .request(HttpMethod.POST, "192.168.1.1"); + assertEquals(Response.Status.OK.getStatusCode(), addResponse.statusCode()); + + List proxies = objectMapper.readValue(addResponse.body(), new TypeReference>() {}); + assertTrue(proxies.contains("192.168.1.1")); + + // Remove the proxy + final HttpResponse removeResponse = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .contentMediaType(MediaType.TEXT_PLAIN) + .request(HttpMethod.DELETE, "192.168.1.1"); + assertEquals(Response.Status.OK.getStatusCode(), removeResponse.statusCode()); + + proxies = objectMapper.readValue(removeResponse.body(), new TypeReference>() {}); + assertFalse(proxies.contains("192.168.1.1")); + } + + @Test + void testGetTrustedProxiesUnauthenticated() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .username("wrong") + .password("password") + .request(); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.statusCode()); + } + + @Test + void testSetTrustedProxiesUnauthenticated() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .username("wrong") + .password("password") + .request(HttpMethod.PUT, List.of("10.0.0.1")); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.statusCode()); + } + + @Test + void testGetTrustedProxiesUnauthorized() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .username("user") + .password("user") + .request(); + assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.statusCode()); + } + + @Test + void testSetTrustedProxiesUnauthorized() throws Exception { + final HttpResponse response = HttpRequestHelper.builder(TrustedProxiesResource.TRUSTED_PROXIES) + .username("user") + .password("user") + .request(HttpMethod.PUT, List.of("10.0.0.1")); + assertEquals(Response.Status.FORBIDDEN.getStatusCode(), response.statusCode()); + } +}