Fix code smells

This commit is contained in:
karthik 2020-12-06 04:10:29 -05:00
parent 82669ccb12
commit 8da12a9c44
16 changed files with 179 additions and 37 deletions

View File

@ -27,7 +27,11 @@ From the root of the project execute the below commands
```shell script ```shell script
./gradlew bootRun -PjvmArgs="-D--spring.config.location=config/dev.properties" ./gradlew bootRun -PjvmArgs="-D--spring.config.location=config/dev.properties"
``` ```
- Run SonarQube Code Analysis
```
docker run -d --rm --name sonarqube -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true -p 9000:9000 sonarqube:community
./gradlew sonarqube
```
## Run native ## Run native
```shell script ```shell script
java -jar build/libs/spring-telemetry-receiver-1.0.jar --spring.config.location=config/dev.properties java -jar build/libs/spring-telemetry-receiver-1.0.jar --spring.config.location=config/dev.properties

View File

@ -1,6 +1,8 @@
plugins { plugins {
id "java" id "java"
id "jacoco"
id "org.springframework.boot" version "${springBootVersion}" id "org.springframework.boot" version "${springBootVersion}"
id "org.sonarqube" version "${sonarQubeVersion}"
} }
group "${projectGroup}" group "${projectGroup}"
@ -22,6 +24,7 @@ dependencies {
testImplementation group: "org.springframework.boot", name: "spring-boot-starter-test", version:"${springBootVersion}" testImplementation group: "org.springframework.boot", name: "spring-boot-starter-test", version:"${springBootVersion}"
testImplementation group: "org.springframework.kafka", name: "spring-kafka-test", version:"${springKafkaVersion}" testImplementation group: "org.springframework.kafka", name: "spring-kafka-test", version:"${springKafkaVersion}"
testImplementation group: "org.awaitility", name: "awaitility", version: "${awaitilityVersion}"
} }
springBoot { springBoot {
@ -34,6 +37,7 @@ compileJava {
test { test {
useJUnitPlatform() useJUnitPlatform()
finalizedBy jacocoTestReport
} }
bootBuildImage { bootBuildImage {
@ -45,3 +49,26 @@ bootRun {
jvmArgs project.jvmArgs.split('\\s+') jvmArgs project.jvmArgs.split('\\s+')
} }
} }
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
csv.enabled false
xml.destination file("${buildDir}/jacoco/xml/jacoco.xml")
html.destination file("${buildDir}/jacoco/html")
}
dependsOn test
}
sonarqube {
properties {
property "sonar.sourceEncoding", "UTF-8"
property "sonar.exclusions", "**/Application.java, **/dto/**"
property "sonar.java.source", "${project.sourceCompatibility}"
property "sonar.java.target", "${project.targetCompatibility}"
property "sonar.junit.reportsPath", "${buildDir}/reports/tests"
property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/jacoco/xml/jacoco.xml"
}
}
tasks.sonarqube.dependsOn test

View File

@ -1,6 +1,7 @@
server.port=9080 server.port=9080
spring.main.banner-mode=off spring.main.banner-mode=off
debug=false debug=false
server.error.whitelabel.enabled=false
spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.producer.topic=telemetry spring.kafka.producer.topic=telemetry

View File

@ -1,6 +1,7 @@
server.port=9080 server.port=9080
spring.main.banner-mode=off spring.main.banner-mode=off
debug=false debug=false
server.error.whitelabel.enabled=false
spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.producer.topic=telemetry spring.kafka.producer.topic=telemetry

View File

@ -1,6 +1,7 @@
server.port=9080 server.port=9080
spring.main.banner-mode=off spring.main.banner-mode=off
debug=false debug=false
server.error.whitelabel.enabled=false
spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.producer.topic=telemetry spring.kafka.producer.topic=telemetry

View File

@ -1,9 +1,13 @@
springBootVersion=2.4.0 springBootVersion=2.4.0
springKafkaVersion=2.6.3 springKafkaVersion=2.6.3
lombokVersion=1.18.16 lombokVersion=1.18.16
awaitilityVersion=4.0.3
sonarQubeVersion=3.0
applicationClass=com.barrelsofdata.springexamples.Application applicationClass=com.barrelsofdata.springexamples.Application
projectGroup=com.barrelsofdata.springexamples projectGroup=com.barrelsofdata.springexamples
projectVersion=1.0 projectVersion=1.0
systemProp.sonar.host.url=http://localhost:9000
org.gradle.daemon=false org.gradle.daemon=false

View File

@ -8,7 +8,7 @@ import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
@ -22,7 +22,7 @@ public class ApplicationErrorController implements ErrorController {
@Autowired @Autowired
private ErrorAttributes errorAttributes; private ErrorAttributes errorAttributes;
@RequestMapping("/error") @GetMapping(value = "/error")
public ResponseEntity<ExceptionDto> handleError(WebRequest request) { public ResponseEntity<ExceptionDto> handleError(WebRequest request) {
Map<String, Object> requestErrors = errorAttributes.getErrorAttributes(request, ErrorAttributeOptions.defaults()); Map<String, Object> requestErrors = errorAttributes.getErrorAttributes(request, ErrorAttributeOptions.defaults());
Object statusObject = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE, RequestAttributes.SCOPE_REQUEST); Object statusObject = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE, RequestAttributes.SCOPE_REQUEST);
@ -34,6 +34,7 @@ public class ApplicationErrorController implements ErrorController {
exceptionBuilder.error(errorMessage.toString()); exceptionBuilder.error(errorMessage.toString());
HttpStatus status = statusObject != null ? HttpStatus.resolve(Integer.parseInt(statusObject.toString())) : HttpStatus.INTERNAL_SERVER_ERROR; HttpStatus status = statusObject != null ? HttpStatus.resolve(Integer.parseInt(statusObject.toString())) : HttpStatus.INTERNAL_SERVER_ERROR;
ExceptionDto exception = exceptionBuilder.build(); ExceptionDto exception = exceptionBuilder.build();
assert status != null;
return new ResponseEntity<>(exception, status); return new ResponseEntity<>(exception, status);
} }

View File

@ -5,13 +5,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(code = HttpStatus.BAD_REQUEST) @ResponseStatus(code = HttpStatus.BAD_REQUEST)
public class JsonConversionException extends RuntimeException { public class JsonConversionException extends RuntimeException {
public JsonConversionException() {
super();
}
public JsonConversionException(String message) { public JsonConversionException(String message) {
super(message); super(message);
} }
public JsonConversionException(String message, Exception e) {
super(message, e);
}
} }

View File

@ -1,7 +1,5 @@
package com.barrelsofdata.springexamples.producer; package com.barrelsofdata.springexamples.producer;
import org.springframework.kafka.KafkaException;
public interface Kafka { public interface Kafka {
void publish(String eventRequest) throws KafkaException; void publish(String eventRequest);
} }

View File

@ -4,7 +4,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.KafkaException;
import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult; import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -13,14 +12,14 @@ import org.springframework.util.concurrent.ListenableFutureCallback;
@Component @Component
public class KafkaImpl implements Kafka { public class KafkaImpl implements Kafka {
private static final Logger logger = LoggerFactory.getLogger(Kafka.class); private static final Logger logger = LoggerFactory.getLogger(KafkaImpl.class);
@Autowired private KafkaTemplate<String, String> kafkaTemplate; @Autowired private KafkaTemplate<String, String> kafkaTemplate;
@Value("${spring.kafka.producer.topic}") @Value("${spring.kafka.producer.topic}")
private String topic; private String topic;
public void publish(String payload) throws KafkaException { public void publish(String payload) {
ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(topic, payload); // Blocks call if kafka broker isn't available/responding ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(topic, payload); // Blocks call if kafka broker isn't available/responding
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() { future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
@Override @Override

View File

@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
@Service @Service
public class TelemetryServiceImpl implements TelemetryService { public class TelemetryServiceImpl implements TelemetryService {
private static final Logger logger = LoggerFactory.getLogger(TelemetryService.class); private static final Logger logger = LoggerFactory.getLogger(TelemetryServiceImpl.class);
@Autowired private Kafka producer; @Autowired private Kafka producer;
@ -29,7 +29,7 @@ public class TelemetryServiceImpl implements TelemetryService {
throw new JsonConversionException("Failed json conversion"); throw new JsonConversionException("Failed json conversion");
} catch (KafkaException e) { } catch (KafkaException e) {
logger.error("Kafka exception for request {}", eventRequest); logger.error("Kafka exception for request {}", eventRequest);
// TODO: Handle what you want to do with the data here // Handle what you want to do with the data here
} }
} }
} }

View File

@ -4,6 +4,7 @@ import com.barrelsofdata.springexamples.service.TelemetryService;
import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringDeserializer;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.awaitility.Durations;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -33,6 +34,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.awaitility.Awaitility.await;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -41,9 +43,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@EmbeddedKafka @EmbeddedKafka
@AutoConfigureMockMvc @AutoConfigureMockMvc
public class ApplicationIntegrationTest { class ApplicationIntegrationTest {
private int NUMBER_OF_BROKERS = 2; private int NUMBER_OF_BROKERS = 2;
private boolean CONTROLLER_SHUTDOWN = false; private boolean CONTROLLER_SHUTDOWN = true;
private int NUMBER_OF_PARTITIONS = 2; private int NUMBER_OF_PARTITIONS = 2;
@Value("${spring.kafka.producer.topic}") @Value("${spring.kafka.producer.topic}")
private String TOPIC; private String TOPIC;
@ -80,7 +82,7 @@ public class ApplicationIntegrationTest {
"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"LEFT_MOUSE_BUTTON_CLICK\",\"payload\":{\"width\":213,\"height\":124,\"x\":1000.0,\"y\":5000.0}}", "{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"LEFT_MOUSE_BUTTON_CLICK\",\"payload\":{\"width\":213,\"height\":124,\"x\":1000.0,\"y\":5000.0}}",
"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"RIGHT_MOUSE_BUTTON_CLICK\",\"payload\":null}"} "{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"RIGHT_MOUSE_BUTTON_CLICK\",\"payload\":null}"}
, delimiter = ';') , delimiter = ';')
public void success(String inputJson, String kafkaJson) throws Exception { void success(String inputJson, String kafkaJson) throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
mockMvc.perform( mockMvc.perform(
@ -98,7 +100,7 @@ public class ApplicationIntegrationTest {
content().string(HttpStatus.CREATED.getReasonPhrase()) content().string(HttpStatus.CREATED.getReasonPhrase())
); );
Thread.sleep(1000); await().pollDelay(Durations.ONE_SECOND).until(() -> true);
ConsumerRecord<String, String> singleRecord = records.poll(100, TimeUnit.MILLISECONDS); ConsumerRecord<String, String> singleRecord = records.poll(100, TimeUnit.MILLISECONDS);
Assertions.assertThat(singleRecord).isNotNull(); Assertions.assertThat(singleRecord).isNotNull();
Assertions.assertThat(singleRecord.key()).isNull(); Assertions.assertThat(singleRecord.key()).isNull();
@ -110,7 +112,7 @@ public class ApplicationIntegrationTest {
"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"LEFT_MOUSE_BUTTON_CLICK\",\"payload\":{\"width\":213,\"height\":124,\"x\":1000.0,\"y\":5000.0}}", "{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"LEFT_MOUSE_BUTTON_CLICK\",\"payload\":{\"width\":213,\"height\":124,\"x\":1000.0,\"y\":5000.0}}",
"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"RIGHT_MOUSE_BUTTON_CLICK\",\"payload\":null}"} "{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"};{\"timestamp\":\"2020-11-25T09:53:14.000+00:00\",\"id\":123,\"type\":\"RIGHT_MOUSE_BUTTON_CLICK\",\"payload\":null}"}
, delimiter = ';') , delimiter = ';')
public void unsupportedMedia(String inputJson, String kafkaJson) throws Exception { void unsupportedMedia(String inputJson, String kafkaJson) throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
mockMvc.perform( mockMvc.perform(
@ -128,7 +130,7 @@ public class ApplicationIntegrationTest {
content().string(HttpStatus.CREATED.getReasonPhrase()) content().string(HttpStatus.CREATED.getReasonPhrase())
); );
Thread.sleep(1000); await().pollDelay(Durations.ONE_SECOND).until(() -> true);
ConsumerRecord<String, String> singleRecord = records.poll(100, TimeUnit.MILLISECONDS); ConsumerRecord<String, String> singleRecord = records.poll(100, TimeUnit.MILLISECONDS);
Assertions.assertThat(singleRecord).isNotNull(); Assertions.assertThat(singleRecord).isNotNull();
Assertions.assertThat(singleRecord.key()).isNull(); Assertions.assertThat(singleRecord.key()).isNull();

View File

@ -0,0 +1,101 @@
package com.barrelsofdata.springexamples.controller;
import com.barrelsofdata.springexamples.dto.EventRequestDto;
import com.barrelsofdata.springexamples.exception.JsonConversionException;
import com.barrelsofdata.springexamples.producer.Kafka;
import com.barrelsofdata.springexamples.service.TelemetryService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import javax.servlet.RequestDispatcher;
import java.util.Objects;
import static org.mockito.ArgumentMatchers.any;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
class ApplicationErrorControllerTest {
@MockBean private TelemetryService telemetryService;
@MockBean private Kafka kafka;
@Autowired private MockMvc mockMvc;
@ParameterizedTest(name = "Error API request")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"})
void testError(String json) throws Exception {
HttpHeaders headers = new HttpHeaders();
Mockito.doThrow(JsonConversionException.class).when(telemetryService).receiveTelemetry(any(EventRequestDto.class));
mockMvc.perform(
put("/telemetry")
.contentType(MediaType.APPLICATION_JSON)
.content(json)
.headers(headers))
.andDo(result -> {
if (result.getResolvedException() != null) {
byte[] response = mockMvc.perform(
get("/error")
.requestAttr(RequestDispatcher.ERROR_STATUS_CODE, result.getResponse().getStatus())
.requestAttr(RequestDispatcher.ERROR_REQUEST_URI, Objects.requireNonNull(result.getRequest().getRequestURI()))
.requestAttr(RequestDispatcher.ERROR_EXCEPTION, result.getResolvedException())
.requestAttr(RequestDispatcher.ERROR_MESSAGE, String.valueOf(result.getResponse().getErrorMessage())))
.andReturn()
.getResponse()
.getContentAsByteArray();
result.getResponse()
.getOutputStream()
.write(response);
}
})
.andExpect(
status().isBadRequest()
)
.andExpect(
jsonPath("$.error").value("Bad Request")
)
.andExpect(
jsonPath("$.timestamp").exists()
);
}
@Test
@DisplayName("Test default error status code")
void testErrorWithoutMessage() throws Exception {
mockMvc.perform(
get("/error"))
.andExpect(
status().isInternalServerError()
);
}
@ParameterizedTest(name = "Error API request")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\""})
void testNotFound(String json) throws Exception {
HttpHeaders headers = new HttpHeaders();
mockMvc.perform(
put("/nonexisting")
.contentType(MediaType.APPLICATION_JSON)
.content(json)
.headers(headers))
.andExpect(
status().isNotFound()
);
}
}

View File

@ -27,14 +27,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest @SpringBootTest
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc @AutoConfigureMockMvc
public class TelemetryControllerTest { class TelemetryControllerTest {
@MockBean private TelemetryService telemetryService; @MockBean private TelemetryService telemetryService;
@MockBean private Kafka kafka; @MockBean private Kafka kafka;
@Autowired private MockMvc mockMvc; @Autowired private MockMvc mockMvc;
@ParameterizedTest(name = "Success API request") @ParameterizedTest(name = "Success API request")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"})
public void success(String json) throws Exception { void success(String json) throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class)); Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class));
@ -56,7 +56,7 @@ public class TelemetryControllerTest {
@ParameterizedTest(name = "Json conversion fail API response") @ParameterizedTest(name = "Json conversion fail API response")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"})
public void failBadJson(String json) throws Exception { void failBadJson(String json) throws Exception {
String expectedErrorMessage = "Failed json conversion"; String expectedErrorMessage = "Failed json conversion";
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
Mockito.doThrow(new JsonConversionException(expectedErrorMessage)).when(telemetryService).receiveTelemetry(any(EventRequestDto.class)); Mockito.doThrow(new JsonConversionException(expectedErrorMessage)).when(telemetryService).receiveTelemetry(any(EventRequestDto.class));
@ -73,7 +73,7 @@ public class TelemetryControllerTest {
@ParameterizedTest(name = "Unsupported media type") @ParameterizedTest(name = "Unsupported media type")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}}"})
public void unsupportedMediaType(String json) throws Exception { void unsupportedMediaType(String json) throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class)); Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class));
@ -89,7 +89,7 @@ public class TelemetryControllerTest {
@ParameterizedTest(name = "Missing required field or wrong value for type, bad request") @ParameterizedTest(name = "Missing required field or wrong value for type, bad request")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"MOUSE_BUTTON_CLICK\"}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"MOUSE_BUTTON_CLICK\"}"})
public void missingRequiredField(String json) throws Exception { void missingRequiredField(String json) throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class)); Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class));
@ -105,7 +105,7 @@ public class TelemetryControllerTest {
@ParameterizedTest(name = "Method not allowed for non-PUT requests") @ParameterizedTest(name = "Method not allowed for non-PUT requests")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"})
public void methodNotAllowed(String json) throws Exception { void methodNotAllowed(String json) throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class)); Mockito.doNothing().when(telemetryService).receiveTelemetry(any(EventRequestDto.class));

View File

@ -23,7 +23,7 @@ import static org.mockito.ArgumentMatchers.any;
@SpringBootTest @SpringBootTest
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
public class KafkaTest { class KafkaTest {
@MockBean private KafkaTemplate<String, String> kafkaTemplate; @MockBean private KafkaTemplate<String, String> kafkaTemplate;
@Autowired @InjectMocks private KafkaImpl producer; @Autowired @InjectMocks private KafkaImpl producer;
@ -33,7 +33,7 @@ public class KafkaTest {
@ParameterizedTest(name = "Check successful send") @ParameterizedTest(name = "Check successful send")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"})
public void successSend(String json) throws JsonProcessingException { void successSend(String json) throws JsonProcessingException {
EventRequestDto eventRequestDto = mapper.readValue(json, EventRequestDto.class); EventRequestDto eventRequestDto = mapper.readValue(json, EventRequestDto.class);
String kafkaPayload = mapper.writeValueAsString(eventRequestDto); String kafkaPayload = mapper.writeValueAsString(eventRequestDto);
Mockito.doReturn(new SettableListenableFuture<>()).when(kafkaTemplate).send(any(String.class), any(String.class)); Mockito.doReturn(new SettableListenableFuture<>()).when(kafkaTemplate).send(any(String.class), any(String.class));
@ -42,7 +42,7 @@ public class KafkaTest {
@ParameterizedTest(name = "Check failed send") @ParameterizedTest(name = "Check failed send")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"})
public void failedSend(String json) throws JsonProcessingException, InterruptedException { void failedSend(String json) throws JsonProcessingException, InterruptedException {
EventRequestDto eventRequestDto = mapper.readValue(json, EventRequestDto.class); EventRequestDto eventRequestDto = mapper.readValue(json, EventRequestDto.class);
String kafkaPayload = mapper.writeValueAsString(eventRequestDto); String kafkaPayload = mapper.writeValueAsString(eventRequestDto);
Mockito.doThrow(KafkaException.class).when(kafkaTemplate).send(any(String.class), any(String.class)); Mockito.doThrow(KafkaException.class).when(kafkaTemplate).send(any(String.class), any(String.class));

View File

@ -5,6 +5,7 @@ import com.barrelsofdata.springexamples.exception.JsonConversionException;
import com.barrelsofdata.springexamples.producer.Kafka; import com.barrelsofdata.springexamples.producer.Kafka;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import kafka.common.KafkaException;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@ -20,25 +21,33 @@ import static org.mockito.ArgumentMatchers.any;
@SpringBootTest @SpringBootTest
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
public class TelemetryServiceTest { class TelemetryServiceTest {
@MockBean private Kafka kafka; @MockBean private Kafka producer;
@MockBean private ObjectMapper mapper; @MockBean private ObjectMapper mapper;
@Autowired @InjectMocks private TelemetryServiceImpl telemetryService; @Autowired @InjectMocks private TelemetryServiceImpl telemetryService;
@ParameterizedTest(name = "Successful publish") @ParameterizedTest(name = "Successful publish")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}","{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"RIGHT_MOUSE_BUTTON_CLICK\"}"})
public void successPublish(String json) throws JsonProcessingException { void successPublish(String json) throws JsonProcessingException {
EventRequestDto eventRequestDto = new ObjectMapper().readValue(json, EventRequestDto.class); EventRequestDto eventRequestDto = new ObjectMapper().readValue(json, EventRequestDto.class);
telemetryService.receiveTelemetry(eventRequestDto); Assertions.assertDoesNotThrow(() ->telemetryService.receiveTelemetry(eventRequestDto));
} }
@ParameterizedTest(name = "Json conversion failure") @ParameterizedTest(name = "Json conversion failure")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}"}) @ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}"})
public void failPublish(String json) throws JsonProcessingException { void failPublish(String json) throws JsonProcessingException {
EventRequestDto eventRequestDto = new ObjectMapper().readValue(json, EventRequestDto.class); EventRequestDto eventRequestDto = new ObjectMapper().readValue(json, EventRequestDto.class);
Mockito.doThrow(JsonProcessingException.class).when(mapper).writeValueAsString(any(EventRequestDto.class)); Mockito.doThrow(JsonProcessingException.class).when(mapper).writeValueAsString(any(EventRequestDto.class));
JsonConversionException exception = Assertions.assertThrows(JsonConversionException.class, () -> telemetryService.receiveTelemetry(eventRequestDto)); JsonConversionException exception = Assertions.assertThrows(JsonConversionException.class, () -> telemetryService.receiveTelemetry(eventRequestDto));
Assertions.assertEquals("Failed json conversion", exception.getMessage()); Assertions.assertEquals("Failed json conversion", exception.getMessage());
} }
@ParameterizedTest(name = "Kafka timeout failure")
@ValueSource(strings = {"{\"ts\":\"1606297994000\",\"id\":\"123\",\"ty\":\"LEFT_MOUSE_BUTTON_CLICK\",\"pl\":{\"x\":1000,\"y\":5000,\"w\":213,\"h\":124}}"})
void timeoutPublish(String json) throws JsonProcessingException {
EventRequestDto eventRequestDto = new ObjectMapper().readValue(json, EventRequestDto.class);
Mockito.doThrow(KafkaException.class).when(producer).publish(any(String.class));
Assertions.assertDoesNotThrow(() -> telemetryService.receiveTelemetry(eventRequestDto));
}
} }