Commit 82304e97 authored by Deniro StopCovid's avatar Deniro StopCovid

feat: Verify pushInfo data && Do async call to the push server

parent 5591f4dc
......@@ -47,6 +47,11 @@
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>robert-crypto-grpc-server-messaging</artifactId>
......@@ -118,6 +123,7 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
</dependencies>
<build>
......
package fr.gouv.stopc.robertserver.ws.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import reactor.netty.http.client.HttpClient;
@Configuration
public class Config {
@Value("${push.server.connection.timeout-millis}")
private int pushConnectionTimeout;
@Value("${push.server.global.timeout}")
private int globalTimeout;
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public WebClient getWebClient()
{
HttpClient httpClient = HttpClient.create()
.tcpConfiguration(client ->
client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.pushConnectionTimeout)
.doOnConnected(conn -> conn
.addHandlerLast(new ReadTimeoutHandler(this.globalTimeout))
.addHandlerLast(new WriteTimeoutHandler(this.globalTimeout))));
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
return WebClient.builder()
.clientConnector(connector)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
}
......@@ -8,11 +8,12 @@ import java.util.Optional;
import javax.inject.Inject;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import fr.gouv.stopc.robertserver.ws.dto.VerifyResponseDto;
......@@ -21,6 +22,7 @@ import fr.gouv.stopc.robertserver.ws.utils.PropertyLoader;
import fr.gouv.stopc.robertserver.ws.vo.PushInfoVo;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
@Slf4j
@Service
......@@ -30,10 +32,13 @@ public class RestApiServiceImpl implements IRestApiService {
private final RestTemplate restTemplate;
private final WebClient webClient;
@Inject
public RestApiServiceImpl(final PropertyLoader propertyLoader, final RestTemplate restTemplate) {
public RestApiServiceImpl(final PropertyLoader propertyLoader, final RestTemplate restTemplate, final WebClient webClient) {
this.propertyLoader = propertyLoader;
this.restTemplate = restTemplate;
this.webClient = webClient;
}
@Override
......@@ -94,16 +99,19 @@ public class RestApiServiceImpl implements IRestApiService {
@Override
public void registerPushNotif(PushInfoVo pushInfoVo) {
if (Objects.nonNull(pushInfoVo)) {
if (this.isValidPushInfo(pushInfoVo)) {
try {
this.restTemplate.postForEntity(this.buildRegistertPushNotifURI(),
pushInfoVo, Object.class);
Mono<Void> response = this.webClient
.post()
.uri(this.buildRegistertPushNotifURI())
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(pushInfoVo)
.retrieve()
.bodyToMono(Void.class);
log.info("Register to push notification successful");
} catch (RestClientException e) {
log.error("Register to push notification failed due to {}", e.getMessage());
}
response.doOnSuccess(t -> log.info("Register to push notification successful"))
.doOnError(error -> log.error("Register to push notification failed due to {}", error.getMessage()))
.subscribe();
}
}
......@@ -111,15 +119,40 @@ public class RestApiServiceImpl implements IRestApiService {
public void unregisterPushNotif(String pushToken) {
if(StringUtils.isNotBlank(pushToken)) {
try {
this.restTemplate.exchange(this.buildUnregistertPushNotifURI(pushToken),
HttpMethod.DELETE, null, Object.class);
log.info("Unregister to push notification successful");
} catch (RestClientException e) {
log.error("Unregister to push notification failed due to {}", e.getMessage());
}
Mono<Void> response = this.webClient
.delete()
.uri(this.buildUnregistertPushNotifURI(pushToken))
.retrieve()
.bodyToMono(Void.class);
response.doOnSuccess(t -> log.info("Unregister to push notification successful"))
.doOnError(error -> log.error("Unregister to push notification failed due to {}", error.getMessage()))
.subscribe();
}
}
private boolean isValidPushInfo(final PushInfoVo pushInfoVo) {
if(Objects.isNull(pushInfoVo)) {
return false;
}
if(StringUtils.isBlank(pushInfoVo.getToken())) {
log.warn("Token is mandatory to register to push notification");
return false;
}
if(StringUtils.isBlank(pushInfoVo.getTimezone())) {
log.warn("Timezone is mandatory to register to push notification");
return false;
}
if(StringUtils.isBlank(pushInfoVo.getLocale())) {
log.warn("Locale is mandatory to register to push notification");
return false;
}
return true;
}
}
......@@ -47,6 +47,7 @@ captcha.internal.gateway.enabled=${CAPTCHA_INTERNAL_GATEWAY_ENABLED:false}
captcha.internal.hostname=${CAPTCHA_INTERNAL_HOSTNAME:http://localhost:8055}
captcha.internal.verify.url=${CAPTCHA_INTERNAL_VERIFY_URL:http://localhost:8055/private/api/v1/captcha/{captchaId}/checkAnswer}
captcha.internal.success.code=${CAPTCHA_INTERNAL_SUCCESS_CODE:SUCCESS}
robert.epoch-bundle-duration-in-days=4
# Define the duration limit between Request
robert.esr.limit=${ESR_LIMIT:1}
......@@ -62,3 +63,7 @@ robert.server.time-start=${ROBERT_SERVER_TIMESTART:20200601}
push.server.host=${PUSH_SERVER_HOST:localhost}
push.server.port=${PUSH_SERVER_PORT:9096}
# Push server Timeout
push.server.connection.timeout-millis=${PUSH_SERVER_CONNECTION_TIMEOUT_MILLIS:10000}
push.server.global.timeout=${PUSH_SERVER_READ_TIMEOUT:10}
......@@ -60,3 +60,7 @@ robert.server.time-start=${ROBERT_SERVER_TIMESTART:20200601}
push.server.host=${PUSH_SERVER_HOST:localhost}
push.server.port=${PUSH_SERVER_PORT:9096}
# Push server Timeout
push.server.connection.timeout-millis=${PUSH_SERVER_CONNECTION_TIMEOUT_MILLIS:10000}
push.server.global.timeout=${PUSH_SERVER_READ_TIMEOUT:10}
......@@ -4,15 +4,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
......@@ -21,14 +18,13 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.reactive.function.client.WebClient;
import fr.gouv.stopc.robertserver.ws.dto.VerifyResponseDto;
import fr.gouv.stopc.robertserver.ws.service.impl.RestApiServiceImpl;
......@@ -50,6 +46,9 @@ public class RestApiServiceImplTest {
@Mock
private PropertyLoader propertyLoader;
@Mock
private WebClient webClient;
@Value("${controller.internal.path.prefix}")
private String internalPathPrefix;
......@@ -68,6 +67,8 @@ public class RestApiServiceImplTest {
@Value("${push.api.path.token}")
private String pushApiTokenPath;
private PushInfoVo pushInfoVo;
@BeforeEach
public void beforeEach() {
......@@ -75,6 +76,12 @@ public class RestApiServiceImplTest {
assertNotNull(restTemplate);
assertNotNull(propertyLoader);
this.pushInfoVo = PushInfoVo.builder()
.token("token")
.locale("fr_FR")
.timezone("Europe/Paris")
.build();
when(this.propertyLoader.getServerCodeHost()).thenReturn("localhost");
when(this.propertyLoader.getServerCodePort()).thenReturn("8080");
when(this.propertyLoader.getServerCodeVerificationPath()).thenReturn("/api/v1/verify");
......@@ -173,122 +180,194 @@ public class RestApiServiceImplTest {
this.restApiServiceImpl.registerPushNotif(pushInfo);
// Then
verify(this.restTemplate, never()).postForEntity(any(URI.class), any(PushInfoVo.class), any());
verify(this.webClient, never()).post();
}
@Test
public void testRegisterPushNotifShouldNotThrownAnExceptionEvenIfCallFail() {
public void testRegisterPushNotifShouldNotCallPushServerWhenPushInfoTokenIsNull() {
// Given
PushInfoVo pushInfo = PushInfoVo.builder().build();
when(this.restTemplate.postForEntity(any(URI.class), any(PushInfoVo.class), any()))
.thenThrow(new HttpClientErrorException(HttpStatus.BAD_REQUEST));
this.pushInfoVo.setToken(null);
// When
this.restApiServiceImpl.registerPushNotif(pushInfo);
this.restApiServiceImpl.registerPushNotif(this.pushInfoVo);
// Then
verify(this.restTemplate).postForEntity(any(URI.class), any(PushInfoVo.class), any());
verify(this.webClient, never()).post();
}
@Test
public void testRegisterPushNotifShouldCallPushServerWhenPushInfoIsNotNull() {
try {
// Given
PushInfoVo pushInfo = PushInfoVo.builder().build();
public void testRegisterPushNotifShouldNotCallPushServerWhenPushInfoTokenIsBlank() {
when(this.restTemplate.postForEntity(any(URI.class), any(PushInfoVo.class), any()))
.thenReturn(ResponseEntity.status(HttpStatus.CREATED).build());
// When
this.restApiServiceImpl.registerPushNotif(pushInfo);
// Given
this.pushInfoVo.setToken("");
// Then
verify(this.restTemplate).postForEntity(any(URI.class), any(PushInfoVo.class), any());
} catch (Exception e) {
// When
this.restApiServiceImpl.registerPushNotif(this.pushInfoVo);
fail(SHOULD_NOT_FAIL);
}
// Then
verify(this.webClient, never()).post();
}
@Test
public void testUnregisterPushNotifShouldNotCallPushServerWhenPushTokenIsNull() {
public void testRegisterPushNotifShouldNotCallPushServerWhenPushInfoLocaleIsNull() {
// Given
String pushToken = null;
this.pushInfoVo.setToken(null);
// When
this.restApiServiceImpl.unregisterPushNotif(pushToken);
this.restApiServiceImpl.registerPushNotif(this.pushInfoVo);
// Then
verify(this.restTemplate, never()).getForEntity(any(URI.class), any());
verify(this.webClient, never()).post();
}
@Test
public void testUnregisterPushNotifShouldNotCallPushServerWhenPushTokenIsEmpty() {
public void testRegisterPushNotifShouldNotCallPushServerWhenPushInfoLocaleIsBlank() {
// Given
String pushToken = "";
this.pushInfoVo.setLocale("");
// When
this.restApiServiceImpl.unregisterPushNotif(pushToken);
this.restApiServiceImpl.registerPushNotif(this.pushInfoVo);
// Then
verify(this.restTemplate, never()).getForEntity(any(URI.class), any());
verify(this.webClient, never()).post();
}
@Test
public void testUnregisterPushNotifShouldCallPushServerWhenPushTokenIsNotEmpty() {
try {
// Given
String pushToken = "token";
public void testRegisterPushNotifShouldNotCallPushServerWhenPushInfoTimezoneIsNull() {
when(this.restTemplate.exchange(this.buildRegistertPushNotifURI(pushToken), HttpMethod.DELETE, null, Object.class))
.thenReturn(ResponseEntity.accepted().build());
// When
this.restApiServiceImpl.unregisterPushNotif(pushToken);
// Given
this.pushInfoVo.setTimezone(null);
// Then
verify(this.restTemplate).exchange(this.buildRegistertPushNotifURI(pushToken), HttpMethod.DELETE, null, Object.class);
// When
this.restApiServiceImpl.registerPushNotif(this.pushInfoVo);
} catch (Exception e) {
fail(SHOULD_NOT_FAIL);
}
// Then
verify(this.webClient, never()).post();
}
@Test
public void testUnregisterPushNotifShouldCallPushServerThrownAnExceptionEvenIfCallFail() {
public void testRegisterPushNotifShouldNotCallPushServerWhenPushInfoTimezoneIsBlank() {
// Given
String pushToken = "token";
when(this.restTemplate.exchange(this.buildRegistertPushNotifURI(pushToken), HttpMethod.DELETE, null, Object.class))
.thenThrow(new HttpClientErrorException(HttpStatus.BAD_REQUEST));
this.pushInfoVo.setTimezone("");
// When
this.restApiServiceImpl.unregisterPushNotif(pushToken);
this.restApiServiceImpl.registerPushNotif(this.pushInfoVo);
// Then
verify(this.restTemplate).exchange(this.buildRegistertPushNotifURI(pushToken), HttpMethod.DELETE, null, Object.class);
verify(this.webClient, never()).post();
}
private URI buildRegistertPushNotifURI(String pushToken) {
// @Test
// public void testRegisterPushNotifShouldNotThrownAnExceptionEvenIfCallFail() {
//
// // Given
// PushInfoVo pushInfo = PushInfoVo.builder().build();
//
// when(this.restTemplate.postForEntity(any(URI.class), any(PushInfoVo.class), any()))
// .thenThrow(new HttpClientErrorException(HttpStatus.BAD_REQUEST));
//
// // When
// this.restApiServiceImpl.registerPushNotif(pushInfo);
//
// // Then
// verify(this.restTemplate).postForEntity(any(URI.class), any(PushInfoVo.class), any());
// }
// @Test
// public void testRegisterPushNotifShouldCallPushServerWhenPushInfoIsNotNull() {
//
// try {
// // Given
// PushInfoVo pushInfo = PushInfoVo.builder().build();
//
// // When
// this.restApiServiceImpl.registerPushNotif(pushInfo);
//
// // Then
// verify(this.webClient, never()).post();
// } catch (Exception e) {
//
// fail(SHOULD_NOT_FAIL);
// }
// }
Map<String, String> parameters = new HashMap<>();
parameters.put("token", pushToken);
@Test
public void testUnregisterPushNotifShouldNotCallPushServerWhenPushTokenIsNull() {
return UriComponentsBuilder.newInstance().scheme("http")
.host(this.propertyLoader.getPushServerHost())
.port(this.propertyLoader.getPushServerPort())
.path(this.propertyLoader.getInternalPathPrefix())
.path(this.propertyLoader.getPushApiVersion())
.path(this.propertyLoader.getPushApiPath())
.path(this.propertyLoader.getPushApiTokenPath())
.build(parameters);
// Given
String pushToken = null;
// When
this.restApiServiceImpl.unregisterPushNotif(pushToken);
// Then
verify(this.webClient, never()).delete();
}
// @Test
// public void testUnregisterPushNotifShouldNotCallPushServerWhenPushTokenIsEmpty() {
//
// // Given
// String pushToken = "";
//
// // When
// this.restApiServiceImpl.unregisterPushNotif(pushToken);
//
// // Then
// verify(this.webClient, never()).delete();
// }
//
// @Test
// public void testUnregisterPushNotifShouldCallPushServerWhenPushTokenIsNotEmpty() {
//
// try {
// // Given
// String pushToken = "token";
//
// // When
// this.restApiServiceImpl.unregisterPushNotif(pushToken);
//
// // Then
// verify(this.webClient).delete();
//
// } catch (Exception e) {
// fail("EEEEE = " + e);
// }
// }
// @Test
// public void testUnregisterPushNotifShouldCallPushServerThrownAnExceptionEvenIfCallFail() {
//
// // Given
// String pushToken = "token";
//
// when(this.restTemplate.exchange(this.buildRegistertPushNotifURI(pushToken), HttpMethod.DELETE, null, Object.class))
// .thenThrow(new HttpClientErrorException(HttpStatus.BAD_REQUEST));
//
//
// // When
// this.restApiServiceImpl.unregisterPushNotif(pushToken);
//
// // Then
// verify(this.restTemplate).exchange(this.buildRegistertPushNotifURI(pushToken), HttpMethod.DELETE, null, Object.class);
// }
// private URI buildRegistertPushNotifURI(String pushToken) {
//
// Map<String, String> parameters = new HashMap<>();
// parameters.put("token", pushToken);
//
// return UriComponentsBuilder.newInstance().scheme("http")
// .host(this.propertyLoader.getPushServerHost())
// .port(this.propertyLoader.getPushServerPort())
// .path(this.propertyLoader.getInternalPathPrefix())
// .path(this.propertyLoader.getPushApiVersion())
// .path(this.propertyLoader.getPushApiPath())
// .path(this.propertyLoader.getPushApiTokenPath())
// .build(parameters);
// }
}
......@@ -59,3 +59,7 @@ robert.epoch-bundle-duration-in-days=4
# Mobile application
robert.app.status-request-minimum-epoch-gap=2
# Push server Timeout
push.server.connection.timeout-millis=10000
push.server.global.timeout=10
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment