package com.vaessl.app.connection; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.resttestclient.TestRestTemplate; import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import com.github.tomakehurst.wiremock.http.Fault; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; import com.vaessl.app.dto.ConnectionRequest; import static org.assertj.core.api.Assertions.assertThat; import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.vaessl.app.connection.Endpoint.*; import static com.vaessl.app.exception.ErrorMessage.*; import static com.vaessl.app.connection.ServiceType.*; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureTestRestTemplate @WireMockTest class HomeboxIntegrationTest { @Autowired TestRestTemplate restTemplate; @Autowired ConnectionRepository cRepository; String okJsonHomeboxResponse = """ { "token": "fake-jwt-token", "attachmentToken": "fake-attach", "expiresAt": "2026-04-26T02:23:13Z" } """; private static final String TEST_USER = "admin"; private static final String TEST_PASS = "pw"; /** * Returns Token and status code OK when login is successful. * * @param wm the WiremockRuntimeInfo object */ @Test void shouldReturnStatusOkWhenHomeboxCredentialsAreValid(WireMockRuntimeInfo wm) { stubFor(post(HOMEBOX_LOGIN.getValue()) .willReturn(okJson(okJsonHomeboxResponse))); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), connectionRequest(wm), String.class); DocumentContext documentContext = JsonPath.parse(response.getBody()); String serviceType = documentContext.read("$.serviceType"); assertThat(serviceType).isEqualTo("HOMEBOX"); String expiresAt = documentContext.read("$.expiresAt", String.class); assertThat(expiresAt).isEqualTo("2026-04-26T02:23:13Z"); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); } /** * Tests the Unauthorized custom exception. * * @param wm the WiremockRuntimeInfo object */ @Test void shouldFailToConnectWhenHomeboxReturnsUnauthorized(WireMockRuntimeInfo wm) { stubFor(post(HOMEBOX_LOGIN.getValue()).willReturn(unauthorized())); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), connectionRequest(wm), String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); assertThat(response.getBody()).contains(UNAUTHORIZED_WRONG_LOGIN.getMessage()); } /** * Tests a server error from the external api. * * @param wm the WiremockRuntimeInfo object */ @Test void shouldFailToConnectWhenHomeboxReturnsServiceUnavailable(WireMockRuntimeInfo wm) { stubFor(post(HOMEBOX_LOGIN.getValue()).willReturn(serviceUnavailable())); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), connectionRequest(wm), String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE); assertThat(response.getBody()).contains(SERVER_ERROR_GENERAL.getMessage()); } /** * Checks when the service is unavailable or the app URL is wrong. */ @Test void shouldReturnServiceUnavailableWhenHomeboxUrlIsWrong(WireMockRuntimeInfo wm) { stubFor(post(HOMEBOX_LOGIN.getValue()) .willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER))); ConnectionRequest badRequest = connectionRequest(wm); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), badRequest, String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE); assertThat(response.getBody()).contains(SERVICE_UNAVAILABLE_UNREACHABLE_URL.getMessage()); } /** * Checks if any login fields are empty since all of them are mandatory. */ @Test void shouldReturnBadRequestWhenHomeboxFieldsAreEmpty() { ConnectionRequest emtpyRequest = new ConnectionRequest("", "", "", "", false); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), emtpyRequest, String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); assertThat(response.getBody()).contains(BAD_REQUEST_EMPTY_FIELDS.getMessage()); } /** * Test the exception when there is an input for serviceType but it's * unsupported. */ @Test void shouldReturnWrongServiceTypeException(WireMockRuntimeInfo wm) { ConnectionRequest wrongServiceTypeReq = new ConnectionRequest( wm.getHttpBaseUrl(), "wrong-service-type", TEST_USER, TEST_PASS, false); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), wrongServiceTypeReq, String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); assertThat(response.getBody()).contains(WRONG_SERVICE_TYPE.getMessage()); } /** * Tests the succesfull persistance of Homebox credential response to the * database. * * @param wm the WiremockRuntimeInfo object */ @Test void shouldSaveHomeboxConnectionResponseToDb(WireMockRuntimeInfo wm) { stubFor(post(urlEqualTo(HOMEBOX_LOGIN.getValue())) .willReturn(okJson(okJsonHomeboxResponse))); ConnectionRequest request = connectionRequest(wm); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), request, String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); ConnectionEntity dbEntry = cRepository.findByAppUrlAndUsername(request.appUrl(), request.username()); assertThat(dbEntry).isNotNull(); assertThat(dbEntry.getAppUrl()).isEqualTo(request.appUrl()); assertThat(dbEntry.getUsername()).isEqualTo(request.username()); if (dbEntry instanceof HomeboxEntity hbE) { assertThat(hbE.getToken()).isEqualTo("fake-jwt-token"); assertThat(hbE.getAttachmentToken()).isEqualTo("fake-attach"); assertThat(hbE.getExpiresAt().toString()).hasToString("2026-04-26T02:23:13Z"); } } @Test void shouldReturnEmptyCredentialsExceptionWhenCredsAreMissing(WireMockRuntimeInfo wm) { ConnectionRequest missingCredentials = new ConnectionRequest(wm.getHttpBaseUrl(), HOMEBOX.getValue(), TEST_USER, null, false); ResponseEntity response = restTemplate.postForEntity(LOGIN.getValue(), missingCredentials, String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); assertThat(response.getBody()).contains(BAD_REQUEST_EMPTY_FIELDS.getMessage()); } /** * Creates a valid connection request with a mock Api through * WireMockRuntimeInfo. * * @param wm the WiremockRuntimeInfo object * @return a mock api connection request. */ private ConnectionRequest connectionRequest(WireMockRuntimeInfo wm) { return new ConnectionRequest(wm.getHttpBaseUrl(), HOMEBOX.getValue(), TEST_USER, TEST_PASS, null); } }