diff --git a/backend/pom.xml b/backend/pom.xml index 17c6151..5a0b791 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -68,6 +68,11 @@ expo-server-sdk 0.6.0 + + org.springframework.security + spring-security-test + 4.0.4.RELEASE + diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/AssignmentList.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/AssignmentList.java new file mode 100644 index 0000000..624d3d3 --- /dev/null +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/AssignmentList.java @@ -0,0 +1,58 @@ +package de.marvinbrieger.toothbrushgame.domain; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import de.marvinbrieger.toothbrushgame.exceptions.MurderAssignmentNotFoundException; +import de.marvinbrieger.toothbrushgame.webservice.mapping.FilteredMurderAssignmentsSerializer; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import net.bytebuddy.implementation.bind.annotation.IgnoreForBinding; + +import javax.persistence.CascadeType; +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.OneToMany; +import javax.persistence.Transient; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Embeddable +public class AssignmentList { + + @Transient + private Game game; + + @OneToMany( + cascade = CascadeType.ALL, + mappedBy = "game" + ) + @JsonSerialize(using = FilteredMurderAssignmentsSerializer.class) + private List murderAssignments; + + public MurderAssignment findAssignment(Long assignmentId) { + return this.murderAssignments.parallelStream() + .filter(assignment -> assignment.getId().equals(assignmentId)) + .findAny() + .orElseThrow(() -> new MurderAssignmentNotFoundException(assignmentId)); + } + + private MurderAssignment findSuccessor(MurderAssignment source) { + return murderAssignments.parallelStream() + .filter(source::hasSuccessor) + .findAny() + .orElseThrow(IllegalArgumentException::new); + } + + public void newAssignemntForSuccessfullKiller(MurderAssignment currentAssignment) { + Player killer = currentAssignment.getKiller(); + MurderAssignment victimsAssignment = findSuccessor(currentAssignment); + + MurderAssignment killersNewMission = new MurderAssignment(null, game, killer, victimsAssignment.getTarget(), + MurderAssignmentStatus.PENDING, null); + + getMurderAssignments().add(killersNewMission); + } + +} diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Game.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Game.java index 128385b..67ea95f 100644 --- a/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Game.java +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Game.java @@ -1,11 +1,9 @@ package de.marvinbrieger.toothbrushgame.domain; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import de.marvinbrieger.toothbrushgame.exceptions.GameInWrongStateException; import de.marvinbrieger.toothbrushgame.exceptions.MurderAssignmentNotFoundException; import de.marvinbrieger.toothbrushgame.exceptions.PlayerAlreadyExistsException; -import de.marvinbrieger.toothbrushgame.webservice.mapping.FilteredMurderAssignmentsSerializer; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -43,12 +41,8 @@ public class Game { @OneToMany(mappedBy = "game") private List players; - @OneToMany( - cascade = CascadeType.ALL, - mappedBy = "game" - ) - @JsonSerialize(using = FilteredMurderAssignmentsSerializer.class) - private List murderAssignments; + @Embedded + private AssignmentList murderAssignments; /** * Creates a new game with the given game code, the title and preferences as the given game, the status {@link GameStatus#PREPARATION}, @@ -66,42 +60,25 @@ public Game(Game game, String gameCode, ApplicationUser creator) { this.gameCode = gameCode; this.gameStatus = GameStatus.PREPARATION; this.players = new ArrayList<>(); - this.murderAssignments = new ArrayList<>(); this.owner = new Player(game.getOwner(), this, creator); + this.murderAssignments = game.getMurderAssignments(); // owner is also a player this.players.add(this.owner); } - public boolean inPreparation() { - return gameStatus == GameStatus.PREPARATION; + public boolean notInPreparation() { + return gameStatus != GameStatus.PREPARATION; } @JsonIgnore - public boolean isRunning() { - return gameStatus == GameStatus.RUNNING; - } - - private MurderAssignment findSuccessor(MurderAssignment source) { - for (MurderAssignment potentialSuccessor : murderAssignments) - if (source.hasSuccessor(potentialSuccessor)) - return potentialSuccessor; - - throw new IllegalArgumentException(); - } - - private void addSucceedingAssignment(MurderAssignment currentAssignment) { - Player killer = currentAssignment.getKiller(); - MurderAssignment targetsAssignment = findSuccessor(currentAssignment); - - MurderAssignment killersNewMission = new MurderAssignment(null, this, killer, targetsAssignment.getTarget(), - MurderAssignmentStatus.PENDING, null); - - getMurderAssignments().add(killersNewMission); + public boolean notRunning() { + return gameStatus != GameStatus.RUNNING; } /** * Fulfills the assignment with given ID. + * * @param assignmentId ID of the assignment that is fulfilled * @throws GameInWrongStateException if the game is not running * @throws MurderAssignmentNotFoundException if there is no assignment with that ID that is part of the game @@ -109,30 +86,28 @@ private void addSucceedingAssignment(MurderAssignment currentAssignment) { */ public void commitMurder(Long assignmentId) { // ensure game is running - if (!this.isRunning()) + if (this.notRunning()) throw new GameInWrongStateException(GameStatus.RUNNING, getGameStatus()); // get the assignment - MurderAssignment assignment = this.murderAssignments.parallelStream() - .filter(assig -> assig.getId().equals(assignmentId)) - .findAny() - .orElseThrow(() -> new MurderAssignmentNotFoundException(assignmentId)); + MurderAssignment currentAssignment = murderAssignments.findAssignment(assignmentId); // commit murder and add new assignment for the killer - assignment.commitMurder(); - assignment.getTarget().getCurrentAssignment().setAssignmentStatus(MurderAssignmentStatus.FAILED); - addSucceedingAssignment(assignment); + currentAssignment.commitMurder(); + currentAssignment.getTarget().setFailed(); + murderAssignments.newAssignemntForSuccessfullKiller(currentAssignment); } /** * Lets the given player join the game. + * * @param player the joining player * @throws GameInWrongStateException if the game is not in preparation * @throws PlayerAlreadyExistsException if there is already a player with the same name or user in the game */ public void addPlayer(Player player) { // check game state - if (!inPreparation()) + if (notInPreparation()) throw new GameInWrongStateException(GameStatus.PREPARATION, getGameStatus()); // check neither player with same name nor with same user has already joined @@ -157,21 +132,22 @@ public void addPlayer(Player player) { * @throws GameInWrongStateException if the game is not in preparation */ public void start(List assignments) { - // check and update state - if (!inPreparation()) + if (notInPreparation()) throw new GameInWrongStateException(GameStatus.PREPARATION, getGameStatus()); - setGameStatus(GameStatus.RUNNING); - setMurderAssignments(assignments); + setGameStatus(GameStatus.RUNNING); + setMurderAssignments(new AssignmentList(this, assignments)); } /** * Ends the game. + * * @throws GameInWrongStateException if the game is not running */ public void end() { - if (isRunning()) + if (notRunning()) throw new GameInWrongStateException(GameStatus.RUNNING, getGameStatus()); + setGameStatus(GameStatus.FINISHED); } } diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/MurderAssignment.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/MurderAssignment.java index 11178a3..bd073ee 100644 --- a/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/MurderAssignment.java +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/MurderAssignment.java @@ -42,13 +42,12 @@ public boolean isPending() { return assignmentStatus == MurderAssignmentStatus.PENDING; } - public boolean hasSuccessor(MurderAssignment assignment) { return target.equals(assignment.killer) && assignment.isPending(); } public void commitMurder() { - if (this.getAssignmentStatus() != MurderAssignmentStatus.PENDING) + if (!isPending()) throw new MurderAssignmentNotFoundException(this.getId(), MurderAssignmentStatus.PENDING); Murder murder = new Murder(null, Instant.now(), this); diff --git a/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Player.java b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Player.java index a9e20cf..ce29191 100644 --- a/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Player.java +++ b/backend/src/main/java/de/marvinbrieger/toothbrushgame/domain/Player.java @@ -48,8 +48,12 @@ public Player(Player player, Game game, ApplicationUser user) { this(null, game, player.getPlayerName(), user, new LinkedList<>()); } + public void setFailed() { + getCurrentAssignment().setAssignmentStatus(MurderAssignmentStatus.FAILED); + } + @JsonIgnore - public MurderAssignment getCurrentAssignment() { + private MurderAssignment getCurrentAssignment() { return assignments.parallelStream() .filter(assignment -> assignment.getAssignmentStatus() == MurderAssignmentStatus.PENDING) .findFirst() 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..0b65ca8 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,13 @@ 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()); + game.addPlayer(newPlayer); + 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/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/GameControllerTest.java b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java new file mode 100644 index 0000000..153d495 --- /dev/null +++ b/backend/src/test/java/de/marvinbrieger/toothbrushgame/webservice/GameControllerTest.java @@ -0,0 +1,114 @@ +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; +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.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.web.context.WebApplicationContext; + +import javax.sql.DataSource; + +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; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@Commit +@TestPropertySource("classpath:test.properties") +@AutoConfigureMockMvc +public class GameControllerTest { + + @Autowired + private UserService userService; + + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + DataSource dataSource; + + private MockMvc mockMvc; + + private MurderApiContext marvinContext; + + private MurderApiContext eliasContext; + + @Before + public void init() throws Exception { + DbCleaningHelper.truncateAllTables(dataSource.getConnection()); + + mockMvc = MockMvcBuilders + .webAppContextSetup(webApplicationContext) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build(); + + marvinContext = new MurderApiContext(mockMvc, MARVINS_DEVICE); + eliasContext = new MurderApiContext(mockMvc, ELIAS_DEVICE); + } + + @Test + public void testCreateGame() throws Exception { + JSONObject game = marvinContext.createPost("/games") + .content(SOFTSKILL_GAME) + .send() + .getJsonAnswer(); + + game = marvinContext.createGet("/games/" + game.getString("id")) + .send() + .getJsonAnswer(); + + assertEquals("SE 14", game.getString("title")); + } + + @Test + public void testJoinGame() throws Exception { + // Arrange + JSONObject game = marvinContext.createPost("/games") + .content(SOFTSKILL_GAME) + .send() + .getJsonAnswer(); + + // Act + JSONObject player = eliasContext.createPost("/games/" + game.getString("id") + "/players") + .content(ELIAS_PLAYER) + .send() + .getJsonAnswer(); + + game = eliasContext.createGet("/games/" + game.getString("id")) + .send() + .getJsonAnswer(); + + // Assert + 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 contained 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