diff --git a/pom.xml b/pom.xml
index 9b8b3ea..c6d195c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,14 +92,48 @@
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
test
-
+
+
+ flapdoodle
+
+ false
+
+
+
+ de.flapdoodle.embed
+ de.flapdoodle.embed.mongo
+ test
+
+
+
+
+
diff --git a/src/main/java/de/wirvsvirus/testresult/backend/rest/TestResultController.java b/src/main/java/de/wirvsvirus/testresult/backend/rest/TestResultController.java
index 187a2fe..b37d137 100644
--- a/src/main/java/de/wirvsvirus/testresult/backend/rest/TestResultController.java
+++ b/src/main/java/de/wirvsvirus/testresult/backend/rest/TestResultController.java
@@ -39,7 +39,7 @@ public Optional getTestResult(@PathVariable("id") String id) {
public TestResult addTestResult(@PathVariable("id") String id, @RequestBody TestResult testResult)
throws FalseInformedException {
testResult.setId(id);
-
+//TODO logic should be moved to service
Optional previousResultOptional = testResultService.getTestResult(id);
if (!previousResultOptional.isPresent()) {
return informNegatives(testResult);
@@ -66,7 +66,7 @@ public class ErrorResult{
TestResult result;
String comment;
}
-
+ //TODO saving should not depend on notification, we also get updates on the status that do not trigger notification
private TestResult informNegatives(TestResult testResult) {
TestResult saveResult;
try {
diff --git a/src/main/java/de/wirvsvirus/testresult/backend/service/TestResultPushService.java b/src/main/java/de/wirvsvirus/testresult/backend/service/TestResultPushService.java
index ba36917..79134a0 100644
--- a/src/main/java/de/wirvsvirus/testresult/backend/service/TestResultPushService.java
+++ b/src/main/java/de/wirvsvirus/testresult/backend/service/TestResultPushService.java
@@ -1,8 +1,5 @@
package de.wirvsvirus.testresult.backend.service;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.InternetAddress;
-
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@@ -17,9 +14,11 @@
@Component
@Slf4j
public class TestResultPushService {
- private static final String MOBILE_PATTERN = "[+491|01]\\d+";
+ private static final String MOBILE_PATTERN = "^(\\+491|01|00491)\\d+";
private static final String MOBILE_CLEANUP_PATTERN = "[^(\\d|+)]";
+ private static final String EMAIL_REGEX = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
+
private static final String FROM_VALUE = "Krankenhaus";
private static final String NEGATIV_TEXT = "Wir freuen uns Ihnen mitteilen zu können, dass ihr COVID-19 Testergebnis negativ ist. Der Virus konnte bei Ihnen nicht festegestellt werden.";
@@ -42,7 +41,7 @@ public boolean executePush(TestResult testProcess) {
boolean pushDone=false;
- if(isValidEmailAddress(contact)) {
+ if(contact.matches(EMAIL_REGEX)) {
message.setContact(contact);
try {
emailService.sendMail(message);
@@ -50,7 +49,7 @@ public boolean executePush(TestResult testProcess) {
} catch (MailSendingException e) {
log.debug("sending mail failed",e);
}
- }else if (contact.replaceAll(MOBILE_CLEANUP_PATTERN, "").matches(MOBILE_PATTERN)) {
+ }else if (contact.replaceAll("\\s", "").matches(MOBILE_PATTERN)) {
try {
message.setContact(contact.replaceAll(MOBILE_CLEANUP_PATTERN, ""));
smsService.sendNegativeResultSms(message);
@@ -68,15 +67,4 @@ private PushMessage createMessage() {
message.setText(NEGATIV_TEXT);
return message;
}
-
- public static boolean isValidEmailAddress(String email) {
- boolean result = true;
- try {
- InternetAddress emailAddr = new InternetAddress(email);
- emailAddr.validate();
- } catch (AddressException ex) {
- result = false;
- }
- return result;
- }
}
diff --git a/src/test/java/de/wirvsvirus/testresult/backend/rest/TestResultControllerIT.java b/src/test/java/de/wirvsvirus/testresult/backend/rest/TestResultControllerIT.java
new file mode 100644
index 0000000..dc24804
--- /dev/null
+++ b/src/test/java/de/wirvsvirus/testresult/backend/rest/TestResultControllerIT.java
@@ -0,0 +1,69 @@
+package de.wirvsvirus.testresult.backend.rest;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.bson.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+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.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import de.wirvsvirus.testresult.backend.persistence.TestResultRepo;
+
+@AutoConfigureMockMvc
+@SpringBootTest
+class TestResultControllerIT {
+
+ @Autowired
+ public MockMvc mvc;
+
+ @Autowired
+ TestResultRepo repo;
+
+ private static final String RESULTID = "123";
+
+ @BeforeEach
+ public void cleanUp() {
+ repo.deleteAll();
+ }
+
+ @Test
+ public void postAndGetTestResult() throws Exception {
+
+ Document postBody = new Document();
+ postBody.put("status", "NEGATIVE");
+
+ mvc.perform(post("/tests/" + RESULTID)
+ .with(user("user").password("password").roles("POSTUSER"))
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(postBody.toJson()))
+ .andExpect(status().isOk());
+
+ mvc.perform(get("/tests/" + RESULTID))
+ .andExpect(status().isOk())
+ .andDo(r -> {
+ Document getResult = Document.parse(r.getResponse().getContentAsString());
+ assertAll("content contains all the values of a new record",
+ () -> assertTrue(getResult.containsKey("id")),
+ () -> assertEquals("123", getResult.getString("id")),
+
+ () -> assertTrue(getResult.containsKey("status")),
+ () -> assertEquals("NEGATIVE", getResult.getString("status")),
+
+ () -> assertTrue(getResult.containsKey("contact")), () -> assertNull(getResult.get("contact")),
+
+ () -> assertTrue(getResult.containsKey("notified")),
+ () -> assertEquals(Boolean.FALSE, getResult.getBoolean("notified")));
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/wirvsvirus/testresult/backend/rest/TestResultControllerNotifictaionTest.java b/src/test/java/de/wirvsvirus/testresult/backend/rest/TestResultControllerNotifictaionTest.java
new file mode 100644
index 0000000..274a325
--- /dev/null
+++ b/src/test/java/de/wirvsvirus/testresult/backend/rest/TestResultControllerNotifictaionTest.java
@@ -0,0 +1,126 @@
+package de.wirvsvirus.testresult.backend.rest;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Optional;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import de.wirvsvirus.testresult.backend.exceptions.FalseInformedException;
+import de.wirvsvirus.testresult.backend.model.TestResult;
+import de.wirvsvirus.testresult.backend.model.TestResult.Result;
+import de.wirvsvirus.testresult.backend.service.TestResultPushService;
+import de.wirvsvirus.testresult.backend.service.TestResultService;
+
+@ExtendWith(MockitoExtension.class)
+public class TestResultControllerNotifictaionTest {
+
+ @Mock
+ TestResultService testResultService;
+ @Mock
+ TestResultPushService pushService;
+
+ @InjectMocks
+ TestResultController controller;
+
+ @Test
+ public void pushNotifiactionTriggeredWhenIdUnknownSoFar() throws FalseInformedException {
+ TestResult tr = new TestResult();
+ tr.setContact("some@mail.com");
+ tr.setNotified(false);
+ tr.setStatus(Result.NEGATIVE);
+
+ when(testResultService.getTestResult(eq("123"))).thenReturn(Optional.empty());
+ when(pushService.executePush(any())).thenReturn(Boolean.TRUE);
+
+ controller.addTestResult("123", tr);
+ //check existing
+ verify(testResultService,times(1)).getTestResult(eq("123"));
+ //do push
+ verify(pushService, times(1)).executePush(any());
+ //save testresult
+ verify(testResultService,times(1)).createTestProcess(any());
+ }
+ @Test
+ public void pushNotifiactionTriggeredWhenStatusIsTheSameButNotYetNotified() throws FalseInformedException {
+
+ TestResult existing = new TestResult();
+ existing.setContact("some@mail.com");
+ existing.setNotified(false);
+ existing.setStatus(Result.NEGATIVE);
+
+ TestResult tr = new TestResult();
+ tr.setContact("some@mail.com");
+ tr.setStatus(Result.NEGATIVE);
+
+ when(testResultService.getTestResult(eq("123"))).thenReturn(Optional.of(existing));
+ when(pushService.executePush(any())).thenReturn(Boolean.TRUE);
+
+ controller.addTestResult("123", tr);
+ //check existing
+ verify(testResultService,times(1)).getTestResult(eq("123"));
+ //do push
+ verify(pushService, times(1)).executePush(any());
+ //save testresult
+ verify(testResultService,times(1)).createTestProcess(any());
+ }
+
+
+ @Test
+ public void pushNotifiactionNotTriggeredWhenAlreadyNotified() throws FalseInformedException {
+
+ TestResult existing = new TestResult();
+ existing.setContact("some@mail.com");
+ existing.setNotified(true);
+ existing.setStatus(Result.NEGATIVE);
+
+ TestResult tr = new TestResult();
+ tr.setContact("some@mail.com");
+ tr.setNotified(false);
+ tr.setStatus(Result.NEGATIVE);
+
+ when(testResultService.getTestResult(eq("123"))).thenReturn(Optional.of(existing));
+
+ controller.addTestResult("123", tr);
+ //check existing
+ verify(testResultService,times(1)).getTestResult(eq("123"));
+ //do push
+ verify(pushService, never()).executePush(any());
+ //save testresult
+ verify(testResultService,never()).createTestProcess(any());
+ }
+
+ @Test
+ public void notifyWhenSwitchingFromPendingToNegative() throws FalseInformedException {
+
+ TestResult existing = new TestResult();
+ existing.setContact("some@mail.com");
+ existing.setNotified(false);
+ existing.setStatus(Result.PENDING);
+
+ TestResult tr = new TestResult();
+ tr.setContact("some@mail.com");
+ tr.setNotified(false);
+ tr.setStatus(Result.NEGATIVE);
+
+ when(testResultService.getTestResult(eq("123"))).thenReturn(Optional.of(existing));
+
+ controller.addTestResult("123", tr);
+ //check existing
+ verify(testResultService,times(1)).getTestResult(eq("123"));
+ //do push
+ verify(pushService, times(1)).executePush(any());
+ //save testresult
+ verify(testResultService,times(1)).createTestProcess(any());
+ }
+
+}
diff --git a/src/test/java/de/wirvsvirus/testresult/backend/service/TestResultPushServiceTest.java b/src/test/java/de/wirvsvirus/testresult/backend/service/TestResultPushServiceTest.java
new file mode 100644
index 0000000..3bc00c6
--- /dev/null
+++ b/src/test/java/de/wirvsvirus/testresult/backend/service/TestResultPushServiceTest.java
@@ -0,0 +1,105 @@
+package de.wirvsvirus.testresult.backend.service;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+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.EnumSource;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import de.wirvsvirus.testresult.backend.model.TestResult;
+import de.wirvsvirus.testresult.backend.model.TestResult.Result;
+
+@ExtendWith(MockitoExtension.class)
+public class TestResultPushServiceTest {
+
+ @Mock
+ private SmsServiceProvider smsService;
+
+ @Mock
+ private EmailService emailService;
+
+ @InjectMocks
+ TestResultPushService service;
+
+ @Test
+ public void sendEmailForNegativeResult() {
+
+ TestResult tr = new TestResult();
+ tr.setContact("mail@test.com");
+ tr.setStatus(Result.NEGATIVE);
+ boolean sentFlag = service.executePush(tr);
+ assertAll("push is done and flag indicates it", () -> assertTrue(sentFlag),
+ () -> verify(emailService, times(1)).sendMail(any()),
+ () -> verify(smsService, never()).sendNegativeResultSms(any()));
+ }
+
+ @ParameterizedTest
+ @EnumSource(Result.class)
+ public void doNotSendEmailSentForNonNegativeResult(Result nonNegative) {
+
+ if (nonNegative.equals(Result.NEGATIVE))
+ return;
+
+ TestResult tr = new TestResult();
+ tr.setContact("mail@test.com");
+ tr.setStatus(nonNegative);
+ boolean sentFlag = service.executePush(tr);
+ assertAll("push is done and flag indicates it", () -> assertFalse(sentFlag),
+ () -> verify(emailService, never()).sendMail(any()),
+ () -> verify(smsService, never()).sendNegativeResultSms(any()));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "004915555", "015555", "+491555" })
+ public void sendSmsForNegativeResultAndValidNumbers(String validNumber) {
+
+ TestResult tr = new TestResult();
+ tr.setContact(validNumber);
+ tr.setStatus(Result.NEGATIVE);
+ boolean sentFlag = service.executePush(tr);
+ assertAll("push is done and flag indicates it", () -> assertTrue(sentFlag),
+ () -> verify(emailService, never()).sendMail(any()),
+ () -> verify(smsService, times(1)).sendNegativeResultSms(any()));
+ }
+
+ @ParameterizedTest
+ @EnumSource(Result.class)
+ public void doNotSendSmsForNonNegativeResult(Result nonNegative) {
+
+ if (nonNegative.equals(Result.NEGATIVE))
+ return;
+
+ TestResult tr = new TestResult();
+ tr.setContact("017555");
+ tr.setStatus(nonNegative);
+ boolean sentFlag = service.executePush(tr);
+ assertAll("push is done and flag indicates it", () -> assertFalse(sentFlag),
+ () -> verify(emailService, never()).sendMail(any()),
+ () -> verify(smsService, never()).sendNegativeResultSms(any()));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "+4855523", "07555", "foobar@bla", "foo.de", "-12314", "0047123123" })
+ public void doNotSendNotificationForInvalidContactPatterns(String invalidContact) {
+
+ TestResult tr = new TestResult();
+ tr.setContact(invalidContact);
+ tr.setStatus(Result.NEGATIVE);
+ boolean sentFlag = service.executePush(tr);
+ assertAll("push is done and flag indicates it", () -> assertFalse(sentFlag),
+ () -> verify(emailService, never()).sendMail(any()),
+ () -> verify(smsService, never()).sendNegativeResultSms(any()));
+ }
+
+}
diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml
new file mode 100644
index 0000000..da4b6ae
--- /dev/null
+++ b/src/test/resources/application-test.yml
@@ -0,0 +1,6 @@
+post:
+ user: user
+ password: password
+admin:
+ user: admin
+ password: adminpassword
\ No newline at end of file