Skip to content

Commit

Permalink
Updated tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chris.ditcher authored and chris.ditcher committed Jul 17, 2024
1 parent 734ea72 commit f6a92d4
Show file tree
Hide file tree
Showing 18 changed files with 368 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.educ.api.course.exception.EntityNotFoundException;
import ca.bc.gov.educ.api.course.exception.GradBusinessRuleException;
import ca.bc.gov.educ.api.course.exception.ServiceException;
import ca.bc.gov.educ.api.course.util.ApiResponseMessage.MessageTypeEnum;
import ca.bc.gov.educ.api.course.util.ApiResponseModel;
import ca.bc.gov.educ.api.course.util.GradValidation;
Expand Down Expand Up @@ -39,6 +40,11 @@ protected ResponseEntity<Object> handleConflict(RuntimeException ex, WebRequest
return new ResponseEntity<>(response, HttpStatus.UNPROCESSABLE_ENTITY);
}

@ExceptionHandler(value = { ServiceException.class })
protected ResponseEntity<Object> handleServiceException(ServiceException ex, WebRequest request) {
return new ResponseEntity<>(ApiResponseModel.ERROR(null, ex.getLocalizedMessage()), HttpStatus.resolve(ex.getStatusCode()));
}

@ExceptionHandler(value = { JpaObjectRetrievalFailureException.class, DataRetrievalFailureException.class })
protected ResponseEntity<Object> handleEntityNotFound(RuntimeException ex, WebRequest request) {
LOG.error("JPA ERROR IS: " + ex.getClass().getName(), ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.*;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
Expand All @@ -17,6 +20,7 @@

@Configuration
public class RestWebClient {

@Autowired
EducCourseApiConstants constants;

Expand All @@ -28,6 +32,36 @@ public RestWebClient() {
this.httpClient.warmup().block();
}

@Bean("courseApiClient")
public WebClient getCourseApiClientWebClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction filter = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
filter.setDefaultClientRegistrationId("course-api-client");
return WebClient.builder()
.exchangeStrategies(ExchangeStrategies
.builder()
.codecs(codecs -> codecs
.defaultCodecs()
.maxInMemorySize(50 * 1024 * 1024))
.build())
.apply(filter.oauth2Configuration())
.build();
}

@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService clientService) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, clientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

return authorizedClientManager;
}

@Bean
public WebClient webClient() {
DefaultUriBuilderFactory defaultUriBuilderFactory = new DefaultUriBuilderFactory();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import ca.bc.gov.educ.api.course.util.EducCourseApiConstants;
import ca.bc.gov.educ.api.course.util.ThreadLocalStateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;

Expand All @@ -17,13 +19,14 @@
@Service
public class RESTService {
private final WebClient webClient;

private final WebClient courseApiWebClient;
private static final String ERROR_5xx = "5xx error.";
private static final String SERVICE_FAILED_ERROR = "Service failed to process after max retries.";

@Autowired
public RESTService(WebClient webClient) {
public RESTService(@Qualifier("courseApiClient") WebClient courseApiWebClient, WebClient webClient) {
this.webClient = webClient;
this.courseApiWebClient = courseApiWebClient;
}

/**
Expand All @@ -38,6 +41,7 @@ public RESTService(WebClient webClient) {
* @param accessToken access token
* @return return type
* @param <T> expected return type
* @deprecated use the one without accessToken instead
*/
public <T> T get(String url, Class<T> clazz, String accessToken) {
T obj;
Expand All @@ -61,7 +65,50 @@ public <T> T get(String url, Class<T> clazz, String accessToken) {
.block();
} catch (Exception e) {
// catches IOExceptions and the like
throw new ServiceException(getErrorMessage(url, e.getLocalizedMessage()), HttpStatus.SERVICE_UNAVAILABLE.value(), e);
throw new ServiceException(getErrorMessage(
url,
e.getLocalizedMessage()),
(e instanceof WebClientResponseException) ? ((WebClientResponseException) e).getStatusCode().value() : HttpStatus.SERVICE_UNAVAILABLE.value(),
e);
}
return obj;
}


/**
* Uses this method with a service client
* @param url
* @param clazz
* @return
* @param <T>
*/
public <T> T get(String url, Class<T> clazz) {
T obj;
try {
obj = courseApiWebClient
.get()
.uri(url)
.headers(h -> { h.set(EducCourseApiConstants.CORRELATION_ID, ThreadLocalStateUtil.getCorrelationID()); })
.retrieve()
// if 5xx errors, throw Service error
.onStatus(HttpStatusCode::is5xxServerError,
clientResponse -> Mono.error(new ServiceException(getErrorMessage(url, ERROR_5xx), clientResponse.statusCode().value())))
.bodyToMono(clazz)
// only does retry if initial error was 5xx as service may be temporarily down
// 4xx errors will always happen if 404, 401, 403 etc, so does not retry
.retryWhen(Retry.backoff(3, Duration.ofSeconds(2))
.filter(ServiceException.class::isInstance)
.onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {
throw new ServiceException(getErrorMessage(url, SERVICE_FAILED_ERROR), HttpStatus.SERVICE_UNAVAILABLE.value());
}))
.block();
} catch (Exception e) {
// catches IOExceptions and the like
throw new ServiceException(getErrorMessage(
url,
e.getLocalizedMessage()),
(e instanceof WebClientResponseException) ? ((WebClientResponseException) e).getStatusCode().value() : HttpStatus.SERVICE_UNAVAILABLE.value(),
e);
}
return obj;
}
Expand Down Expand Up @@ -93,7 +140,11 @@ public <T> T post(String url, Object body, Class<T> clazz, String accessToken) {
}))
.block();
} catch (Exception e) {
throw new ServiceException(getErrorMessage(url, e.getLocalizedMessage()), HttpStatus.SERVICE_UNAVAILABLE.value(), e);
throw new ServiceException(getErrorMessage(
url,
e.getLocalizedMessage()),
(e instanceof WebClientResponseException) ? ((WebClientResponseException) e).getStatusCode().value() : HttpStatus.SERVICE_UNAVAILABLE.value(),
e);
}
return obj;
}
Expand Down
10 changes: 10 additions & 0 deletions api/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ spring:
jwt:
issuer-uri: ${TOKEN_ISSUER_URL}
jwk-set-uri: ${TOKEN_ISSUER_URL}/protocol/openid-connect/certs
client:
registration:
course-api-client:
client-id: ${COURSE_CLIENT_NAME}
client-secret: ${COURSE_CLIENT_SECRET}
authorization-grant-type: client_credentials
provider:
course-api-client:
issuer-uri: ${TOKEN_ISSUER_URL}
token-uri: ${TOKEN_ISSUER_URL}/protocol/openid-connect/token

#Logging properties
logging:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.reactive.function.client.WebClient;

import java.sql.Date;
import java.util.Arrays;
Expand All @@ -33,6 +38,23 @@ public class CourseAlgorithmServiceTest {
@MockBean
private CourseRestrictionService courseRestrictionService;

@MockBean
public OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository;

@MockBean
public OAuth2AuthorizedClientService oAuth2AuthorizedClientService;

@MockBean
public ClientRegistrationRepository clientRegistrationRepository;

@Qualifier("courseApiClient")
@MockBean
public WebClient courseApiClient;

@Qualifier("default")
@MockBean
public WebClient webClient;

@Test
public void testGetCourseAlgorithmData_whenGivenPenNumber_thenReturnSuccess() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.core.ParameterizedTypeReference;
Expand All @@ -19,8 +20,12 @@
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.reactive.function.client.WebClient;

import java.sql.Date;
import java.util.*;
Expand Down Expand Up @@ -54,6 +59,23 @@ public class CourseRequirementServiceTest {
@MockBean
private RESTService restService;

@MockBean
public OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository;

@MockBean
public OAuth2AuthorizedClientService oAuth2AuthorizedClientService;

@MockBean
public ClientRegistrationRepository clientRegistrationRepository;

@Qualifier("courseApiClient")
@MockBean
public WebClient courseApiClient;

@Qualifier("default")
@MockBean
public WebClient webClient;

@Before
public void setUp() {
openMocks(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.reactive.function.client.WebClient;
Expand All @@ -36,7 +40,21 @@ public class CourseRestrictionServiceTest {
private CourseRestrictionRepository courseRestrictionRepository;

@MockBean
WebClient webClient;
public OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository;

@MockBean
public OAuth2AuthorizedClientService oAuth2AuthorizedClientService;

@MockBean
public ClientRegistrationRepository clientRegistrationRepository;

@Qualifier("courseApiClient")
@MockBean
public WebClient courseApiClient;

@Qualifier("default")
@MockBean
public WebClient webClient;

@Test
public void testGetAllCourseRestrictionList() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.reactive.function.client.WebClient;
Expand All @@ -34,7 +38,21 @@ public class CourseServiceTest {
private CourseRepository courseRepository;

@MockBean
WebClient webClient;
public OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository;

@MockBean
public OAuth2AuthorizedClientService oAuth2AuthorizedClientService;

@MockBean
public ClientRegistrationRepository clientRegistrationRepository;

@Qualifier("courseApiClient")
@MockBean
public WebClient courseApiClient;

@Qualifier("default")
@MockBean
public WebClient webClient;

@Test
public void testGetCourseList() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.reactive.function.client.WebClient;

import java.sql.Date;
import java.util.ArrayList;
Expand All @@ -30,6 +35,23 @@ public class EquivalentOrChallengeCodeServiceTest {

@MockBean
private EquivalentOrChallengeCodeRepository equivalentOrChallengeCodeRepository;

@MockBean
public OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository;

@MockBean
public OAuth2AuthorizedClientService oAuth2AuthorizedClientService;

@MockBean
public ClientRegistrationRepository clientRegistrationRepository;

@Qualifier("courseApiClient")
@MockBean
public WebClient courseApiClient;

@Qualifier("default")
@MockBean
public WebClient webClient;

@Test
public void testGetEquivalentOrChallengeCodeList() {
Expand Down
Loading

0 comments on commit f6a92d4

Please sign in to comment.