You will be provided with a partial code base and an issue statement explaining a problem to resolve.
<issue>
Diagnosis key submission unit tests
Implement unit tests for the diagnosis key submission service according to best practices.

</issue>

<code>
[start of README.md]
1 # cwa-server
2 
3 # API
4 ## Distribution
5 ### Postman
6 https://documenter.getpostman.com/view/5099981/Szmb8Lcd?version=latest
7 ### OpenAPI
8 https://github.com/corona-warn-app/cwa-server/blob/master/services/distribution/api_v1.json
9 # Deployments
10 ## Distribution Server Mock
11 http://download-mock-ena-server.apps.p006.otc.mcs-paas.io/version/
12 
[end of README.md]
[start of common/persistence/src/main/java/app/coronawarn/server/services/common/persistence/service/DiagnosisKeyService.java]
1 package app.coronawarn.server.services.common.persistence.service;
2 
3 import java.util.Collection;
4 import app.coronawarn.server.services.common.persistence.domain.DiagnosisKey;
5 import app.coronawarn.server.services.common.persistence.repository.DiagnosisKeyRepository;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.stereotype.Component;
8 
9 @Component
10 public class DiagnosisKeyService {
11 
12   @Autowired
13   private DiagnosisKeyRepository keyRepository;
14 
15   /**
16    * Persists the specified collection of {@link DiagnosisKey} instances. Use the returned
17    * collection for further operations as the saveDiagnosisKeys operation might have changed the
18    * {@link DiagnosisKey} instances completely.
19    *
20    * @param diagnosisKeys must not contain {@literal null}.
21    * @return a collection of the saved keys; will never contain {@literal null}.
22    * @throws IllegalArgumentException in case the given collection contains {@literal null}.
23    */
24   public Collection<DiagnosisKey> saveDiagnosisKeys(
25       Collection<DiagnosisKey> diagnosisKeys) {
26     return keyRepository.saveAll(diagnosisKeys);
27   }
28 }
29 
[end of common/persistence/src/main/java/app/coronawarn/server/services/common/persistence/service/DiagnosisKeyService.java]
[start of services/submission/src/main/java/app/coronawarn/server/services/submission/controller/SubmissionController.java]
1 package app.coronawarn.server.services.submission.controller;
2 
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.stream.Collectors;
6 import app.coronawarn.server.common.protocols.generated.ExposureKeys.TemporaryExposureKey;
7 import app.coronawarn.server.services.common.persistence.domain.DiagnosisKey;
8 import app.coronawarn.server.services.common.persistence.service.DiagnosisKeyService;
9 import app.coronawarn.server.services.submission.verification.TanVerifier;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.http.ResponseEntity;
12 import org.springframework.web.bind.annotation.GetMapping;
13 import org.springframework.web.bind.annotation.PathVariable;
14 import org.springframework.web.bind.annotation.PostMapping;
15 import org.springframework.web.bind.annotation.RequestBody;
16 import org.springframework.web.bind.annotation.RequestHeader;
17 import org.springframework.web.bind.annotation.RequestMapping;
18 import org.springframework.web.bind.annotation.RestController;
19 
20 // TODO Implement Unit Tests
21 @RestController
22 @RequestMapping("/version/v1")
23 public class SubmissionController {
24 
25   @Autowired
26   private DiagnosisKeyService exposureKeyService;
27 
28   @Autowired
29   private TanVerifier tanVerifier;
30 
31   @GetMapping(value = "")
32   public ResponseEntity<String> hello() {
33     return ResponseEntity.ok().body("Diagnosis Key Submission Endpoint v1");
34   }
35 
36   // TODO update protoSpec and endpoint to Collection<TemporaryExposureKey>
37   @PostMapping(value = "/diagnosis-keys/country/{country}")
38   public ResponseEntity<String> submitDiagnosisKey(
39       @PathVariable String country,
40       @RequestBody TemporaryExposureKey exposureKeys,
41       @RequestHeader(value = "cwa-fake") Integer fake,
42       @RequestHeader(value = "cwa-authorization") String tan) {
43     if (fake != 0) {
44       //TODO consider sleep or similar
45       return buildSuccessResponseEntity();
46     }
47     if (!this.tanVerifier.verifyTan(tan)) {
48       return buildTanInvalidResponseEntity();
49     }
50 
51     persistDiagnosisKeysPayload(Collections.singleton(exposureKeys));
52 
53     return buildSuccessResponseEntity();
54   }
55 
56   /**
57    * @return A response that indicates that an invalid TAN was specified in the request.
58    */
59   private ResponseEntity<String> buildTanInvalidResponseEntity() {
60     // TODO implement
61     return null;
62   }
63 
64   /**
65    * @return A response that indicates successful request processing.
66    */
67   private ResponseEntity<String> buildSuccessResponseEntity() {
68     return ResponseEntity.ok().build();
69   }
70 
71   /**
72    * Persists the diagnosis keys contained in the specified request payload.
73    *
74    * @param protoBufDiagnosisKeys Diagnosis keys that were specified in the request.
75    * @throws IllegalArgumentException in case the given collection contains {@literal null}.
76    */
77   private void persistDiagnosisKeysPayload(
78       Collection<TemporaryExposureKey> protoBufDiagnosisKeys) {
79     Collection<DiagnosisKey> diagnosisKeys = protoBufDiagnosisKeys.stream()
80         .map(aProtoBufKey -> DiagnosisKey.builder().fromProtoBuf(aProtoBufKey).build())
81         .collect(Collectors.toList());
82 
83     this.exposureKeyService.saveDiagnosisKeys(diagnosisKeys);
84   }
85 }
86 
[end of services/submission/src/main/java/app/coronawarn/server/services/submission/controller/SubmissionController.java]
[start of services/submission/src/main/resources/application.properties]
1 logging.level.org.springframework.web=DEBUG
2 spring.jpa.hibernate.ddl-auto = create
3 spring.flyway.enabled=false
4 
[end of services/submission/src/main/resources/application.properties]
</code>

Here is an example of a patch file. It consists of changes to the code base. It specifies the file names, the line numbers of each change, and the removed and added lines. A single patch file can contain changes to multiple files.
<patch>
--- a/file.py
+++ b/file.py
@@ -1,27 +1,35 @@
 def euclidean(a, b):
-    while b:
-        a, b = b, a % b
-    return a
+    if b == 0:
+        return a
+    return euclidean(b, a % b)
 
 
 def bresenham(x0, y0, x1, y1):
     points = []
     dx = abs(x1 - x0)
     dy = abs(y1 - y0)
-    sx = 1 if x0 < x1 else -1
-    sy = 1 if y0 < y1 else -1
-    err = dx - dy
+    x, y = x0, y0
+    sx = -1 if x0 > x1 else 1
+    sy = -1 if y0 > y1 else 1
 
-    while True:
-        points.append((x0, y0))
-        if x0 == x1 and y0 == y1:
-            break
-        e2 = 2 * err
-        if e2 > -dy:
+    if dx > dy:
+        err = dx / 2.0
+        while x != x1:
+            points.append((x, y))
             err -= dy
-            x0 += sx
-        if e2 < dx:
-            err += dx
-            y0 += sy
+            if err < 0:
+                y += sy
+                err += dx
+            x += sx
+    else:
+        err = dy / 2.0
+        while y != y1:
+            points.append((x, y))
+            err -= dx
+            if err < 0:
+                x += sx
+                err += dy
+            y += sy
 
+    points.append((x, y))
     return points
</patch>

I need you to solve the provded issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the format shown above.
Respond below:


Diagnosis key submission unit tests
Implement unit tests for the diagnosis key submission service according to best practices.

<patch>
diff --git a/common/persistence/src/main/java/app/coronawarn/server/services/common/persistence/service/DiagnosisKeyService.java b/common/persistence/src/main/java/app/coronawarn/server/services/common/persistence/service/DiagnosisKeyService.java
--- a/common/persistence/src/main/java/app/coronawarn/server/services/common/persistence/service/DiagnosisKeyService.java
+++ b/common/persistence/src/main/java/app/coronawarn/server/services/common/persistence/service/DiagnosisKeyService.java
@@ -13,16 +13,12 @@ public class DiagnosisKeyService {
   private DiagnosisKeyRepository keyRepository;
 
   /**
-   * Persists the specified collection of {@link DiagnosisKey} instances. Use the returned
-   * collection for further operations as the saveDiagnosisKeys operation might have changed the
-   * {@link DiagnosisKey} instances completely.
+   * Persists the specified collection of {@link DiagnosisKey} instances.
    *
    * @param diagnosisKeys must not contain {@literal null}.
-   * @return a collection of the saved keys; will never contain {@literal null}.
    * @throws IllegalArgumentException in case the given collection contains {@literal null}.
    */
-  public Collection<DiagnosisKey> saveDiagnosisKeys(
-      Collection<DiagnosisKey> diagnosisKeys) {
-    return keyRepository.saveAll(diagnosisKeys);
+  public void saveDiagnosisKeys(Collection<DiagnosisKey> diagnosisKeys) {
+    keyRepository.saveAll(diagnosisKeys);
   }
 }
diff --git a/services/submission/src/main/java/app/coronawarn/server/services/submission/controller/SubmissionController.java b/services/submission/src/main/java/app/coronawarn/server/services/submission/controller/SubmissionController.java
--- a/services/submission/src/main/java/app/coronawarn/server/services/submission/controller/SubmissionController.java
+++ b/services/submission/src/main/java/app/coronawarn/server/services/submission/controller/SubmissionController.java
@@ -1,23 +1,22 @@
 package app.coronawarn.server.services.submission.controller;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.stream.Collectors;
 import app.coronawarn.server.common.protocols.generated.ExposureKeys.TemporaryExposureKey;
 import app.coronawarn.server.services.common.persistence.domain.DiagnosisKey;
 import app.coronawarn.server.services.common.persistence.service.DiagnosisKeyService;
 import app.coronawarn.server.services.submission.verification.TanVerifier;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Collectors;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-// TODO Implement Unit Tests
 @RestController
 @RequestMapping("/version/v1")
 public class SubmissionController {
@@ -34,9 +33,8 @@ public ResponseEntity<String> hello() {
   }
 
   // TODO update protoSpec and endpoint to Collection<TemporaryExposureKey>
-  @PostMapping(value = "/diagnosis-keys/country/{country}")
-  public ResponseEntity<String> submitDiagnosisKey(
-      @PathVariable String country,
+  @PostMapping(value = "/diagnosis-keys")
+  public ResponseEntity<Void> submitDiagnosisKey(
       @RequestBody TemporaryExposureKey exposureKeys,
       @RequestHeader(value = "cwa-fake") Integer fake,
       @RequestHeader(value = "cwa-authorization") String tan) {
@@ -56,15 +54,14 @@ public ResponseEntity<String> submitDiagnosisKey(
   /**
    * @return A response that indicates that an invalid TAN was specified in the request.
    */
-  private ResponseEntity<String> buildTanInvalidResponseEntity() {
-    // TODO implement
-    return null;
+  private ResponseEntity<Void> buildTanInvalidResponseEntity() {
+    return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
   }
 
   /**
    * @return A response that indicates successful request processing.
    */
-  private ResponseEntity<String> buildSuccessResponseEntity() {
+  private ResponseEntity<Void> buildSuccessResponseEntity() {
     return ResponseEntity.ok().build();
   }
 
diff --git a/services/submission/src/main/resources/application.properties b/services/submission/src/main/resources/application.properties
--- a/services/submission/src/main/resources/application.properties
+++ b/services/submission/src/main/resources/application.properties
@@ -1,3 +1,3 @@
 logging.level.org.springframework.web=DEBUG
-spring.jpa.hibernate.ddl-auto = create
+spring.jpa.hibernate.ddl-auto=create
 spring.flyway.enabled=false

</patch>
diff --git a/services/distribution/src/test/resources/application.properties b/services/distribution/src/test/resources/application.properties
--- a/services/distribution/src/test/resources/application.properties
+++ b/services/distribution/src/test/resources/application.properties
@@ -1,5 +1,4 @@
-spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
-spring.datasource.url=jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1
-spring.datasource.username=cwa
-spring.datasource.password=cwa
-spring.jpa.hibernate.ddl-auto=create
\ No newline at end of file
+spring.jpa.hibernate.ddl-auto=create
+logging.level.org.springframework=off
+logging.level.root=warn
+spring.main.banner-mode=off
diff --git a/services/distribution/src/test/resources/logback-test.xml b/services/distribution/src/test/resources/logback-test.xml
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/test/resources/logback-test.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+  <include resource="org/springframework/boot/logging/logback/base.xml" />
+  <logger name="org.springframework" level="off"/>
+</configuration>
diff --git a/services/submission/src/test/java/app/coronawarn/server/services/submission/ServerApplicationTests.java b/services/submission/src/test/java/app/coronawarn/server/services/submission/ServerApplicationTests.java
--- a/services/submission/src/test/java/app/coronawarn/server/services/submission/ServerApplicationTests.java
+++ b/services/submission/src/test/java/app/coronawarn/server/services/submission/ServerApplicationTests.java
@@ -1,13 +1,20 @@
 package app.coronawarn.server.services.submission;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import app.coronawarn.server.services.submission.controller.SubmissionController;
 import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
 @SpringBootTest
 class ServerApplicationTests {
 
-	@Test
-	void contextLoads() {
-	}
+  @Autowired
+  private SubmissionController controller;
 
+  @Test
+  public void contextLoads() {
+    assertNotNull(this.controller);
+  }
 }
diff --git a/services/submission/src/test/java/app/coronawarn/server/services/submission/controller/SubmissionControllerTest.java b/services/submission/src/test/java/app/coronawarn/server/services/submission/controller/SubmissionControllerTest.java
new file mode 100644
--- /dev/null
+++ b/services/submission/src/test/java/app/coronawarn/server/services/submission/controller/SubmissionControllerTest.java
@@ -0,0 +1,159 @@
+package app.coronawarn.server.services.submission.controller;
+
+
+import static app.coronawarn.server.common.protocols.generated.ExposureKeys.TemporaryExposureKey;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyCollection;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import app.coronawarn.server.services.common.persistence.service.DiagnosisKeyService;
+import app.coronawarn.server.services.submission.verification.TanVerifier;
+import com.google.protobuf.ByteString;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class SubmissionControllerTest {
+
+  private static final URI SUBMISSION_URL = URI.create("/version/v1/diagnosis-keys");
+
+  @MockBean
+  private DiagnosisKeyService diagnosisKeyService;
+
+  @MockBean
+  private TanVerifier tanVerifier;
+
+  @Autowired
+  private TestRestTemplate testRestTemplate;
+
+  @BeforeEach
+  public void setUpMocks() {
+    when(tanVerifier.verifyTan(anyString())).thenReturn(true);
+  }
+
+  @Test
+  public void checkResponseStatusForValidParameters() {
+    ResponseEntity<Void> actResponse =
+        executeRequest(buildTemporaryExposureKey(), buildOkHeaders());
+
+    assertEquals(HttpStatus.OK, actResponse.getStatusCode());
+  }
+
+  @Test
+  public void checkSaveOperationCallForValidParameters() {
+    executeRequest(buildTemporaryExposureKey(), buildOkHeaders());
+
+    verify(diagnosisKeyService, atLeastOnce()).saveDiagnosisKeys(anyCollection());
+  }
+
+  @ParameterizedTest
+  @MethodSource("createIncompleteHeaders")
+  public void badRequestIfCwaHeadersMissing(HttpHeaders headers) {
+    ResponseEntity<Void> actResponse = executeRequest(buildTemporaryExposureKey(), headers);
+
+    verify(diagnosisKeyService, never()).saveDiagnosisKeys(any());
+    assertEquals(HttpStatus.BAD_REQUEST, actResponse.getStatusCode());
+  }
+
+  private static Stream<Arguments> createIncompleteHeaders() {
+    return Stream.of(
+        Arguments.of(setContentTypeProtoBufHeader(new HttpHeaders())),
+        Arguments.of(setContentTypeProtoBufHeader(setCwaFakeHeader(new HttpHeaders(), "0"))),
+        Arguments.of(setContentTypeProtoBufHeader(setCwaAuthHeader(new HttpHeaders()))));
+  }
+
+  @Test
+  public void checkAcceptedHttpMethods() {
+    Set<HttpMethod> expAllowedMethods =
+        Stream.of(HttpMethod.POST, HttpMethod.OPTIONS)
+            .collect(Collectors.toCollection(HashSet::new));
+
+    Set<HttpMethod> actAllowedMethods = testRestTemplate.optionsForAllow(SUBMISSION_URL.toString());
+
+    assertEquals(expAllowedMethods, actAllowedMethods);
+  }
+
+  @Test
+  public void invalidTanHandling() {
+    when(tanVerifier.verifyTan(anyString())).thenReturn(false);
+
+    ResponseEntity<Void> actResponse =
+        executeRequest(buildTemporaryExposureKey(), buildOkHeaders());
+
+    verify(diagnosisKeyService, never()).saveDiagnosisKeys(any());
+    assertEquals(HttpStatus.FORBIDDEN, actResponse.getStatusCode());
+  }
+
+  @Test
+  public void fakeRequestHandling() {
+    HttpHeaders headers = buildOkHeaders();
+    setCwaFakeHeader(headers, "1");
+
+    ResponseEntity<Void> actResponse = executeRequest(buildTemporaryExposureKey(), headers);
+
+    verify(diagnosisKeyService, never()).saveDiagnosisKeys(any());
+    assertEquals(HttpStatus.OK, actResponse.getStatusCode());
+  }
+
+  private static HttpHeaders buildOkHeaders() {
+    HttpHeaders headers = setCwaAuthHeader(setContentTypeProtoBufHeader(new HttpHeaders()));
+
+    return setCwaFakeHeader(headers, "0");
+  }
+
+  private static HttpHeaders setContentTypeProtoBufHeader(HttpHeaders headers) {
+    headers.setContentType(MediaType.valueOf("application/x-protobuf"));
+    return headers;
+  }
+
+  private static HttpHeaders setCwaAuthHeader(HttpHeaders headers) {
+    headers.set("cwa-authorization", "okTan");
+    return headers;
+  }
+
+  private static HttpHeaders setCwaFakeHeader(HttpHeaders headers, String value) {
+    headers.set("cwa-fake", value);
+    return headers;
+  }
+
+  private static TemporaryExposureKey buildTemporaryExposureKey() {
+    return buildTemporaryExposureKey("testKey123456789", 3L, 2);
+  }
+
+  private static TemporaryExposureKey buildTemporaryExposureKey(
+      String keyData, long rollingStartNumber, int riskLevelValue) {
+    return TemporaryExposureKey.newBuilder()
+        .setKeyData(ByteString.copyFromUtf8(keyData))
+        .setRollingStartNumber(rollingStartNumber)
+        .setRiskLevelValue(riskLevelValue).build();
+  }
+
+  private ResponseEntity<Void> executeRequest(TemporaryExposureKey body, HttpHeaders headers) {
+    RequestEntity<TemporaryExposureKey> request =
+        new RequestEntity<>(body, headers, HttpMethod.POST, SUBMISSION_URL);
+    return testRestTemplate.postForEntity(SUBMISSION_URL, request, Void.class);
+  }
+}
diff --git a/services/submission/src/test/resources/application.properties b/services/submission/src/test/resources/application.properties
--- a/services/submission/src/test/resources/application.properties
+++ b/services/submission/src/test/resources/application.properties
@@ -1,5 +1,4 @@
-spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
-spring.datasource.url=jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1
-spring.datasource.username=cwa
-spring.datasource.password=cwa
-spring.jpa.hibernate.ddl-auto=create
\ No newline at end of file
+spring.jpa.hibernate.ddl-auto=create
+logging.level.org.springframework=off
+logging.level.root=warn
+spring.main.banner-mode=off
diff --git a/services/submission/src/test/resources/logback-test.xml b/services/submission/src/test/resources/logback-test.xml
new file mode 100644
--- /dev/null
+++ b/services/submission/src/test/resources/logback-test.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+  <include resource="org/springframework/boot/logging/logback/base.xml" />
+  <logger name="org.springframework" level="off"/>
+</configuration>
