-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an actuator and change security to OAuth2
- Loading branch information
flawmop
committed
Aug 22, 2024
1 parent
f61246b
commit c43f883
Showing
7 changed files
with
2,088 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 120 additions & 27 deletions
147
...est-e2e/java/com/insilicosoft/portal/svc/rip/controller/FileAsyncUploadControllerE2E.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,175 @@ | ||
package com.insilicosoft.portal.svc.rip.controller; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; | ||
|
||
import java.nio.file.Path; | ||
|
||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; | ||
import org.springframework.boot.test.web.client.TestRestTemplate; | ||
|
||
import org.springframework.core.io.FileSystemResource; | ||
import org.springframework.http.HttpEntity; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.util.LinkedMultiValueMap; | ||
import org.springframework.http.client.MultipartBodyBuilder; | ||
import org.springframework.test.context.DynamicPropertyRegistry; | ||
import org.springframework.test.context.DynamicPropertySource; | ||
import org.springframework.test.web.reactive.server.WebTestClient; | ||
import org.springframework.web.reactive.function.BodyInserters; | ||
import org.springframework.web.reactive.function.client.WebClient; | ||
import org.testcontainers.junit.jupiter.Container; | ||
import org.testcontainers.junit.jupiter.Testcontainers; | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.insilicosoft.portal.svc.rip.RipIdentifiers; | ||
|
||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) | ||
import dasniko.testcontainers.keycloak.KeycloakContainer; | ||
|
||
@SpringBootTest(webEnvironment = RANDOM_PORT) | ||
@Testcontainers | ||
public class FileAsyncUploadControllerE2E { | ||
|
||
private static final String postUrl = RipIdentifiers.REQUEST_MAPPING_RUN.concat(RipIdentifiers.REQUEST_MAPPING_UPLOAD_ASYNC); | ||
private static final HttpHeaders httpHeaders = new HttpHeaders(); | ||
private static final String goodRequestFileName = "request_good.json"; | ||
private static final Path goodPath = Path.of("src", "test", "resources", "requests", goodRequestFileName); | ||
|
||
private static KeycloakToken bjornTokens; | ||
|
||
{ | ||
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); | ||
} | ||
|
||
@Autowired | ||
private TestRestTemplate restTemplate; | ||
private WebTestClient webTestClient; | ||
|
||
// Alternatively localhost:5000/keycloak:19.0 | ||
@Container | ||
private static final KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:19.0") | ||
.withRealmImportFile("keycloak/test-realm-config.json"); | ||
|
||
|
||
@DynamicPropertySource | ||
static void dynamicProperties(DynamicPropertyRegistry registry) { | ||
registry.add("spring.security.oauth2.resourceserver.jwt.issuer-uri", | ||
() -> keycloak.getAuthServerUrl() + "realms/PolarBookshop"); | ||
} | ||
|
||
@BeforeAll | ||
static void generateAccessTokens() { | ||
WebClient webClient = WebClient.builder().baseUrl(keycloak.getAuthServerUrl() + "realms/PolarBookshop/protocol/openid-connect/token") | ||
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) | ||
.build(); | ||
bjornTokens = authenticateWith("bjorn", "password", webClient); | ||
} | ||
|
||
@DisplayName("Test GET method(s)") | ||
@Nested | ||
class GetMethods { | ||
@DisplayName("Success") | ||
@Test | ||
void success() { | ||
ResponseEntity<String> response = restTemplate.getForEntity(RipIdentifiers.REQUEST_MAPPING_RUN, | ||
String.class); | ||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); | ||
assertThat(response.getBody()).isEqualTo("All good from FileAsyncUploadController->InputProcessorService!!"); | ||
webTestClient.get() | ||
.uri(RipIdentifiers.REQUEST_MAPPING_RUN) | ||
.headers(headers -> { | ||
headers.setBearerAuth(bjornTokens.accessToken); | ||
}) | ||
.exchange() | ||
.expectStatus().isOk() | ||
.expectBody(String.class).value(body -> { | ||
assertThat(body).isEqualTo("All good from FileAsyncUploadController->InputProcessorService!!"); | ||
}); | ||
} | ||
} | ||
|
||
@DisplayName("Test POST method(s)") | ||
@Nested | ||
class PostMethods { | ||
@DisplayName("Fail on expected request param not supplied") | ||
@DisplayName("Fail on unauthorized") | ||
@Test | ||
void failOnBadParamName() { | ||
var linkedMVMap = new LinkedMultiValueMap<>(); | ||
void failOnUnauthorized() { | ||
webTestClient.post() | ||
.uri(postUrl) | ||
.headers(headers -> { | ||
headers.addAll(httpHeaders); | ||
}) | ||
.exchange() | ||
.expectStatus().isUnauthorized(); | ||
} | ||
|
||
ResponseEntity<String> response = restTemplate.postForEntity(postUrl, | ||
new HttpEntity<>(linkedMVMap, httpHeaders), | ||
String.class); | ||
@DisplayName("Fail on multipart exception") | ||
@Test | ||
void failOnMultipartException() { | ||
webTestClient.post() | ||
.uri(postUrl) | ||
.headers(headers -> { | ||
headers.setBearerAuth(bjornTokens.accessToken); | ||
headers.addAll(httpHeaders); | ||
}) | ||
.exchange() | ||
.expectStatus().is5xxServerError() | ||
.expectBody(String.class).value(body -> { | ||
assertThat(body).isEqualTo("Error occurred during file upload - MultipartException"); | ||
}); | ||
} | ||
|
||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); | ||
assertThat(response.getBody()).isEqualTo("The POST request must supply the parameter '" + RipIdentifiers.PARAM_NAME_SIMULATION_FILE + "'"); | ||
@DisplayName("Fail on expected request param not supplied") | ||
@Test | ||
void failOnBadParamName() { | ||
var multipartBodyBuilder = new MultipartBodyBuilder(); | ||
multipartBodyBuilder.part("fish", new FileSystemResource(goodPath)); | ||
webTestClient.post() | ||
.uri(postUrl) | ||
.headers(headers -> { | ||
headers.setBearerAuth(bjornTokens.accessToken); | ||
}) | ||
.body(BodyInserters.fromMultipartData(multipartBodyBuilder.build())) | ||
.exchange() | ||
.expectStatus().isBadRequest() | ||
.expectBody(String.class).value(body -> { | ||
assertThat(body).isEqualTo("The POST request must supply the parameter '" + RipIdentifiers.PARAM_NAME_SIMULATION_FILE + "'"); | ||
}); | ||
} | ||
|
||
@DisplayName("Success on a good simulations request file") | ||
@Test | ||
void success() { | ||
var linkedMVMap = new LinkedMultiValueMap<>(); | ||
linkedMVMap.add(RipIdentifiers.PARAM_NAME_SIMULATION_FILE, new FileSystemResource(goodPath)); | ||
var multipartBodyBuilder = new MultipartBodyBuilder(); | ||
multipartBodyBuilder.part(RipIdentifiers.PARAM_NAME_SIMULATION_FILE, new FileSystemResource(goodPath)); | ||
webTestClient.post() | ||
.uri(postUrl) | ||
.headers(headers -> { | ||
headers.setBearerAuth(bjornTokens.accessToken); | ||
}) | ||
.body(BodyInserters.fromMultipartData(multipartBodyBuilder.build())) | ||
.exchange() | ||
.expectStatus().isOk() | ||
.expectBody(String.class).value(body -> { | ||
assertThat(body).isEqualTo(goodRequestFileName); | ||
}); | ||
} | ||
} | ||
|
||
ResponseEntity<String> response = restTemplate.postForEntity(postUrl, | ||
new HttpEntity<>(linkedMVMap, httpHeaders), | ||
String.class); | ||
private static KeycloakToken authenticateWith(String username, String password, WebClient webClient) { | ||
return webClient.post() | ||
.body(BodyInserters.fromFormData("grant_type", "password") | ||
.with("client_id", "polar-test") | ||
.with("username", username) | ||
.with("password", password)) | ||
.retrieve() | ||
.bodyToMono(KeycloakToken.class) | ||
.block(); | ||
} | ||
|
||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); | ||
assertThat(response.getBody()).isEqualTo(goodRequestFileName); | ||
private record KeycloakToken(String accessToken) { | ||
@JsonCreator | ||
private KeycloakToken(@JsonProperty("access_token") final String accessToken) { | ||
this.accessToken = accessToken; | ||
} | ||
} | ||
} |
Oops, something went wrong.