diff --git a/pom.xml b/pom.xml
index cf88828b..e429444b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,11 +53,6 @@
reactor-spring
1.0.1.RELEASE
-
- org.json
- json
- 20190722
-
org.postgresql
postgresql
@@ -80,7 +75,7 @@
org.keycloak
keycloak-spring-boot-starter
-
+
diff --git a/src/main/java/de/sakpaas/backend/service/UserService.java b/src/main/java/de/sakpaas/backend/service/UserService.java
index 1ecbe81c..7c9897a7 100644
--- a/src/main/java/de/sakpaas/backend/service/UserService.java
+++ b/src/main/java/de/sakpaas/backend/service/UserService.java
@@ -79,7 +79,7 @@ public UserInfoDto getUserInfo(String header) throws InvalidBearerTokenException
* @throws VerificationException iff the given JWT is invalid
*/
@VisibleForTesting
- AccessToken verifyToken(String token) throws VerificationException {
+ public AccessToken verifyToken(String token) throws VerificationException {
return AdapterTokenVerifier.verifyToken(
token,
keycloakConfiguration.getKeycloakDeployment()
diff --git a/src/main/java/de/sakpaas/backend/v2/controller/UserController.java b/src/main/java/de/sakpaas/backend/v2/controller/UserController.java
index 40a95d88..dfc7c0ba 100644
--- a/src/main/java/de/sakpaas/backend/v2/controller/UserController.java
+++ b/src/main/java/de/sakpaas/backend/v2/controller/UserController.java
@@ -69,7 +69,7 @@ public ResponseEntity> getFavorites(
List favorites = favoriteService.findByUserUuid(userInfo.getId());
List response = favorites.stream()
- .map(favorite -> locationMapper.mapLocationToOutputDto(favorite.getLocation()))
+ .map(favorite -> locationMapper.mapLocationToOutputDto(favorite.getLocation(), userInfo))
.collect(Collectors.toList());
return new ResponseEntity<>(response, OK);
@@ -79,7 +79,7 @@ public ResponseEntity> getFavorites(
* Post Endpoint that creates a favorite.
*
* @param locationId the location Id of the new favorite
- * @param header The Authorization-Header that has to be provided in the request.
+ * @param header The Authorization-Header that has to be provided in the request.
* @return Returns a ResponseEntity
*/
@PostMapping("/self/favorites/{id}")
@@ -101,7 +101,7 @@ public ResponseEntity postFavorite(
* Delete Endpoint that deletes a favorite.
*
* @param locationId the location Id of the new favorite
- * @param header The Authorization-Header that has to be provided in the request.
+ * @param header The Authorization-Header that has to be provided in the request.
* @return Returns a ResponseEntity
*/
@DeleteMapping("/self/favorites/{id}")
diff --git a/src/main/java/de/sakpaas/backend/v2/mapper/LocationMapper.java b/src/main/java/de/sakpaas/backend/v2/mapper/LocationMapper.java
index 4244d60d..6475abbd 100644
--- a/src/main/java/de/sakpaas/backend/v2/mapper/LocationMapper.java
+++ b/src/main/java/de/sakpaas/backend/v2/mapper/LocationMapper.java
@@ -55,7 +55,7 @@ public LocationResultLocationDto mapLocationToOutputDto(Location location, UserI
boolean flag = favoriteRepository.findByUserUuid(user.getId())
.stream()
- .anyMatch(favorite -> favorite.getLocation() == location);
+ .anyMatch(favorite -> favorite.getLocation().equals(location));
return new LocationResultLocationDto(
location.getId(), location.getName(), flag,
diff --git a/src/test/java/de/sakpaas/backend/HappyHamsterTest.java b/src/test/java/de/sakpaas/backend/HappyHamsterTest.java
index fb1670fb..b1a2406e 100644
--- a/src/test/java/de/sakpaas/backend/HappyHamsterTest.java
+++ b/src/test/java/de/sakpaas/backend/HappyHamsterTest.java
@@ -2,12 +2,16 @@
import de.sakpaas.backend.util.KeycloakConfiguration;
import org.junit.ClassRule;
+import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.testcontainers.containers.PostgreSQLContainer;
+@EnableConfigurationProperties(KeycloakSpringBootProperties.class)
public class HappyHamsterTest {
+
@MockBean
- private KeycloakConfiguration keycloakConfiguration;
+ protected KeycloakConfiguration keycloakConfiguration;
@ClassRule
public static PostgreSQLContainer container = PostgresqlContainer.getInstance();
diff --git a/src/test/java/de/sakpaas/backend/IntegrationTest.java b/src/test/java/de/sakpaas/backend/IntegrationTest.java
new file mode 100644
index 00000000..c7f5f7e9
--- /dev/null
+++ b/src/test/java/de/sakpaas/backend/IntegrationTest.java
@@ -0,0 +1,200 @@
+package de.sakpaas.backend;
+
+import static org.hamcrest.Matchers.anything;
+import static org.hamcrest.Matchers.equalTo;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+
+import de.sakpaas.backend.model.Favorite;
+import de.sakpaas.backend.model.Location;
+import de.sakpaas.backend.model.Occupancy;
+import de.sakpaas.backend.service.AddressRepository;
+import de.sakpaas.backend.service.FavoriteRepository;
+import de.sakpaas.backend.service.LocationDetailsRepository;
+import de.sakpaas.backend.service.LocationRepository;
+import de.sakpaas.backend.service.OccupancyRepository;
+import de.sakpaas.backend.service.UserService;
+import java.util.List;
+import java.util.UUID;
+import lombok.SneakyThrows;
+import net.minidev.json.JSONArray;
+import net.minidev.json.JSONObject;
+import net.minidev.json.JSONValue;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.keycloak.common.VerificationException;
+import org.keycloak.representations.AccessToken;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.ResultMatcher;
+
+public class IntegrationTest extends HappyHamsterTest {
+
+ public static final UUID USER_UUID = UUID.fromString("550e8400-e29b-11d4-a716-446655440000");
+ public static final AccessToken USER_ACCESS_TOKEN = new AccessToken();
+ public static final String AUTHENTICATION_VALID = "Bearer token.valid.token";
+ public static final String AUTHENTICATION_INVALID = "Bearer token.invalid.token";
+ @Autowired
+ protected MockMvc mockMvc;
+ @SpyBean
+ protected UserService userService;
+ @Autowired
+ protected OccupancyRepository occupancyRepository;
+ @Autowired
+ protected FavoriteRepository favoriteRepository;
+ @Autowired
+ protected LocationRepository locationRepository;
+ @Autowired
+ protected LocationDetailsRepository locationDetailsRepository;
+ @Autowired
+ protected AddressRepository addressRepository;
+
+ @BeforeAll
+ static void setupAll() {
+ USER_ACCESS_TOKEN.setSubject(USER_UUID.toString());
+ USER_ACCESS_TOKEN.setPreferredUsername("test.user");
+ USER_ACCESS_TOKEN.setName("Testonius Tester");
+ USER_ACCESS_TOKEN.setGivenName("Testonius");
+ USER_ACCESS_TOKEN.setFamilyName("Tester");
+ USER_ACCESS_TOKEN.setEmail("testonius.tester@example.com");
+ }
+
+ @SneakyThrows
+ @BeforeEach
+ void setup() {
+ Mockito.doAnswer(invocation -> {
+ if (invocation.getArgument(0).equals("token.valid.token")) {
+ return USER_ACCESS_TOKEN;
+ }
+ throw new VerificationException();
+ })
+ .when(userService)
+ .verifyToken(Mockito.any());
+
+ // Cleanup tables
+ occupancyRepository.deleteAll();
+ favoriteRepository.deleteAll();
+ locationRepository.deleteAll();
+ addressRepository.deleteAll();
+ locationDetailsRepository.deleteAll();
+ }
+
+ @AfterEach
+ void tearDown() {
+ // Cleanup tables
+ occupancyRepository.deleteAll();
+ favoriteRepository.deleteAll();
+ locationRepository.deleteAll();
+ addressRepository.deleteAll();
+ locationDetailsRepository.deleteAll();
+ }
+
+ protected Location insert(Location location) {
+ locationDetailsRepository.save(location.getDetails());
+ addressRepository.save(location.getAddress());
+ return locationRepository.save(location);
+ }
+
+ protected Favorite insert(Favorite favorite) {
+ return favoriteRepository.save(favorite);
+ }
+
+ protected Occupancy insert(Occupancy occupancy) {
+ return occupancyRepository.save(occupancy);
+ }
+
+ protected ResultMatcher expectErrorObject() {
+ return result -> {
+ ResultMatcher[] matcher = new ResultMatcher[] {
+ jsonPath("$.timestamp").exists(),
+ jsonPath("$.status").isNumber(),
+ jsonPath("$.error").isString(),
+ jsonPath("$.path").isString(),
+ jsonPath("$.context.textId").isString(),
+ jsonPath("$.context.parameters").isArray(),
+ jsonPath("$.context.defaultMessage").isString(),
+ };
+ for (ResultMatcher resultMatcher : matcher) {
+ resultMatcher.match(result);
+ }
+ };
+ }
+
+ /**
+ * Checks if the given {@link org.springframework.test.web.servlet.MvcResult} has the form of a
+ * Location as defined in the openAPI specification. The fields given in the location parameter
+ * have to be correct.
+ *
+ * @param location the baseline {@link Location}
+ * @return the {@link ResultMatcher}
+ */
+ protected ResultMatcher expectLocation(Location location) {
+ return result -> this.match(result, "$", location);
+ }
+
+
+ /**
+ * Checks if the given {@link org.springframework.test.web.servlet.MvcResult} has the form of a
+ * List of Locations as defined in the openAPI specification. The fields given in the locations
+ * parameter have to be correct.
+ *
+ * @param locations the baseline {@link List} of {@link Location}s
+ * @return the {@link ResultMatcher}
+ */
+ protected ResultMatcher expectLocationList(List locations) {
+ return result -> {
+ // Check if the result is an array
+ jsonPath("$").isArray().match(result);
+
+ // Find correct Location for array element
+ JSONArray array = (JSONArray) JSONValue.parse(result.getResponse().getContentAsString());
+ for (int i = 0; i < array.size(); i++) {
+ long id = ((JSONObject) array.get(i))
+ .getAsNumber("id")
+ .longValue();
+ Location location = locations.stream()
+ .filter(loc -> loc.getId() == id)
+ .findAny()
+ .orElseThrow(() -> new AssertionError("Unknown LocationId in result."));
+ this.match(result, "$[" + i + "]", location);
+ }
+ };
+ }
+
+ private void match(MvcResult result, String selector, Location location) throws Exception {
+ // Define assertions
+ ResultMatcher[] matcher = new ResultMatcher[] {
+ jsonPath(selector + ".id").value(equalTo(location.getId()), Long.class),
+ jsonPath(selector + ".name").value(location.getName()),
+ // Favorite (unknown contents)
+ jsonPath(selector + ".favorite", anything()),
+ // Coordinates
+ jsonPath(selector + ".coordinates.latitude").value(location.getLatitude()),
+ jsonPath(selector + ".coordinates.longitude").value(location.getLongitude()),
+ // Details
+ jsonPath(selector + ".details.type").value(location.getDetails().getType()),
+ jsonPath(selector + ".details.brand").value(location.getDetails().getBrand()),
+ jsonPath(selector + ".details.openingHours")
+ .value(location.getDetails().getOpeningHours()),
+ // Occupancy (unknown contents)
+ jsonPath(selector + ".occupancy.value", anything()),
+ jsonPath(selector + ".occupancy.count", anything()),
+ jsonPath(selector + ".occupancy.latestReport", anything()),
+ // Address
+ jsonPath(selector + ".address.country").value(location.getAddress().getCountry()),
+ jsonPath(selector + ".address.city").value(location.getAddress().getCity()),
+ jsonPath(selector + ".address.postcode")
+ .value(location.getAddress().getPostcode()),
+ jsonPath(selector + ".address.street").value(location.getAddress().getStreet()),
+ jsonPath(selector + ".address.housenumber")
+ .value(location.getAddress().getHousenumber())
+ };
+ // Run assertions
+ for (ResultMatcher resultMatcher : matcher) {
+ resultMatcher.match(result);
+ }
+ }
+}
diff --git a/src/test/java/de/sakpaas/backend/controller/UserControllerTest.java b/src/test/java/de/sakpaas/backend/controller/UserControllerTest.java
deleted file mode 100644
index 4dc4a207..00000000
--- a/src/test/java/de/sakpaas/backend/controller/UserControllerTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package de.sakpaas.backend.controller;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-import de.sakpaas.backend.dto.UserInfoDto;
-import de.sakpaas.backend.model.Address;
-import de.sakpaas.backend.model.Favorite;
-import de.sakpaas.backend.model.Location;
-import de.sakpaas.backend.model.LocationDetails;
-import de.sakpaas.backend.service.AddressRepository;
-import de.sakpaas.backend.service.FavoriteRepository;
-import de.sakpaas.backend.service.LocationDetailsRepository;
-import de.sakpaas.backend.service.LocationRepository;
-import de.sakpaas.backend.service.OccupancyRepository;
-import de.sakpaas.backend.service.PresenceRepository;
-import de.sakpaas.backend.service.UserService;
-import de.sakpaas.backend.util.KeycloakConfiguration;
-import de.sakpaas.backend.v2.controller.UserController;
-import de.sakpaas.backend.v2.dto.LocationResultLocationDto;
-import de.sakpaas.backend.v2.mapper.LocationMapper;
-import io.micrometer.core.instrument.MeterRegistry;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-import org.junit.jupiter.api.Test;
-import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
-import org.keycloak.common.util.RandomString;
-import org.mockito.Mockito;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.test.web.servlet.MockMvc;
-import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
-
-@WebMvcTest(UserController.class)
-@EnableConfigurationProperties(KeycloakSpringBootProperties.class)
-public class UserControllerTest {
- @Autowired
- private MockMvc mockMvc;
-
- @MockBean
- private UserService userService;
- @MockBean
- private LocationMapper locationMapper;
- @MockBean
- private FavoriteRepository favoriteRepository;
- @MockBean
- private AddressRepository addressRepository;
- @MockBean
- private LocationDetailsRepository locationDetailsRepository;
- @MockBean
- private LocationRepository locationRepository;
- @MockBean
- private PresenceRepository presenceRepository;
- @MockBean
- private OccupancyRepository occupancyRepository;
- @MockBean
- private MeterRegistry meterRegistry;
- @MockBean
- private KeycloakConfiguration keycloakConfiguration;
-
- @Test
- public void shouldGetLocationsForCurrentUser() throws Exception {
- String header = RandomString.randomCode(32);
- UUID user = UUID.randomUUID();
-
- List locations = new ArrayList<>();
- List resultDtos = new ArrayList<>();
- List favorites = new ArrayList<>();
- for (int i = 0; i < 3; i++) {
- Location location = location((long) i);
- locations.add(location);
- resultDtos.add(resultDto((long) i));
- favorites.add(new Favorite(user, location));
- }
-
- Mockito.when(userService.getUserInfo(header)).thenReturn(
- new UserInfoDto(user.toString(), "test", "test", "test", "test",
- "test@test.de"));
- Mockito.when(favoriteRepository.findByUserUuid(user)).thenReturn(favorites);
- Mockito.when(locationMapper.mapLocationToOutputDto(locations.get(0)))
- .thenReturn(resultDtos.get(0));
- Mockito.when(locationMapper.mapLocationToOutputDto(locations.get(1)))
- .thenReturn(resultDtos.get(1));
- Mockito.when(locationMapper.mapLocationToOutputDto(locations.get(2)))
- .thenReturn(resultDtos.get(2));
-
- String resultJson =
- this.mockMvc.perform(get("/v2/users/self/favorites").header("Authorization", header))
- .andDo(print())
- .andExpect(status().isOk())
- .andReturn()
- .getResponse()
- .getContentAsString();
-
- String compareJson = new ObjectMapper().writeValueAsString(resultDtos);
- assertThat(compareJson, equalTo(resultJson));
- }
-
- private Location location(Long id) {
- return new Location(id, "Location: " + id, 0.0D, 0.0D, new LocationDetails(), new Address());
- }
-
- private LocationResultLocationDto resultDto(Long id) {
- return new LocationResultLocationDto(id, "Location: " + id, false, null, null, null, null);
- }
-}
diff --git a/src/test/java/de/sakpaas/backend/v2/controller/EndpointAddFavoriteByLocationIdTest.java b/src/test/java/de/sakpaas/backend/v2/controller/EndpointAddFavoriteByLocationIdTest.java
new file mode 100644
index 00000000..df78e8ce
--- /dev/null
+++ b/src/test/java/de/sakpaas/backend/v2/controller/EndpointAddFavoriteByLocationIdTest.java
@@ -0,0 +1,180 @@
+package de.sakpaas.backend.v2.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import de.sakpaas.backend.IntegrationTest;
+import de.sakpaas.backend.model.Address;
+import de.sakpaas.backend.model.Favorite;
+import de.sakpaas.backend.model.Location;
+import de.sakpaas.backend.model.LocationDetails;
+import de.sakpaas.backend.model.Occupancy;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Tests the endpoint POST /v2/users/self/favorites/{id}
if it conforms to
+ * the openAPI specification.
+ */
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@AutoConfigureMockMvc
+class EndpointAddFavoriteByLocationIdTest extends IntegrationTest {
+
+ @Test
+ void testMalformed() throws Exception {
+ // Test all authentication possibilities
+ mockMvc.perform(post("/v2/users/self/favorites/xxxx")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(post("/v2/users/self/favorites/xxxx")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(post("/v2/users/self/favorites/xxxx"))
+ // No Authentication
+ .andExpect(status().isBadRequest());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.isEmpty()).isTrue();
+ }
+
+ @Test
+ void testNotFound() throws Exception {
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isNotFound());
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.isEmpty()).isTrue();
+ }
+
+ @Test
+ void testFound() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ super.insert(location);
+
+ // Test all authentication possibilities
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(true));
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.size()).isEqualTo(1);
+ assertThat(testFavorites.get(0).getLocation()).isEqualTo(location);
+ assertThat(testFavorites.get(0).getUserUuid()).isEqualTo(USER_UUID);
+ }
+
+ @Test
+ void testAlreadyFavorite() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Favorite favorite = new Favorite(USER_UUID, location);
+ super.insert(location);
+ super.insert(favorite);
+
+ // Test all authentication possibilities
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(true));
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.size()).isEqualTo(1);
+ assertThat(testFavorites.get(0).getLocation()).isEqualTo(location);
+ assertThat(testFavorites.get(0).getUserUuid()).isEqualTo(USER_UUID);
+ }
+
+ @Test
+ void testOccupancy() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Occupancy occupancy = new Occupancy(location, 0.5, "TEST");
+ super.insert(location);
+ super.insert(occupancy);
+
+ // Test all authentication possibilities
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(true))
+ .andExpect(jsonPath("$.occupancy.value").value(occupancy.getOccupancy()))
+ .andExpect(jsonPath("$.occupancy.count").value(1))
+ .andExpect(jsonPath("$.occupancy.latestReport").isString());
+
+ mockMvc.perform(post("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.size()).isEqualTo(1);
+ assertThat(testFavorites.get(0).getLocation()).isEqualTo(location);
+ assertThat(testFavorites.get(0).getUserUuid()).isEqualTo(USER_UUID);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/sakpaas/backend/v2/controller/EndpointGetLocationByIdTest.java b/src/test/java/de/sakpaas/backend/v2/controller/EndpointGetLocationByIdTest.java
new file mode 100644
index 00000000..f0be51f7
--- /dev/null
+++ b/src/test/java/de/sakpaas/backend/v2/controller/EndpointGetLocationByIdTest.java
@@ -0,0 +1,161 @@
+package de.sakpaas.backend.v2.controller;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import de.sakpaas.backend.IntegrationTest;
+import de.sakpaas.backend.model.Address;
+import de.sakpaas.backend.model.Favorite;
+import de.sakpaas.backend.model.Location;
+import de.sakpaas.backend.model.LocationDetails;
+import de.sakpaas.backend.model.Occupancy;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Tests the endpoint /v2/locations/{id}
if it conforms to the openAPI specification.
+ */
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@AutoConfigureMockMvc
+class EndpointGetLocationByIdTest extends IntegrationTest {
+
+ @Test
+ void testMalformed() throws Exception {
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations/xxxx")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations/xxxx")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations/xxxx"))
+ // No Authentication
+ .andExpect(status().isBadRequest());
+ }
+
+ @Test
+ void testNotFound() throws Exception {
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isNotFound());
+
+ mockMvc.perform(get("/v2/locations/1000"))
+ // No Authentication
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ void testFound() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ super.insert(location);
+
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(false))
+ .andExpect(jsonPath("$.occupancy.value").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.count").value(0))
+ .andExpect(jsonPath("$.occupancy.latestReport").doesNotExist());
+
+ mockMvc.perform(get("/v2/locations/1000"))
+ // No Authentication
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.value").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.count").value(0))
+ .andExpect(jsonPath("$.occupancy.latestReport").doesNotExist());
+ }
+
+ @Test
+ void testFoundFavorite() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Favorite favorite = new Favorite(USER_UUID, location);
+ super.insert(location);
+ super.insert(favorite);
+
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(true))
+ .andExpect(jsonPath("$.occupancy.value").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.count").value(0))
+ .andExpect(jsonPath("$.occupancy.latestReport").doesNotExist());
+
+ mockMvc.perform(get("/v2/locations/1000"))
+ // No Authentication
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.value").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.count").value(0))
+ .andExpect(jsonPath("$.occupancy.latestReport").doesNotExist());
+ }
+
+ @Test
+ void testFoundOccupancy() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Occupancy occupancy = new Occupancy(location, 0.5, "TEST");
+ super.insert(location);
+ super.insert(occupancy);
+
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(false))
+ .andExpect(jsonPath("$.occupancy.value").value(occupancy.getOccupancy()))
+ .andExpect(jsonPath("$.occupancy.count").value(1))
+ .andExpect(jsonPath("$.occupancy.latestReport").isString());
+
+ mockMvc.perform(get("/v2/locations/1000"))
+ // No Authentication
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.value").value(occupancy.getOccupancy()))
+ .andExpect(jsonPath("$.occupancy.count").value(1))
+ .andExpect(jsonPath("$.occupancy.latestReport").isString());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/sakpaas/backend/v2/controller/EndpointGetLocationsByCoordinatesTest.java b/src/test/java/de/sakpaas/backend/v2/controller/EndpointGetLocationsByCoordinatesTest.java
new file mode 100644
index 00000000..0eed104e
--- /dev/null
+++ b/src/test/java/de/sakpaas/backend/v2/controller/EndpointGetLocationsByCoordinatesTest.java
@@ -0,0 +1,228 @@
+package de.sakpaas.backend.v2.controller;
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.nullValue;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import de.sakpaas.backend.IntegrationTest;
+import de.sakpaas.backend.model.Address;
+import de.sakpaas.backend.model.Favorite;
+import de.sakpaas.backend.model.Location;
+import de.sakpaas.backend.model.LocationDetails;
+import de.sakpaas.backend.model.Occupancy;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Tests the endpoint /v2/locations
if it conforms to the openAPI specification.
+ */
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@AutoConfigureMockMvc
+class EndpointGetLocationsByCoordinatesTest extends IntegrationTest {
+
+ @Test
+ void testMalformed() throws Exception {
+ // Test all authentication possibilities
+ // No coordinates given
+ mockMvc.perform(get("/v2/locations")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations"))
+ // No Authentication
+ .andExpect(status().isBadRequest());
+
+ // Incomplete coordinates given
+ mockMvc.perform(get("/v2/locations?latitude=42.0")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations?latitude=42.0")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations?latitude=42.0"))
+ // No Authentication
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations?longitude=42.0")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations?longitude=42.0")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations?longitude=42.0"))
+ // No Authentication
+ .andExpect(status().isBadRequest());
+
+ // Wrong type
+ mockMvc.perform(get("/v2/locations?latitude=XXX&longitude=42.0")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations?latitude=XXX&longitude=42.0")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(get("/v2/locations?latitude=XXX&longitude=42.0"))
+ // No Authentication
+ .andExpect(status().isBadRequest());
+ }
+
+ @Test
+ void testEmpty() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ super.insert(location);
+
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations?latitude=0.0&longitude=0.0")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/locations?latitude=0.0&longitude=0.0")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
+
+ mockMvc.perform(get("/v2/locations?latitude=0.0&longitude=0.0"))
+ // No Authentication
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
+ }
+
+ @Test
+ void testFound() throws Exception {
+ // Setup test data
+ Location locationEdeka = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Location locationLidl = new Location(3000L, "Lidl", 0.0, 0.0,
+ new LocationDetails("beverages", "Mo-So 01-23", "Lidl"),
+ new Address("ES", "Madrid", "5432", "Street", "1111")
+ );
+ super.insert(locationEdeka);
+ super.insert(locationLidl);
+ List locations = Arrays.asList(
+ locationEdeka,
+ locationLidl
+ );
+
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations?latitude=42.0&longitude=7.0")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/locations?latitude=42.0&longitude=7.0")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocationList(locations))
+ .andExpect(jsonPath("$", hasSize(1)));
+
+ mockMvc.perform(get("/v2/locations?latitude=42.0&longitude=7.0"))
+ // No Authentication
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocationList(locations))
+ .andExpect(jsonPath("$", hasSize(1)));
+ }
+
+ @Test
+ void testFavorite() throws Exception {
+ // Setup test data
+ Location locationEdeka = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Location locationAldi = new Location(2000L, "Aldi", 42.001, 7.001,
+ new LocationDetails("kiosk", "Fr-Sa 12-14", "Aldi"),
+ new Address("FR", "Paris", "101010", "Louvre", "1")
+ );
+ List locations = Arrays.asList(
+ locationEdeka,
+ locationAldi
+ );
+ super.insert(locationEdeka);
+ super.insert(locationAldi);
+ Favorite favoriteEdeka = new Favorite(USER_UUID, locationEdeka);
+ super.insert(favoriteEdeka);
+
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/locations?latitude=42.0&longitude=7.0")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/locations?latitude=42.0&longitude=7.0")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocationList(locations))
+ .andExpect(jsonPath("$", hasSize(2)))
+ .andExpect(jsonPath("$.[?(@.id==1000)].favorite").value(true))
+ .andExpect(jsonPath("$.[?(@.id==2000)].favorite").value(false));
+
+ mockMvc.perform(get("/v2/locations?latitude=42.0&longitude=7.0"))
+ // No Authentication
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocationList(locations))
+ .andExpect(jsonPath("$", hasSize(2)))
+ // The result is a list and will not automatically unpacked with nullValue()
+ .andExpect(jsonPath("$.[?(@.id==1000)].favorite").value(contains(nullValue())))
+ .andExpect(jsonPath("$.[?(@.id==2000)].favorite").value(contains(nullValue())));
+ }
+
+ @Test
+ void testOccupancy() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Occupancy occupancy = new Occupancy(location, 0.5, "TEST");
+ super.insert(location);
+ super.insert(occupancy);
+
+ // Test all authentication possibilities
+ mockMvc.perform(
+ get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(
+ get("/v2/locations/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(false))
+ .andExpect(jsonPath("$.occupancy.value").value(occupancy.getOccupancy()))
+ .andExpect(jsonPath("$.occupancy.count").value(1))
+ .andExpect(jsonPath("$.occupancy.latestReport").isString());
+
+ mockMvc.perform(
+ get("/v2/locations/1000"))
+ // No Authentication
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").doesNotExist())
+ .andExpect(jsonPath("$.occupancy.value").value(occupancy.getOccupancy()))
+ .andExpect(jsonPath("$.occupancy.count").value(1))
+ .andExpect(jsonPath("$.occupancy.latestReport").isString());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/sakpaas/backend/v2/controller/EndpointListFavoritesTest.java b/src/test/java/de/sakpaas/backend/v2/controller/EndpointListFavoritesTest.java
new file mode 100644
index 00000000..38c23e72
--- /dev/null
+++ b/src/test/java/de/sakpaas/backend/v2/controller/EndpointListFavoritesTest.java
@@ -0,0 +1,98 @@
+package de.sakpaas.backend.v2.controller;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.everyItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import de.sakpaas.backend.IntegrationTest;
+import de.sakpaas.backend.model.Address;
+import de.sakpaas.backend.model.Favorite;
+import de.sakpaas.backend.model.Location;
+import de.sakpaas.backend.model.LocationDetails;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Tests the endpoint /v2/users/self/favorites
if it conforms to the openAPI
+ * specification.
+ */
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@AutoConfigureMockMvc
+class EndpointListFavoritesTest extends IntegrationTest {
+
+ @Test
+ void testEmpty() throws Exception {
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/users/self/favorites")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/users/self/favorites")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$").isArray())
+ .andExpect(jsonPath("$").isEmpty());
+
+ mockMvc.perform(get("/v2/users/self/favorites"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ void testFound() throws Exception {
+ // Setup test data
+ Location locationEdeka = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Location locationAldi = new Location(2000L, "Aldi", 42.001, 7.001,
+ new LocationDetails("kiosk", "Fr-Sa 12-14", "Aldi"),
+ new Address("FR", "Paris", "101010", "Louvre", "1")
+ );
+ Location locationPenny = new Location(3000L, "Penny", 0.0, 0.0,
+ new LocationDetails("beverages", "Sa-So 02-03", "Penny"),
+ new Address("CH", "Zurich", "567", "Am Berg", "5")
+ );
+ super.insert(locationEdeka);
+ super.insert(locationAldi);
+ super.insert(locationPenny);
+ List locations = Arrays.asList(
+ locationEdeka,
+ locationAldi,
+ locationPenny
+ );
+ super.insert(new Favorite(USER_UUID, locationEdeka));
+ super.insert(new Favorite(USER_UUID, locationPenny));
+
+ // Test all authentication possibilities
+ mockMvc.perform(get("/v2/users/self/favorites")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(get("/v2/users/self/favorites")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocationList(locations))
+ .andExpect(jsonPath("$", hasSize(2)))
+ .andExpect(jsonPath("$[*].favorite").value(everyItem(equalTo(true))));
+
+ mockMvc.perform(get("/v2/users/self/favorites"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/de/sakpaas/backend/v2/controller/EndpointRemoveFavoriteByLocationIdTest.java b/src/test/java/de/sakpaas/backend/v2/controller/EndpointRemoveFavoriteByLocationIdTest.java
new file mode 100644
index 00000000..bb94f43d
--- /dev/null
+++ b/src/test/java/de/sakpaas/backend/v2/controller/EndpointRemoveFavoriteByLocationIdTest.java
@@ -0,0 +1,224 @@
+package de.sakpaas.backend.v2.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import de.sakpaas.backend.IntegrationTest;
+import de.sakpaas.backend.model.Address;
+import de.sakpaas.backend.model.Favorite;
+import de.sakpaas.backend.model.Location;
+import de.sakpaas.backend.model.LocationDetails;
+import de.sakpaas.backend.model.Occupancy;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Tests the endpoint DELETE /v2/users/self/favorites/{id}
if it conforms to the
+ * openAPI specification.
+ */
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@AutoConfigureMockMvc
+class EndpointRemoveFavoriteByLocationIdTest extends IntegrationTest {
+
+ @Test
+ void testMalformed() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Favorite favorite = new Favorite(USER_UUID, location);
+ super.insert(location);
+ super.insert(favorite);
+
+ // Test all authentication possibilities
+ mockMvc.perform(delete("/v2/users/self/favorites/xxxx")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/xxxx")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isBadRequest());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/xxxx"))
+ // No Authentication
+ .andExpect(status().isBadRequest());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.size()).isEqualTo(1);
+ assertThat(testFavorites.get(0).getLocation()).isEqualTo(location);
+ assertThat(testFavorites.get(0).getUserUuid()).isEqualTo(USER_UUID);
+ }
+
+ @Test
+ void testLocationNotFound() throws Exception {
+ // Test all authentication possibilities
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isNotFound());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.isEmpty()).isTrue();
+ }
+
+ @Test
+ void testFavoriteNotFound() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ super.insert(location);
+
+ // Test all authentication possibilities
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(false));
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.isEmpty()).isTrue();
+ }
+
+ @Test
+ void testFavoriteFound() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Favorite favorite = new Favorite(USER_UUID, location);
+ super.insert(location);
+ super.insert(favorite);
+
+ // Test all authentication possibilities
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(false));
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.isEmpty()).isTrue();
+ }
+
+ @Test
+ void testMultipleFavoritesFound() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Favorite favorite = new Favorite(USER_UUID, location);
+ Favorite favoriteDuplicate = new Favorite(USER_UUID, location);
+ super.insert(location);
+ super.insert(favorite);
+ super.insert(favoriteDuplicate);
+
+ // Test all authentication possibilities
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(false));
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.isEmpty()).isTrue();
+ }
+
+ @Test
+ void testOccupancy() throws Exception {
+ // Setup test data
+ Location location = new Location(1000L, "Edeka Eima", 42.0, 7.0,
+ new LocationDetails("supermarket", "Mo-Fr 10-22", "Edeka"),
+ new Address("DE", "Mannheim", "25565", "Handelshafen", "12a")
+ );
+ Occupancy occupancy = new Occupancy(location, 0.5, "TEST");
+ Favorite favorite = new Favorite(USER_UUID, location);
+ super.insert(location);
+ super.insert(occupancy);
+ super.insert(favorite);
+
+ // Test all authentication possibilities
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_INVALID))
+ .andExpect(status().isUnauthorized());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000")
+ .header("Authorization", AUTHENTICATION_VALID))
+ .andExpect(status().isOk())
+ .andExpect(super.expectLocation(location))
+ .andExpect(jsonPath("$.favorite").value(false))
+ .andExpect(jsonPath("$.occupancy.value").value(occupancy.getOccupancy()))
+ .andExpect(jsonPath("$.occupancy.count").value(1))
+ .andExpect(jsonPath("$.occupancy.latestReport").isString());
+
+ mockMvc.perform(delete("/v2/users/self/favorites/1000"))
+ // No Authentication
+ .andExpect(status().is4xxClientError());
+ // Authentication should be handled by Keycloak, but only the controller is being tested,
+ // thus the controller requests the Principal can not be added and a 400 Error is thrown.
+ //.andExpect(status().isUnauthorized());
+
+ // Test database change
+ List testFavorites = favoriteRepository.findByUserUuid(USER_UUID);
+ assertThat(testFavorites.isEmpty()).isTrue();
+ }
+}
\ No newline at end of file