From 92c11f9f911585ee49fc0d947084ba198f6e1fd5 Mon Sep 17 00:00:00 2001 From: Marvin Brieger Date: Tue, 9 Jun 2020 16:49:07 +0200 Subject: [PATCH 1/6] join_game_bugfix: setup for mock mvc tests, wrote test that verfies the bug --- backend/pom.xml | 5 + .../services/GameServiceImpl.java | 3 +- .../services/PlayerServiceImpl.java | 11 +-- .../webservice/UserController.java | 4 +- .../mocks/ApplicationUserMocks.java | 26 +++++ .../toothbrushgame/mocks/GameMocks.java | 70 +++---------- .../mocks/GamePreferencesMocks.java | 11 --- .../toothbrushgame/mocks/PlayerMocks.java | 40 +++----- .../services/PlayerServiceImplTest.java | 63 ------------ .../webservice/ApiCallBuilder.java | 4 + .../webservice/ApiCallContext.java | 53 ++++++++++ .../webservice/GameControllerTest.java | 98 +++++++++++++++++++ backend/src/test/resources/test.properties | 10 ++ 13 files changed, 232 insertions(+), 166 deletions(-) create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/ApplicationUserMocks.java delete mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GamePreferencesMocks.java delete mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImplTest.java create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java create mode 100644 backend/src/test/resources/test.properties diff --git a/backend/pom.xml b/backend/pom.xml index cb9723e..5d35399 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -71,6 +71,11 @@ system ${basedir}/libs/expo-server-sdk-0.4.4-SNAPSHOT.jar + + org.springframework.security + spring-security-test + 4.0.4.RELEASE + diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/GameServiceImpl.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/GameServiceImpl.java index 9ac92f1..35b7e18 100644 --- a/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/GameServiceImpl.java +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/GameServiceImpl.java @@ -11,6 +11,7 @@ import de.marvinbrieger.toothbrushgame.push.messagebuilders.MurderAssignmentNotificationService; import de.marvinbrieger.toothbrushgame.services.interfaces.CurrentUserService; import de.marvinbrieger.toothbrushgame.services.interfaces.EnsureGameOwnerService; +import de.marvinbrieger.toothbrushgame.services.interfaces.GameService; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; @@ -18,7 +19,7 @@ @Service @AllArgsConstructor -public class GameServiceImpl implements de.marvinbrieger.toothbrushgame.services.interfaces.GameService { +public class GameServiceImpl implements GameService { private final GameRepository gameRepository; private final GameCodeService gameCodeService; private final AssignmentGeneratorService assignmentHelperService; diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java index d98391d..e9bdd47 100644 --- a/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java @@ -19,13 +19,12 @@ public class PlayerServiceImpl implements PlayerService { @Override public Player joinGame(Long gameId, Player player) { - Game gameToJoin = gameRepository.findById(gameId) + return gameRepository.findById(gameId) + .map(game -> { + Player newPlayer = new Player(player, game, currentUserService.getCurrentUser()); + return playerRepository.save(newPlayer); + }) .orElseThrow(() -> new GameNotFoundException(gameId)); - - Player newPlayer = new Player(player, gameToJoin, currentUserService.getCurrentUser()); - gameToJoin.addPlayer(newPlayer); - - return playerRepository.save(player); } } diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/webservice/UserController.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/webservice/UserController.java index 9b95cc7..3e93c01 100644 --- a/backend/src/main/java/de/marvinbrieger/toothbrushgame/webservice/UserController.java +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/webservice/UserController.java @@ -1,10 +1,12 @@ package de.marvinbrieger.toothbrushgame.webservice; +import java.io.File; import de.marvinbrieger.toothbrushgame.domain.ApplicationUser; import de.marvinbrieger.toothbrushgame.services.interfaces.UserService; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.io.IOException; import java.util.Locale; @RestController @@ -14,7 +16,7 @@ public class UserController { private final UserService userService; @PostMapping("/sign-up") - public void signUp(@RequestBody ApplicationUser user) { + public void signUp(@RequestBody ApplicationUser user) throws IOException { userService.signUp(user); } diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/ApplicationUserMocks.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/ApplicationUserMocks.java new file mode 100644 index 0000000..923ccdc --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/ApplicationUserMocks.java @@ -0,0 +1,26 @@ +package de.marvinbrieger.toothbrushgame.mocks; + +import org.json.JSONException; +import org.json.JSONObject; + +public class ApplicationUserMocks { + + public static JSONObject MARVINS_DEVICE; + + public static JSONObject ELIAS_DEVICE; + + static { + try { + MARVINS_DEVICE = new JSONObject() + .put("deviceId", "marvins device") + .put("password", "marvins password"); + + ELIAS_DEVICE = new JSONObject() + .put("deviceId", "elias device") + .put("password", "elias password"); + } catch (JSONException e) { + e.printStackTrace(); + } + } + +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GameMocks.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GameMocks.java index f847006..51c98dd 100644 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GameMocks.java +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GameMocks.java @@ -1,66 +1,26 @@ package de.marvinbrieger.toothbrushgame.mocks; -import de.marvinbrieger.toothbrushgame.domain.Game; -import de.marvinbrieger.toothbrushgame.domain.GameStatus; -import de.marvinbrieger.toothbrushgame.domain.MurderAssignment; -import de.marvinbrieger.toothbrushgame.domain.Player; -import de.marvinbrieger.toothbrushgame.services.AssignmentGeneratorService; - -import java.util.ArrayList; -import java.util.List; - -import static de.marvinbrieger.toothbrushgame.mocks.GamePreferencesMocks.STANDARD_PREFERENCES; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.ELIAS; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.STORED_ALEX; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.STORED_ELIAS; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.STORED_KIPF; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.STORED_MARVIN; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.STORED_NEUMANN; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.STORED_WINTER; +import org.json.JSONException; +import org.json.JSONObject; public class GameMocks { - public static final Game SOFTSKILL_GAME; - - public static final Game STORED_SOFTSKILL_GAME; - - public static final Game SOFTSKILL_GAME_MARVIN_JOINED; - - public static final Game SOFTSKILL_GAME_STARTED; + public static JSONObject SOFTSKILL_GAME; static { - SOFTSKILL_GAME = new Game(null, "Softskillkurs SE 14", STANDARD_PREFERENCES, - null, ELIAS, null, null, null); - - List storedPlayers = new ArrayList(); - storedPlayers.add(STORED_ELIAS); - STORED_SOFTSKILL_GAME = new Game(1L, "Softskillkurs SE 14", STANDARD_PREFERENCES, - "ANTZUF", STORED_ELIAS, GameStatus.PREPARATION, storedPlayers, null); - - List playersMarvinJoined = new ArrayList(); - playersMarvinJoined.add(STORED_ELIAS); - playersMarvinJoined.add(STORED_MARVIN); - SOFTSKILL_GAME_MARVIN_JOINED = new Game(1L, "Softskillkurs SE 14", STANDARD_PREFERENCES, - "ANTZUF", STORED_ELIAS, GameStatus.PREPARATION, playersMarvinJoined, null); - - List playersStartedGame = getPlayersList(); - Game startedGame = new Game(1L, "Softskillkurs SE 14", STANDARD_PREFERENCES, - "ANTZUF", STORED_ELIAS, GameStatus.RUNNING, playersStartedGame, null); - AssignmentGeneratorService assignmentHelperService = new AssignmentGeneratorService(); - List murderAssignments = assignmentHelperService.generateKillAssignments(startedGame); - startedGame.setMurderAssignments(murderAssignments); - SOFTSKILL_GAME_STARTED = startedGame; + try { + SOFTSKILL_GAME = new JSONObject() + .put("title", "SE 14") + .put("preferences", new JSONObject() + .put("dailyReassignment", false) + .put("noAttestors", true) + .put("furtherRules", "nicht beim Essen töten")) + .put("owner", new JSONObject() + .put("playerName", "Marvin")); + } catch (JSONException e) { + e.printStackTrace(); + } } - private static List getPlayersList() { - List players = new ArrayList(); - players.add(STORED_ELIAS); - players.add(STORED_MARVIN); - players.add(STORED_ALEX); - players.add(STORED_KIPF); - players.add(STORED_WINTER); - players.add(STORED_NEUMANN); - return players; - } } diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GamePreferencesMocks.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GamePreferencesMocks.java deleted file mode 100644 index ccd720a..0000000 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/GamePreferencesMocks.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.marvinbrieger.toothbrushgame.mocks; - -import de.marvinbrieger.toothbrushgame.domain.GamePreferences; -import java.util.HashSet; - -public class GamePreferencesMocks { - - public static final GamePreferences STANDARD_PREFERENCES - = new GamePreferences(1L, false, true, "", new HashSet<>()); - -} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/PlayerMocks.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/PlayerMocks.java index 8228dbf..814f2c3 100644 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/PlayerMocks.java +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/mocks/PlayerMocks.java @@ -2,40 +2,22 @@ import de.marvinbrieger.toothbrushgame.domain.ApplicationUser; import de.marvinbrieger.toothbrushgame.domain.Player; +import org.json.JSONException; +import org.json.JSONObject; import java.util.HashSet; public class PlayerMocks { - public static final ApplicationUser USER_MARVIN = new ApplicationUser(1L, "marvins device", "marvins password", null, new HashSet<>(), - null); - public static final ApplicationUser USER_ELIAS = new ApplicationUser(2L, "elias device", "elias password", null, new HashSet<>(), null); - public static final Player ELIAS = new Player(null, null, "Elias", USER_ELIAS, null); + public static JSONObject ELIAS_PLAYER; - public static final Player STORED_ELIAS = new Player(1L, null, "Elias", USER_ELIAS, null); - - public static final Player MARVIN = new Player(null, null, "Marvin", USER_MARVIN, null); - - public static final Player STORED_MARVIN = new Player(2L, null, "Marvin", USER_MARVIN, null); - - public static final Player ALEX = new Player(null, null, "Alex", null, null); - - public static final Player STORED_ALEX = new Player(3L, null, "Alex", null, null); - - public static final Player KIPF = new Player(null, null, "Kipf", null, null); - - public static final Player STORED_KIPF = new Player(4L, null, "Kipf", null, null); - - public static final Player WINTER = new Player(null, null, "Winter", null, null); - - public static final Player STORED_WINTER = new Player(5L, null, "Winter", null, null); - - public static final Player NEUMANN = new Player(null, null, "Neumann", null, null); - - public static final Player STORED_NEUMANN = new Player(6L, null, "Neumann", null, null); - - public static final Player SCHELLY = new Player(null, null, "Schelly", null, null); - - public static final Player STORED_SCHELLY = new Player(7L, null, "Schelly", null, null); + static { + try { + ELIAS_PLAYER = new JSONObject() + .put("playerName", "Elias"); + } catch (JSONException e) { + e.printStackTrace(); + } + } } diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImplTest.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImplTest.java deleted file mode 100644 index 723471a..0000000 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImplTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package de.marvinbrieger.toothbrushgame.services; - -import de.marvinbrieger.toothbrushgame.domain.Game; -import de.marvinbrieger.toothbrushgame.exceptions.GameNotFoundException; -import de.marvinbrieger.toothbrushgame.exceptions.PlayerAlreadyExistsException; -import de.marvinbrieger.toothbrushgame.persistence.GameRepository; -import de.marvinbrieger.toothbrushgame.persistence.PlayerRepository; -import de.marvinbrieger.toothbrushgame.services.interfaces.CurrentUserService; -import de.marvinbrieger.toothbrushgame.services.interfaces.PlayerService; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.Optional; - -import static de.marvinbrieger.toothbrushgame.mocks.GameMocks.STORED_SOFTSKILL_GAME; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.ELIAS; -import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.MARVIN; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@RunWith(SpringRunner.class) -public class PlayerServiceImplTest { - - private PlayerService playerService; - - private final Long EXISTING_ID = 1L; - - private final Long MISSING_ID = 2L; - - @Before - public void setup() { - PlayerRepository playerRepository = mock(PlayerRepository.class); - when(playerRepository.existsByGame_IdAndPlayerName(EXISTING_ID, "Elias")).thenReturn(true); - when(playerRepository.existsByGame_IdAndPlayerName(EXISTING_ID, "Marvin")).thenReturn(false); - - GameRepository gameRepository = mock(GameRepository.class); - Optional standardGame = Optional.of(STORED_SOFTSKILL_GAME); - when(gameRepository.findById(EXISTING_ID)).thenReturn(standardGame); - when(gameRepository.findById(MISSING_ID)).thenReturn(Optional.empty()); - - CurrentUserService currentUserService = mock(CurrentUserService.class); - - this.playerService = new PlayerServiceImpl(playerRepository, gameRepository, currentUserService); - } - - @Test(expected = PlayerAlreadyExistsException.class) - public void ownerShouldJoin_ThrowsException() { - playerService.joinGame(EXISTING_ID, ELIAS); - } - - @Test(expected = GameNotFoundException.class) - public void joinToMissingGame_ThrowsException() { - playerService.joinGame(MISSING_ID, MARVIN); - } - - @Test - public void joinToGame_Succeeds() { - playerService.joinGame(EXISTING_ID, MARVIN); - } - -} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java new file mode 100644 index 0000000..888704b --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java @@ -0,0 +1,4 @@ +package de.marvinbrieger.toothbrushgame.webservice; + +public class ApiCallBuilder { +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java new file mode 100644 index 0000000..71a3e78 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java @@ -0,0 +1,53 @@ +package de.marvinbrieger.toothbrushgame.webservice; + +import org.json.JSONObject; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +public class ApiCallContext { + + private String bearerToken; + + private MockMvc mockMVC; + + public ApiCallContext(MockMvc mockMvc, JSONObject applicatonUser) throws Exception { + this.mockMVC = mockMvc; + + mockMvc.perform(MockMvcRequestBuilders.post("/user/sign-up") + .contentType(MediaType.APPLICATION_JSON) + .characterEncoding("utf-8") + .content(applicatonUser.toString())) + .andDo(print()); + + this.bearerToken = mockMvc.perform(MockMvcRequestBuilders.post("/user/login") + .contentType(MediaType.APPLICATION_JSON) + .characterEncoding("utf-8") + .content(applicatonUser.toString())) + .andDo(print()) + .andReturn() + .getResponse() + .getHeader("Authorization"); + } + + ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception { + return mockMVC.perform(builder + .header("Authorization", bearerToken) + .contentType(MediaType.APPLICATION_JSON) + .characterEncoding("utf-8") + ).andDo(print()); + } + + JSONObject performAndGetJson(MockHttpServletRequestBuilder builder) throws Exception { + return new JSONObject( + perform(builder) + .andReturn() + .getResponse() + .getContentAsString() + ); + } + +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java new file mode 100644 index 0000000..beabc13 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java @@ -0,0 +1,98 @@ +package de.marvinbrieger.toothbrushgame.webservice; + +import de.marvinbrieger.toothbrushgame.services.interfaces.UserService; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +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.context.SpringBootTest.WebEnvironment; +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import javax.transaction.Transactional; + +import static de.marvinbrieger.toothbrushgame.mocks.ApplicationUserMocks.ELIAS_DEVICE; +import static de.marvinbrieger.toothbrushgame.mocks.ApplicationUserMocks.MARVINS_DEVICE; +import static de.marvinbrieger.toothbrushgame.mocks.GameMocks.SOFTSKILL_GAME; +import static de.marvinbrieger.toothbrushgame.mocks.PlayerMocks.ELIAS_PLAYER; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@Transactional +@TestPropertySource("classpath:test.properties") +@AutoConfigureMockMvc +public class GameControllerTest { + + @Autowired + private UserService userService; + + @Autowired + private WebApplicationContext webApplicationContext; + + private MockMvc mockMvc; + + private ApiCallContext marvinContext; + + private ApiCallContext eliasContext; + + @Before + public void init() throws Exception { + mockMvc = MockMvcBuilders + .webAppContextSetup(webApplicationContext) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build(); + + marvinContext = new ApiCallContext(mockMvc, MARVINS_DEVICE); + eliasContext = new ApiCallContext(mockMvc, ELIAS_DEVICE); + } + + @Test + public void testCreateGame() throws Exception { + JSONObject creationAnswer = marvinContext.performAndGetJson(post("/games") + .content(SOFTSKILL_GAME.toString())); + + String gameId = creationAnswer.getString("id"); + JSONObject game = marvinContext.performAndGetJson(get("/games/" + gameId)); + + assertEquals("SE 14", game.getString("title")); + } + + @Test + public void testJoinGame() throws Exception { + // Arrange + JSONObject creationAnswer = marvinContext.performAndGetJson(post("/games") + .content(SOFTSKILL_GAME.toString())); + + // Act + String gameId = creationAnswer.getString("id"); + JSONObject player = marvinContext.performAndGetJson(post("/games/" + gameId + "/players") + .content(ELIAS_PLAYER.toString())); + + // Assert + JSONObject game = marvinContext.performAndGetJson(get("/games/" + gameId)); + JSONArray playersArray = game.getJSONArray("players"); + boolean found = false; + for (int k = 0; k < playersArray.length(); k++) { + JSONObject joinedPlayer = playersArray.getJSONObject(k); + if (joinedPlayer.getString("playerName").equals(ELIAS_PLAYER.getString("playerName"))) + found = true; + } + + if (!found) + fail("player should be containd after joining"); + } + +} diff --git a/backend/src/test/resources/test.properties b/backend/src/test/resources/test.properties new file mode 100644 index 0000000..c8defcf --- /dev/null +++ b/backend/src/test/resources/test.properties @@ -0,0 +1,10 @@ +# Data-Source-Settings +spring.datasource.url=jdbc:h2:mem:mydb;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.username=root +spring.datasource.password=dbpass +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.platform=h2 + +# The SQL dialect makes Hibernate generate better SQL for the chosen database +spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect +spring.jpa.hibernate.ddl-auto=create From c01c48b2832781e7021af182bf33511786c149de Mon Sep 17 00:00:00 2001 From: Marvin Brieger Date: Tue, 9 Jun 2020 22:32:42 +0200 Subject: [PATCH 2/6] join_game_bugfix: typo --- .../toothbrushgame/webservice/GameControllerTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java index beabc13..c1a90e2 100644 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java @@ -11,13 +11,15 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; +import org.springframework.test.annotation.Commit; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Isolation; import org.springframework.web.context.WebApplicationContext; -import javax.transaction.Transactional; +import org.springframework.transaction.annotation.Transactional; import static de.marvinbrieger.toothbrushgame.mocks.ApplicationUserMocks.ELIAS_DEVICE; import static de.marvinbrieger.toothbrushgame.mocks.ApplicationUserMocks.MARVINS_DEVICE; @@ -27,7 +29,6 @@ import static org.junit.Assert.fail; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @@ -92,7 +93,7 @@ public void testJoinGame() throws Exception { } if (!found) - fail("player should be containd after joining"); + fail("player should be contained after joining"); } } From 422457571dec75a6d7217a1635df9e09b09d6011 Mon Sep 17 00:00:00 2001 From: Marvin Brieger Date: Wed, 10 Jun 2020 10:00:39 +0200 Subject: [PATCH 3/6] running tests --- .../utils/DbCleaningHelper.java | 21 ++++++++ .../toothbrushgame/utils/MockMvcHelper.java | 16 ++++++ .../utils/MurderApiContext.java | 54 +++++++++++++++++++ .../utils/MurderApiRequest.java | 38 +++++++++++++ .../utils/MurderApiResponse.java | 24 +++++++++ .../webservice/ApiCallBuilder.java | 4 -- .../webservice/ApiCallContext.java | 53 ------------------ .../webservice/GameControllerTest.java | 49 +++++++++++------ 8 files changed, 185 insertions(+), 74 deletions(-) create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/DbCleaningHelper.java create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MockMvcHelper.java create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiContext.java create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiRequest.java create mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiResponse.java delete mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java delete mode 100644 backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/DbCleaningHelper.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/DbCleaningHelper.java new file mode 100644 index 0000000..01b9d87 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/DbCleaningHelper.java @@ -0,0 +1,21 @@ +package de.marvinbrieger.toothbrushgame.utils; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class DbCleaningHelper { + + public static void truncateAllTables(Connection conn) throws SQLException { + conn.createStatement().executeUpdate("SET FOREIGN_KEY_CHECKS=0"); + ResultSet rs = conn.createStatement(). + executeQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = SCHEMA()"); + + while (rs.next()) { + String tableName = rs.getString(1); + conn.createStatement().executeUpdate("TRUNCATE TABLE " + tableName); + } + conn.createStatement().executeUpdate("SET FOREIGN_KEY_CHECKS=1"); + } + +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MockMvcHelper.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MockMvcHelper.java new file mode 100644 index 0000000..358c7e9 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MockMvcHelper.java @@ -0,0 +1,16 @@ +package de.marvinbrieger.toothbrushgame.utils; + +import org.json.JSONObject; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; + +abstract public class MockMvcHelper { + + public static MockHttpServletRequestBuilder withJsonHeaders(MockHttpServletRequestBuilder builder) { + return builder.contentType(MediaType.APPLICATION_JSON) + .characterEncoding("utf-8"); + } + +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiContext.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiContext.java new file mode 100644 index 0000000..e6baf75 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiContext.java @@ -0,0 +1,54 @@ +package de.marvinbrieger.toothbrushgame.utils; + +import org.json.JSONObject; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import static de.marvinbrieger.toothbrushgame.utils.MockMvcHelper.withJsonHeaders; +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.MockMvcResultHandlers.print; + +public class MurderApiContext { + + private String bearerToken; + + private MockMvc mockMvc; + + private boolean print; + + public MurderApiContext(MockMvc mockMvc, JSONObject applicationUser) throws Exception { + this(mockMvc, applicationUser, false); + } + + public MurderApiContext(MockMvc mockMvc, JSONObject applicationUser, boolean print) throws Exception { + this.mockMvc = mockMvc; + this.print = print; + + ResultActions signUp = mockMvc.perform( + withJsonHeaders(post("/user/sign-up")) + .content(applicationUser.toString())); + ResultActions login = mockMvc.perform( + withJsonHeaders(post("/user/login")) + .content(applicationUser.toString())); + + if (print) { + signUp.andDo(print()); + login.andDo(print()); + } + + this.bearerToken = login.andReturn() + .getResponse() + .getHeader("Authorization"); + } + + public MurderApiRequest createGet(String route) throws Exception { + return new MurderApiRequest(mockMvc, withJsonHeaders(get(route)) + .header("Authorization", bearerToken), print); + } + + public MurderApiRequest createPost(String route) throws Exception { + return new MurderApiRequest(mockMvc, withJsonHeaders(post(route)) + .header("Authorization", bearerToken), print); + } + +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiRequest.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiRequest.java new file mode 100644 index 0000000..81729a9 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiRequest.java @@ -0,0 +1,38 @@ +package de.marvinbrieger.toothbrushgame.utils; + +import org.json.JSONObject; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +public class MurderApiRequest { + + private MockMvc mockMvc; + + private MockHttpServletRequestBuilder requestBuilder; + + private boolean print; + + public MurderApiRequest(MockMvc mockMvc, MockHttpServletRequestBuilder requestBuilder, boolean print) throws Exception { + this.mockMvc = mockMvc; + this.requestBuilder = requestBuilder; + this.print = print; + } + + public MurderApiRequest content(JSONObject payload) { + requestBuilder.content(payload.toString()); + return this; + } + + public MurderApiResponse send() throws Exception { + ResultActions result = mockMvc.perform(requestBuilder); + if (print) + result.andDo(print()); + + return new MurderApiResponse(result.andReturn().getResponse()); + } + +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiResponse.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiResponse.java new file mode 100644 index 0000000..a26eeb9 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/utils/MurderApiResponse.java @@ -0,0 +1,24 @@ +package de.marvinbrieger.toothbrushgame.utils; + +import org.json.JSONException; +import org.json.JSONObject; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.web.servlet.ResultActions; + +import java.io.UnsupportedEncodingException; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +public class MurderApiResponse { + + private MockHttpServletResponse response; + + public MurderApiResponse(MockHttpServletResponse response) { + this.response = response; + } + + public JSONObject getJsonAnswer() throws UnsupportedEncodingException, JSONException { + return new JSONObject(response.getContentAsString()); + } + +} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java deleted file mode 100644 index 888704b..0000000 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallBuilder.java +++ /dev/null @@ -1,4 +0,0 @@ -package de.marvinbrieger.toothbrushgame.webservice; - -public class ApiCallBuilder { -} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java deleted file mode 100644 index 71a3e78..0000000 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/ApiCallContext.java +++ /dev/null @@ -1,53 +0,0 @@ -package de.marvinbrieger.toothbrushgame.webservice; - -import org.json.JSONObject; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; - -public class ApiCallContext { - - private String bearerToken; - - private MockMvc mockMVC; - - public ApiCallContext(MockMvc mockMvc, JSONObject applicatonUser) throws Exception { - this.mockMVC = mockMvc; - - mockMvc.perform(MockMvcRequestBuilders.post("/user/sign-up") - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding("utf-8") - .content(applicatonUser.toString())) - .andDo(print()); - - this.bearerToken = mockMvc.perform(MockMvcRequestBuilders.post("/user/login") - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding("utf-8") - .content(applicatonUser.toString())) - .andDo(print()) - .andReturn() - .getResponse() - .getHeader("Authorization"); - } - - ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception { - return mockMVC.perform(builder - .header("Authorization", bearerToken) - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding("utf-8") - ).andDo(print()); - } - - JSONObject performAndGetJson(MockHttpServletRequestBuilder builder) throws Exception { - return new JSONObject( - perform(builder) - .andReturn() - .getResponse() - .getContentAsString() - ); - } - -} diff --git a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java index c1a90e2..153d495 100644 --- a/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java @@ -1,6 +1,8 @@ package de.marvinbrieger.toothbrushgame.webservice; import de.marvinbrieger.toothbrushgame.services.interfaces.UserService; +import de.marvinbrieger.toothbrushgame.utils.DbCleaningHelper; +import de.marvinbrieger.toothbrushgame.utils.MurderApiContext; import org.json.JSONArray; import org.json.JSONObject; import org.junit.Before; @@ -16,10 +18,9 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Isolation; import org.springframework.web.context.WebApplicationContext; -import org.springframework.transaction.annotation.Transactional; +import javax.sql.DataSource; import static de.marvinbrieger.toothbrushgame.mocks.ApplicationUserMocks.ELIAS_DEVICE; import static de.marvinbrieger.toothbrushgame.mocks.ApplicationUserMocks.MARVINS_DEVICE; @@ -32,7 +33,7 @@ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@Transactional +@Commit @TestPropertySource("classpath:test.properties") @AutoConfigureMockMvc public class GameControllerTest { @@ -43,30 +44,38 @@ public class GameControllerTest { @Autowired private WebApplicationContext webApplicationContext; + @Autowired + DataSource dataSource; + private MockMvc mockMvc; - private ApiCallContext marvinContext; + private MurderApiContext marvinContext; - private ApiCallContext eliasContext; + private MurderApiContext eliasContext; @Before public void init() throws Exception { + DbCleaningHelper.truncateAllTables(dataSource.getConnection()); + mockMvc = MockMvcBuilders .webAppContextSetup(webApplicationContext) .apply(SecurityMockMvcConfigurers.springSecurity()) .build(); - marvinContext = new ApiCallContext(mockMvc, MARVINS_DEVICE); - eliasContext = new ApiCallContext(mockMvc, ELIAS_DEVICE); + marvinContext = new MurderApiContext(mockMvc, MARVINS_DEVICE); + eliasContext = new MurderApiContext(mockMvc, ELIAS_DEVICE); } @Test public void testCreateGame() throws Exception { - JSONObject creationAnswer = marvinContext.performAndGetJson(post("/games") - .content(SOFTSKILL_GAME.toString())); + JSONObject game = marvinContext.createPost("/games") + .content(SOFTSKILL_GAME) + .send() + .getJsonAnswer(); - String gameId = creationAnswer.getString("id"); - JSONObject game = marvinContext.performAndGetJson(get("/games/" + gameId)); + game = marvinContext.createGet("/games/" + game.getString("id")) + .send() + .getJsonAnswer(); assertEquals("SE 14", game.getString("title")); } @@ -74,16 +83,22 @@ public void testCreateGame() throws Exception { @Test public void testJoinGame() throws Exception { // Arrange - JSONObject creationAnswer = marvinContext.performAndGetJson(post("/games") - .content(SOFTSKILL_GAME.toString())); + JSONObject game = marvinContext.createPost("/games") + .content(SOFTSKILL_GAME) + .send() + .getJsonAnswer(); // Act - String gameId = creationAnswer.getString("id"); - JSONObject player = marvinContext.performAndGetJson(post("/games/" + gameId + "/players") - .content(ELIAS_PLAYER.toString())); + JSONObject player = eliasContext.createPost("/games/" + game.getString("id") + "/players") + .content(ELIAS_PLAYER) + .send() + .getJsonAnswer(); + + game = eliasContext.createGet("/games/" + game.getString("id")) + .send() + .getJsonAnswer(); // Assert - JSONObject game = marvinContext.performAndGetJson(get("/games/" + gameId)); JSONArray playersArray = game.getJSONArray("players"); boolean found = false; for (int k = 0; k < playersArray.length(); k++) { From a5cc9189d014dc3142a991b72318c1109f79278e Mon Sep 17 00:00:00 2001 From: Marvin Brieger Date: Wed, 10 Jun 2020 10:02:51 +0200 Subject: [PATCH 4/6] readd validation --- .../marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java index e9bdd47..0b65ca8 100644 --- a/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/services/PlayerServiceImpl.java @@ -22,6 +22,7 @@ public Player joinGame(Long gameId, Player player) { return gameRepository.findById(gameId) .map(game -> { Player newPlayer = new Player(player, game, currentUserService.getCurrentUser()); + game.addPlayer(newPlayer); return playerRepository.save(newPlayer); }) .orElseThrow(() -> new GameNotFoundException(gameId)); From 3386fd8fec2588be7b6cddba0dea3fcdaca73580 Mon Sep 17 00:00:00 2001 From: Elias Keis <13063245+elKei24@users.noreply.github.com> Date: Wed, 10 Jun 2020 16:37:39 +0200 Subject: [PATCH 5/6] set jwt secret for unit tests --- backend/src/test/resources/test.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/test/resources/test.properties b/backend/src/test/resources/test.properties index c8defcf..a85260f 100644 --- a/backend/src/test/resources/test.properties +++ b/backend/src/test/resources/test.properties @@ -8,3 +8,5 @@ spring.datasource.platform=h2 # The SQL dialect makes Hibernate generate better SQL for the chosen database spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create + +murder.jwt.secret=12345 From 8be25507efaefaf3e9b1a7bcd2d805a3f64dbf91 Mon Sep 17 00:00:00 2001 From: Elias Keis <13063245+elKei24@users.noreply.github.com> Date: Wed, 10 Jun 2020 16:47:11 +0200 Subject: [PATCH 6/6] no need for pg db in CI any more --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70b605e..d04b1f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,11 +19,6 @@ jobs: key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - - uses: harmon758/postgresql-action@v1 - with: - postgresql db: 'murdergame' - postgresql user: 'murdergame' - postgresql password: 'murdergame' - name: Compile, test and verify working-directory: ./backend run: ./mvnw -q -Dspring.datasource.url="jdbc:postgresql://localhost:5432/murdergame" -Dspring.datasource.username="murdergame" -Dspring.datasource.password="murdergame" verify