diff options
Diffstat (limited to 'sw-server/src/test/kotlin/org/luxons')
12 files changed, 1203 insertions, 0 deletions
diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/SevenWondersTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/SevenWondersTest.kt new file mode 100644 index 00000000..01de366a --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/SevenWondersTest.kt @@ -0,0 +1,145 @@ +package org.luxons.sevenwonders + +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.luxons.sevenwonders.test.api.SevenWondersClient +import org.luxons.sevenwonders.test.api.SevenWondersSession +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment +import org.springframework.boot.web.server.LocalServerPort +import org.springframework.test.context.junit4.SpringRunner +import java.util.concurrent.TimeUnit +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@RunWith(SpringRunner::class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +class SevenWondersTest { + + @LocalServerPort + private val randomServerPort: Int = 0 + + private lateinit var client: SevenWondersClient + + private lateinit var serverUrl: String + + @Before + fun setUpClientAndUrl() { + client = SevenWondersClient() + serverUrl = "ws://localhost:$randomServerPort" + } + + private fun disconnect(vararg sessions: SevenWondersSession) { + for (session in sessions) { + session.disconnect() + } + } + + @Test + fun chooseName() { + val session = client.connect(serverUrl) + val playerName = "Test User" + val player = session.chooseName(playerName) + assertNotNull(player) + assertEquals(playerName, player.displayName) + session.disconnect() + } + + private fun newPlayer(name: String): SevenWondersSession { + val otherSession = client.connect(serverUrl) + otherSession.chooseName(name) + return otherSession + } + + @Test + fun lobbySubscription_ignoredForOutsiders() { + val ownerSession = newPlayer("GameOwner") + val session1 = newPlayer("Player1") + val session2 = newPlayer("Player2") + val gameName = "Test Game" + val lobby = ownerSession.createGame(gameName) + session1.joinGame(lobby.id) + session2.joinGame(lobby.id) + + val outsiderSession = newPlayer("Outsider") + val session = outsiderSession.jackstompSession + val started = session.subscribeEmptyMsgs("/topic/lobby/" + lobby.id + "/started") + + ownerSession.startGame(lobby.id) + val nothing = started.next(1, TimeUnit.SECONDS) + assertNull(nothing) + disconnect(ownerSession, session1, session2, outsiderSession) + } + + @Test + fun createGame_success() { + val ownerSession = newPlayer("GameOwner") + + val gameName = "Test Game" + val lobby = ownerSession.createGame(gameName) + assertNotNull(lobby) + assertEquals(gameName, lobby.name) + + disconnect(ownerSession) + } + + @Test + fun createGame_seenByConnectedPlayers() { + val otherSession = newPlayer("OtherPlayer") + val games = otherSession.watchGames() + + var receivedLobbies = games.next() + assertNotNull(receivedLobbies) + assertEquals(0, receivedLobbies.size) + + val ownerSession = newPlayer("GameOwner") + val gameName = "Test Game" + val createdLobby = ownerSession.createGame(gameName) + + receivedLobbies = games.next() + assertNotNull(receivedLobbies) + assertEquals(1, receivedLobbies.size) + val receivedLobby = receivedLobbies[0] + assertEquals(createdLobby.id, receivedLobby.id) + assertEquals(createdLobby.name, receivedLobby.name) + + disconnect(ownerSession, otherSession) + } + + @Test + fun startGame_3players() { + val session1 = newPlayer("Player1") + val session2 = newPlayer("Player2") + + val lobby = session1.createGame("Test Game") + session2.joinGame(lobby.id) + + val session3 = newPlayer("Player3") + session3.joinGame(lobby.id) + + session1.startGame(lobby.id) + + val turns1 = session1.watchTurns() + val turns2 = session2.watchTurns() + val turns3 = session3.watchTurns() + session1.sayReady() + session2.sayReady() + session3.sayReady() + val turn1 = turns1.next() + val turn2 = turns2.next() + val turn3 = turns3.next() + assertNotNull(turn1) + assertNotNull(turn2) + assertNotNull(turn3) + + disconnect(session1, session2, session3) + } + + @After + fun tearDown() { + client.stop() + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/GameBrowserControllerTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/GameBrowserControllerTest.kt new file mode 100644 index 00000000..343b7f34 --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/GameBrowserControllerTest.kt @@ -0,0 +1,124 @@ +package org.luxons.sevenwonders.controllers + +import org.junit.Before +import org.junit.Test +import org.luxons.sevenwonders.actions.CreateGameAction +import org.luxons.sevenwonders.actions.JoinGameAction +import org.luxons.sevenwonders.api.toDTO +import org.luxons.sevenwonders.controllers.GameBrowserController.UserAlreadyInGameException +import org.luxons.sevenwonders.repositories.LobbyRepository +import org.luxons.sevenwonders.repositories.PlayerNotFoundException +import org.luxons.sevenwonders.repositories.PlayerRepository +import org.luxons.sevenwonders.test.mockSimpMessagingTemplate +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class GameBrowserControllerTest { + + private lateinit var playerRepository: PlayerRepository + + private lateinit var gameBrowserController: GameBrowserController + + @Before + fun setUp() { + playerRepository = PlayerRepository() + val lobbyRepository = LobbyRepository() + val template = mockSimpMessagingTemplate() + val lobbyController = LobbyController(lobbyRepository, playerRepository, template) + gameBrowserController = GameBrowserController(lobbyController, lobbyRepository, playerRepository, template) + } + + @Test + fun listGames_initiallyEmpty() { + val principal = TestPrincipal("testuser") + val games = gameBrowserController.listGames(principal) + assertTrue(games.isEmpty()) + } + + @Test + fun createGame_success() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val principal = TestPrincipal("testuser") + + val action = CreateGameAction("Test Game") + + val createdLobby = gameBrowserController.createGame(action, principal) + + assertEquals("Test Game", createdLobby.name) + + val games = gameBrowserController.listGames(principal) + assertFalse(games.isEmpty()) + val lobby = games.iterator().next() + assertEquals(lobby, createdLobby) + assertEquals(player.toDTO(principal.name), lobby.players[0]) + } + + @Test + fun createGame_failsForUnknownPlayer() { + val principal = TestPrincipal("unknown") + val action = CreateGameAction("Test Game") + + assertFailsWith<PlayerNotFoundException> { + gameBrowserController.createGame(action, principal) + } + } + + @Test + fun createGame_failsWhenAlreadyInGame() { + playerRepository.createOrUpdate("testuser", "Test User") + val principal = TestPrincipal("testuser") + + val createGameAction1 = CreateGameAction("Test Game 1") + + // auto-enters the game + gameBrowserController.createGame(createGameAction1, principal) + + val createGameAction2 = CreateGameAction("Test Game 2") + + // already in a game + assertFailsWith<UserAlreadyInGameException> { + gameBrowserController.createGame(createGameAction2, principal) + } + } + + @Test + fun joinGame_success() { + val owner = playerRepository.createOrUpdate("testowner", "Test User Owner") + val ownerPrincipal = TestPrincipal("testowner") + val createGameAction = CreateGameAction("Test Game") + + val createdLobby = gameBrowserController.createGame(createGameAction, ownerPrincipal) + assertEquals(owner.toDTO(ownerPrincipal.name), createdLobby.players[0]) + + val joiner = playerRepository.createOrUpdate("testjoiner", "Test User Joiner") + val joinerPrincipal = TestPrincipal("testjoiner") + val joinGameAction = JoinGameAction(createdLobby.id) + + val joinedLobby = gameBrowserController.joinGame(joinGameAction, joinerPrincipal) + + assertEquals(owner.toDTO(joinerPrincipal.name), joinedLobby.players[0]) + assertEquals(joiner.toDTO(joinerPrincipal.name), joinedLobby.players[1]) + } + + @Test + fun joinGame_failsWhenAlreadyInGame() { + playerRepository.createOrUpdate("testowner", "Test User Owner") + val ownerPrincipal = TestPrincipal("testowner") + val createGameAction = CreateGameAction("Test Game") + + val createdLobby = gameBrowserController.createGame(createGameAction, ownerPrincipal) + + playerRepository.createOrUpdate("testjoiner", "Test User Joiner") + val joinerPrincipal = TestPrincipal("testjoiner") + val joinGameAction = JoinGameAction(createdLobby.id) + + // joins the game + gameBrowserController.joinGame(joinGameAction, joinerPrincipal) + // should fail because already in a game + assertFailsWith<UserAlreadyInGameException> { + gameBrowserController.joinGame(joinGameAction, joinerPrincipal) + } + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/HomeControllerTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/HomeControllerTest.kt new file mode 100644 index 00000000..3374a025 --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/HomeControllerTest.kt @@ -0,0 +1,25 @@ +package org.luxons.sevenwonders.controllers + +import org.junit.Test +import org.luxons.sevenwonders.actions.ChooseNameAction +import org.luxons.sevenwonders.repositories.PlayerRepository +import kotlin.test.assertEquals + +class HomeControllerTest { + + @Test + fun chooseName() { + val playerRepository = PlayerRepository() + val homeController = HomeController(playerRepository) + + val action = ChooseNameAction("Test User") + val principal = TestPrincipal("testuser") + + val player = homeController.chooseName(action, principal) + + assertEquals("testuser", player.username) + assertEquals("Test User", player.displayName) + assertEquals(false, player.isGameOwner) + assertEquals(true, player.isUser) + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt new file mode 100644 index 00000000..a140e000 --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt @@ -0,0 +1,217 @@ +package org.luxons.sevenwonders.controllers + +import org.junit.Before +import org.junit.Test +import org.luxons.sevenwonders.actions.ReorderPlayersAction +import org.luxons.sevenwonders.actions.UpdateSettingsAction +import org.luxons.sevenwonders.game.api.CustomizableSettings +import org.luxons.sevenwonders.game.api.WonderSidePickMethod.ALL_A +import org.luxons.sevenwonders.lobby.Lobby +import org.luxons.sevenwonders.lobby.Player +import org.luxons.sevenwonders.lobby.PlayerIsNotOwnerException +import org.luxons.sevenwonders.lobby.PlayerNotInLobbyException +import org.luxons.sevenwonders.lobby.State +import org.luxons.sevenwonders.repositories.LobbyRepository +import org.luxons.sevenwonders.repositories.PlayerNotFoundException +import org.luxons.sevenwonders.repositories.PlayerRepository +import org.luxons.sevenwonders.test.mockSimpMessagingTemplate +import java.util.HashMap +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertSame +import kotlin.test.assertTrue + +class LobbyControllerTest { + + private lateinit var playerRepository: PlayerRepository + + private lateinit var lobbyRepository: LobbyRepository + + private lateinit var lobbyController: LobbyController + + @Before + fun setUp() { + val template = mockSimpMessagingTemplate() + playerRepository = PlayerRepository() + lobbyRepository = LobbyRepository() + lobbyController = LobbyController(lobbyRepository, playerRepository, template) + } + + @Test + fun init_succeeds() { + val owner = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", owner) + + assertTrue(lobby.getPlayers().contains(owner)) + assertSame(lobby, owner.lobby) + assertEquals(owner, lobby.owner) + assertTrue(owner.isInLobby) + assertFalse(owner.isInGame) + } + + @Test + fun leave_failsWhenPlayerDoesNotExist() { + val principal = TestPrincipal("I don't exist") + + assertFailsWith<PlayerNotFoundException> { + lobbyController.leave(principal) + } + } + + @Test + fun leave_failsWhenNotInLobby() { + playerRepository.createOrUpdate("testuser", "Test User") + val principal = TestPrincipal("testuser") + + assertFailsWith<PlayerNotInLobbyException> { + lobbyController.leave(principal) + } + } + + @Test + fun leave_succeedsWhenInALobby_asOwner() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + + val principal = TestPrincipal("testuser") + lobbyController.leave(principal) + + assertFalse(lobbyRepository.list().contains(lobby)) + assertFalse(player.isInLobby) + assertFalse(player.isInGame) + } + + @Test + fun leave_succeedsWhenInALobby_asPeasant() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + val player2 = addPlayer(lobby, "testuser2") + + val principal = TestPrincipal("testuser2") + lobbyController.leave(principal) + + assertFalse(lobby.getPlayers().contains(player2)) + assertFalse(player2.isInLobby) + assertFalse(player2.isInGame) + } + + @Test + fun reorderPlayers_succeedsForOwner() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + + val player2 = addPlayer(lobby, "testuser2") + val player3 = addPlayer(lobby, "testuser3") + val player4 = addPlayer(lobby, "testuser4") + + val players = listOf(player, player2, player3, player4) + assertEquals(players, lobby.getPlayers()) + + val reorderedPlayers = listOf(player3, player, player2, player4) + val playerNames = reorderedPlayers.map { it.username } + val reorderPlayersAction = ReorderPlayersAction(playerNames) + + val principal = TestPrincipal("testuser") + lobbyController.reorderPlayers(reorderPlayersAction, principal) + + assertEquals(reorderedPlayers, lobby.getPlayers()) + } + + @Test + fun reorderPlayers_failsForPeasant() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + + val player2 = addPlayer(lobby, "testuser2") + val player3 = addPlayer(lobby, "testuser3") + + val reorderedPlayers = listOf(player3, player, player2) + val playerNames = reorderedPlayers.map { it.username } + val reorderPlayersAction = ReorderPlayersAction(playerNames) + + val principal = TestPrincipal("testuser2") + + assertFailsWith<PlayerIsNotOwnerException> { + lobbyController.reorderPlayers(reorderPlayersAction, principal) + } + } + + @Test + fun updateSettings_succeedsForOwner() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + + addPlayer(lobby, "testuser2") + addPlayer(lobby, "testuser3") + addPlayer(lobby, "testuser4") + + assertEquals(CustomizableSettings(), lobby.settings) + + val newSettings = CustomizableSettings(12L, 5, ALL_A, 5, 5, 4, 10, 2, HashMap()) + val updateSettingsAction = UpdateSettingsAction(newSettings) + + val principal = TestPrincipal("testuser") + lobbyController.updateSettings(updateSettingsAction, principal) + + assertEquals(newSettings, lobby.settings) + } + + @Test + fun updateSettings_failsForPeasant() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + + addPlayer(lobby, "testuser2") + addPlayer(lobby, "testuser3") + + val updateSettingsAction = UpdateSettingsAction(CustomizableSettings()) + + val principal = TestPrincipal("testuser2") + + assertFailsWith<PlayerIsNotOwnerException> { + lobbyController.updateSettings(updateSettingsAction, principal) + } + } + + @Test + fun startGame_succeedsForOwner() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + + addPlayer(lobby, "testuser2") + addPlayer(lobby, "testuser3") + addPlayer(lobby, "testuser4") + + val principal = TestPrincipal("testuser") + lobbyController.startGame(principal) + + assertSame(State.PLAYING, lobby.state) + } + + @Test + fun startGame_failsForPeasant() { + val player = playerRepository.createOrUpdate("testuser", "Test User") + val lobby = lobbyRepository.create("Test Game", player) + + addPlayer(lobby, "testuser2") + addPlayer(lobby, "testuser3") + + val principal = TestPrincipal("testuser2") + + assertFailsWith<PlayerIsNotOwnerException> { + lobbyController.startGame(principal) + } + } + + private fun addPlayer(lobby: Lobby, username: String): Player { + val player = playerRepository.createOrUpdate(username, username) + lobby.addPlayer(player) + + assertTrue(lobby.getPlayers().contains(player)) + assertSame(lobby, player.lobby) + assertTrue(player.isInLobby) + assertFalse(player.isInGame) + return player + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/TestPrincipal.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/TestPrincipal.kt new file mode 100644 index 00000000..76b0f8fa --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/controllers/TestPrincipal.kt @@ -0,0 +1,8 @@ +package org.luxons.sevenwonders.controllers + +import java.security.Principal + +internal class TestPrincipal(private val name: String) : Principal { + + override fun getName(): String = name +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt new file mode 100644 index 00000000..967a97e2 --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt @@ -0,0 +1,266 @@ +package org.luxons.sevenwonders.lobby + +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Test +import org.junit.experimental.theories.DataPoints +import org.junit.experimental.theories.Theories +import org.junit.experimental.theories.Theory +import org.junit.runner.RunWith +import org.luxons.sevenwonders.game.api.CustomizableSettings +import org.luxons.sevenwonders.game.data.GameDefinition +import org.luxons.sevenwonders.lobby.Lobby.GameAlreadyStartedException +import org.luxons.sevenwonders.lobby.Lobby.PlayerListMismatchException +import org.luxons.sevenwonders.lobby.Lobby.PlayerNameAlreadyUsedException +import org.luxons.sevenwonders.lobby.Lobby.PlayerOverflowException +import org.luxons.sevenwonders.lobby.Lobby.PlayerUnderflowException +import org.luxons.sevenwonders.lobby.Lobby.UnknownPlayerException +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertSame +import kotlin.test.assertTrue + +@RunWith(Theories::class) +class LobbyTest { + + private lateinit var gameOwner: Player + + private lateinit var lobby: Lobby + + @Before + fun setUp() { + gameOwner = Player("gameowner", "Game owner") + lobby = Lobby(0, "Test Game", gameOwner, gameDefinition) + } + + @Test + fun testId() { + val lobby = Lobby(5, "Test Game", gameOwner, gameDefinition) + assertEquals(5, lobby.id) + } + + @Test + fun testName() { + val lobby = Lobby(5, "Test Game", gameOwner, gameDefinition) + assertEquals("Test Game", lobby.name) + } + + @Test + fun testOwner() { + val lobby = Lobby(5, "Test Game", gameOwner, gameDefinition) + assertSame(gameOwner, lobby.getPlayers()[0]) + assertSame(lobby, gameOwner.lobby) + } + + @Test + fun isOwner_falseWhenNull() { + assertFalse(lobby.isOwner(null)) + } + + @Test + fun isOwner_falseWhenEmptyString() { + assertFalse(lobby.isOwner("")) + } + + @Test + fun isOwner_falseWhenGarbageString() { + assertFalse(lobby.isOwner("this is garbage")) + } + + @Test + fun isOwner_trueWhenOwnerUsername() { + assertTrue(lobby.isOwner(gameOwner.username)) + } + + @Test + fun isOwner_falseWhenOtherPlayerName() { + val player = Player("testuser", "Test User") + lobby.addPlayer(player) + assertFalse(lobby.isOwner(player.username)) + } + + @Test + fun addPlayer_success() { + val player = Player("testuser", "Test User") + lobby.addPlayer(player) + assertTrue(lobby.containsUser("testuser")) + assertSame(lobby, player.lobby) + } + + @Test + fun addPlayer_failsOnSameName() { + val player = Player("testuser", "Test User") + val player2 = Player("testuser2", "Test User") + lobby.addPlayer(player) + assertFailsWith<PlayerNameAlreadyUsedException> { + lobby.addPlayer(player2) + } + } + + @Test + fun addPlayer_playerOverflowWhenTooMany() { + assertFailsWith<PlayerOverflowException> { + // the owner + the max number gives an overflow + addPlayers(gameDefinition.maxPlayers) + } + } + + @Test + fun addPlayer_failWhenGameStarted() { + // total with owner is the minimum + addPlayers(gameDefinition.minPlayers - 1) + lobby.startGame() + assertFailsWith<GameAlreadyStartedException> { + lobby.addPlayer(Player("soonerNextTime", "The Late Guy")) + } + } + + private fun addPlayers(nbPlayers: Int) { + repeat(nbPlayers) { + val player = Player("testuser$it", "Test User $it") + lobby.addPlayer(player) + } + } + + @Test + fun removePlayer_failsWhenNotPresent() { + assertFailsWith<UnknownPlayerException> { + lobby.removePlayer("anyname") + } + } + + @Test + fun removePlayer_success() { + val player = Player("testuser", "Test User") + lobby.addPlayer(player) + assertTrue(player.isInLobby) + assertFalse(player.isInGame) + + lobby.removePlayer("testuser") + assertFalse(lobby.containsUser("testuser")) + assertFalse(player.isInLobby) + assertFalse(player.isInGame) + } + + @Test + fun reorderPlayers_success() { + val player1 = Player("testuser1", "Test User 1") + val player2 = Player("testuser2", "Test User 2") + val player3 = Player("testuser3", "Test User 3") + lobby.addPlayer(player1) + lobby.addPlayer(player2) + lobby.addPlayer(player3) + + val reorderedUsernames = listOf("testuser3", "gameowner", "testuser1", "testuser2") + lobby.reorderPlayers(reorderedUsernames) + + assertEquals(reorderedUsernames, lobby.getPlayers().map { it.username }) + } + + @Test + fun reorderPlayers_failsOnUnknownPlayer() { + val player1 = Player("testuser1", "Test User 1") + val player2 = Player("testuser2", "Test User 2") + lobby.addPlayer(player1) + lobby.addPlayer(player2) + + assertFailsWith<PlayerListMismatchException> { + lobby.reorderPlayers(listOf("unknown", "testuser2", "gameowner")) + } + } + + @Test + fun reorderPlayers_failsOnExtraPlayer() { + val player1 = Player("testuser1", "Test User 1") + val player2 = Player("testuser2", "Test User 2") + lobby.addPlayer(player1) + lobby.addPlayer(player2) + + assertFailsWith<PlayerListMismatchException> { + lobby.reorderPlayers(listOf("testuser2", "onemore", "testuser1", "gameowner")) + } + } + + @Test + fun reorderPlayers_failsOnMissingPlayer() { + val player1 = Player("testuser1", "Test User 1") + val player2 = Player("testuser2", "Test User 2") + lobby.addPlayer(player1) + lobby.addPlayer(player2) + + assertFailsWith<PlayerListMismatchException> { + lobby.reorderPlayers(listOf("testuser2", "gameowner")) + } + } + + @Theory + fun startGame_failsBelowMinPlayers(nbPlayers: Int) { + assumeTrue(nbPlayers < gameDefinition.minPlayers) + + // there is already the owner + addPlayers(nbPlayers - 1) + + assertFailsWith<PlayerUnderflowException> { + lobby.startGame() + } + } + + @Theory + fun startGame_succeedsAboveMinPlayers(nbPlayers: Int) { + assumeTrue(nbPlayers >= gameDefinition.minPlayers) + assumeTrue(nbPlayers <= gameDefinition.maxPlayers) + // there is already the owner + addPlayers(nbPlayers - 1) + + assertEquals(nbPlayers, lobby.getPlayers().size) + lobby.getPlayers().forEach { + assertSame(lobby, it.lobby) + assertTrue(it.isInLobby) + assertFalse(it.isInGame) + } + + val game = lobby.startGame() + assertNotNull(game) + lobby.getPlayers().forEachIndexed { index, it -> + assertSame(index, it.index) + assertSame(lobby, it.lobby) + assertSame(game, it.game) + assertTrue(it.isInLobby) + assertTrue(it.isInGame) + } + } + + @Test + fun startGame_switchesState() { + assertEquals(State.LOBBY, lobby.state) + // there is already the owner + addPlayers(gameDefinition.minPlayers - 1) + lobby.startGame() + assertEquals(State.PLAYING, lobby.state) + } + + @Test + fun setSettings() { + val settings = CustomizableSettings() + lobby.settings = settings + assertSame(settings, lobby.settings) + } + + companion object { + + private lateinit var gameDefinition: GameDefinition + + @JvmStatic + @DataPoints + fun nbPlayers(): IntArray = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + + @JvmStatic + @BeforeClass + fun loadDefinition() { + gameDefinition = GameDefinition.load() + } + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/repositories/LobbyRepositoryTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/repositories/LobbyRepositoryTest.kt new file mode 100644 index 00000000..446feee6 --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/repositories/LobbyRepositoryTest.kt @@ -0,0 +1,78 @@ +package org.luxons.sevenwonders.repositories + +import org.junit.Before +import org.junit.Test +import org.luxons.sevenwonders.lobby.Player +import kotlin.test.assertFailsWith +import kotlin.test.assertNotNull +import kotlin.test.assertSame +import kotlin.test.assertTrue +import kotlin.test.fail + +class LobbyRepositoryTest { + + private lateinit var repository: LobbyRepository + + @Before + fun setUp() { + repository = LobbyRepository() + } + + @Test + fun list_initiallyEmpty() { + assertTrue(repository.list().isEmpty()) + } + + @Test + fun list_returnsAllLobbies() { + val owner = Player("owner", "The Owner") + val lobby1 = repository.create("Test Name 1", owner) + val lobby2 = repository.create("Test Name 2", owner) + assertTrue(repository.list().contains(lobby1)) + assertTrue(repository.list().contains(lobby2)) + } + + @Test + fun create_withCorrectOwner() { + val owner = Player("owner", "The Owner") + val lobby = repository.create("Test Name", owner) + assertTrue(lobby.isOwner(owner.username)) + } + + @Test + fun find_failsOnUnknownId() { + assertFailsWith<LobbyNotFoundException> { + repository.find(123) + } + } + + @Test + fun find_returnsTheSameObject() { + val owner = Player("owner", "The Owner") + val lobby1 = repository.create("Test Name 1", owner) + val lobby2 = repository.create("Test Name 2", owner) + assertSame(lobby1, repository.find(lobby1.id)) + assertSame(lobby2, repository.find(lobby2.id)) + } + + @Test + fun remove_failsOnUnknownId() { + assertFailsWith<LobbyNotFoundException> { + repository.remove(123) + } + } + + @Test + fun remove_succeeds() { + val owner = Player("owner", "The Owner") + val lobby1 = repository.create("Test Name 1", owner) + assertNotNull(repository.find(lobby1.id)) + repository.remove(lobby1.id) + try { + repository.find(lobby1.id) + fail() // the call to find() should have failed + } catch (e: LobbyNotFoundException) { + // the lobby has been properly removed + } + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/repositories/PlayerRepositoryTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/repositories/PlayerRepositoryTest.kt new file mode 100644 index 00000000..aeedc54c --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/repositories/PlayerRepositoryTest.kt @@ -0,0 +1,75 @@ +package org.luxons.sevenwonders.repositories + +import org.junit.Before +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertSame +import kotlin.test.assertTrue + +class PlayerRepositoryTest { + + private lateinit var repository: PlayerRepository + + @Before + fun setUp() { + repository = PlayerRepository() + } + + @Test + fun contains_falseIfNoUserAdded() { + assertFalse(repository.contains("anyUsername")) + } + + @Test + fun contains_trueForCreatedPlayer() { + repository.createOrUpdate("player1", "Player 1") + assertTrue(repository.contains("player1")) + } + + @Test + fun createOrUpdate_createsProperly() { + val player1 = repository.createOrUpdate("player1", "Player 1") + assertEquals("player1", player1.username) + assertEquals("Player 1", player1.displayName) + } + + @Test + fun createOrUpdate_updatesDisplayName() { + val player1 = repository.createOrUpdate("player1", "Player 1") + val player1Updated = repository.createOrUpdate("player1", "Much Better Name") + assertSame(player1, player1Updated) + assertEquals("Much Better Name", player1Updated.displayName) + } + + @Test + fun find_failsOnUnknownUsername() { + assertFailsWith<PlayerNotFoundException> { + repository.find("anyUsername") + } + } + + @Test + fun find_returnsTheSameObject() { + val player1 = repository.createOrUpdate("player1", "Player 1") + val player2 = repository.createOrUpdate("player2", "Player 2") + assertSame(player1, repository.find("player1")) + assertSame(player2, repository.find("player2")) + } + + @Test + fun remove_failsOnUnknownUsername() { + assertFailsWith<PlayerNotFoundException> { + repository.remove("anyUsername") + } + } + + @Test + fun remove_succeeds() { + repository.createOrUpdate("player1", "Player 1") + assertTrue(repository.contains("player1")) + repository.remove("player1") + assertFalse(repository.contains("player1")) + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/TestUtils.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/TestUtils.kt new file mode 100644 index 00000000..9f328c5f --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/TestUtils.kt @@ -0,0 +1,10 @@ +package org.luxons.sevenwonders.test + +import org.springframework.messaging.Message +import org.springframework.messaging.MessageChannel +import org.springframework.messaging.simp.SimpMessagingTemplate + +fun mockSimpMessagingTemplate(): SimpMessagingTemplate = SimpMessagingTemplate(object : MessageChannel { + override fun send(message: Message<*>): Boolean = true + override fun send(message: Message<*>, timeout: Long): Boolean = true +}) diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/api/SevenWondersClient.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/api/SevenWondersClient.kt new file mode 100644 index 00000000..ee5827cc --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/api/SevenWondersClient.kt @@ -0,0 +1,38 @@ +package org.luxons.sevenwonders.test.api + +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.KotlinModule +import org.hildan.jackstomp.JackstompClient +import org.luxons.sevenwonders.config.SEVEN_WONDERS_WS_ENDPOINT +import org.luxons.sevenwonders.game.resources.MutableResources +import org.luxons.sevenwonders.game.resources.Resources +import org.springframework.messaging.converter.MappingJackson2MessageConverter +import java.util.concurrent.ExecutionException +import java.util.concurrent.TimeoutException + +class SevenWondersClient { + + private val client: JackstompClient + + init { + val customMappingsModule = SimpleModule("ConcreteResourcesDeserializationModule") + customMappingsModule.addAbstractTypeMapping(Resources::class.java, MutableResources::class.java) + + val mappingJackson2MessageConverter = MappingJackson2MessageConverter() + mappingJackson2MessageConverter.objectMapper.registerModule(customMappingsModule) + mappingJackson2MessageConverter.objectMapper.registerModule(KotlinModule()) + + client = JackstompClient() + client.webSocketClient.messageConverter = mappingJackson2MessageConverter + } + + @Throws(InterruptedException::class, ExecutionException::class, TimeoutException::class) + fun connect(serverUrl: String): SevenWondersSession { + val session = client.syncConnect(serverUrl + SEVEN_WONDERS_WS_ENDPOINT) + return SevenWondersSession(session) + } + + fun stop() { + client.stop() + } +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/api/SevenWondersSession.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/api/SevenWondersSession.kt new file mode 100644 index 00000000..70031a71 --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/test/api/SevenWondersSession.kt @@ -0,0 +1,70 @@ +package org.luxons.sevenwonders.test.api + +import org.hildan.jackstomp.Channel +import org.hildan.jackstomp.JackstompSession +import org.luxons.sevenwonders.actions.ChooseNameAction +import org.luxons.sevenwonders.actions.CreateGameAction +import org.luxons.sevenwonders.actions.JoinGameAction +import org.luxons.sevenwonders.api.LobbyDTO +import org.luxons.sevenwonders.api.PlayerDTO +import org.luxons.sevenwonders.errors.ErrorDTO +import org.luxons.sevenwonders.game.api.PlayerTurnInfo +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +class SevenWondersSession(val jackstompSession: JackstompSession) { + + fun disconnect() { + jackstompSession.disconnect() + } + + fun watchErrors(): Channel<ErrorDTO> = jackstompSession.subscribe("/user/queue/errors", ErrorDTO::class.java) + + @Throws(InterruptedException::class) + fun chooseName(displayName: String): PlayerDTO { + val action = ChooseNameAction(displayName) + return jackstompSession.request(action, PlayerDTO::class.java, "/app/chooseName", "/user/queue/nameChoice") + } + + fun watchGames(): Channel<Array<LobbyDTO>> { + return jackstompSession.subscribe("/topic/games", Array<LobbyDTO>::class.java) + } + + @Throws(InterruptedException::class) + fun createGame(gameName: String): LobbyDTO { + val action = CreateGameAction(gameName) + return jackstompSession.request(action, LobbyDTO::class.java, "/app/lobby/create", "/user/queue/lobby/joined") + } + + @Throws(InterruptedException::class) + fun joinGame(gameId: Long): LobbyDTO { + val action = JoinGameAction(gameId) + val lobby = + jackstompSession.request(action, LobbyDTO::class.java, "/app/lobby/join", "/user/queue/lobby/joined") + assertNotNull(lobby) + assertEquals(gameId, lobby.id) + return lobby + } + + fun watchLobbyUpdates(gameId: Long): Channel<LobbyDTO> = + jackstompSession.subscribe("/topic/lobby/$gameId/updated", LobbyDTO::class.java) + + fun watchLobbyStart(gameId: Long): Channel<LobbyDTO> = + jackstompSession.subscribe("/topic/lobby/$gameId/started", LobbyDTO::class.java) + + @Throws(InterruptedException::class) + fun startGame(gameId: Long) { + val sendDestination = "/app/lobby/startGame" + val receiveDestination = "/topic/lobby/$gameId/started" + val received = jackstompSession.request(null, sendDestination, receiveDestination) + assertTrue(received) + } + + fun sayReady() { + jackstompSession.send("/app/game/sayReady", "") + } + + fun watchTurns(): Channel<PlayerTurnInfo> = + jackstompSession.subscribe("/user/queue/game/turn", PlayerTurnInfo::class.java) +} diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/validation/DestinationAccessValidatorTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/validation/DestinationAccessValidatorTest.kt new file mode 100644 index 00000000..85d03e99 --- /dev/null +++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/validation/DestinationAccessValidatorTest.kt @@ -0,0 +1,147 @@ +package org.luxons.sevenwonders.validation + +import org.junit.Before +import org.junit.Test +import org.luxons.sevenwonders.lobby.Lobby +import org.luxons.sevenwonders.lobby.Player +import org.luxons.sevenwonders.repositories.LobbyNotFoundException +import org.luxons.sevenwonders.repositories.LobbyRepository +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class DestinationAccessValidatorTest { + + private lateinit var lobbyRepository: LobbyRepository + + private lateinit var destinationAccessValidator: DestinationAccessValidator + + @Before + fun setup() { + lobbyRepository = LobbyRepository() + destinationAccessValidator = DestinationAccessValidator(lobbyRepository) + } + + private fun createLobby(gameName: String, ownerUsername: String, vararg otherPlayers: String): Lobby { + val owner = Player(ownerUsername, ownerUsername) + val lobby = lobbyRepository.create(gameName, owner) + for (playerName in otherPlayers) { + val player = Player(playerName, playerName) + lobby.addPlayer(player) + } + return lobby + } + + private fun createGame(gameName: String, ownerUsername: String, vararg otherPlayers: String) { + val lobby = createLobby(gameName, ownerUsername, *otherPlayers) + lobby.startGame() + } + + @Test + fun validate_failsOnNullUser() { + assertFalse(destinationAccessValidator.hasAccess(null, "doesNotMatter")) + } + + @Test + fun validate_successWhenNoReference() { + assertTrue(destinationAccessValidator.hasAccess("", "")) + assertTrue(destinationAccessValidator.hasAccess("", "test")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "test")) + } + + @Test + fun validate_successWhenNoRefFollows() { + assertTrue(destinationAccessValidator.hasAccess("testUser", "/game/")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "/lobby/")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "prefix/game/")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "prefix/lobby/")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "/game//suffix")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "/lobby//suffix")) + } + + @Test + fun validate_successWhenRefIsNotANumber() { + assertTrue(destinationAccessValidator.hasAccess("testUser", "/game/notANumber")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "/lobby/notANumber")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "prefix/game/notANumber")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "prefix/lobby/notANumber")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "/game/notANumber/suffix")) + assertTrue(destinationAccessValidator.hasAccess("testUser", "/lobby/notANumber/suffix")) + } + + @Test + fun validate_failWhenNoLobbyExist() { + assertFailsWith<LobbyNotFoundException> { + destinationAccessValidator.hasAccess("", "/lobby/0") + } + } + + @Test + fun validate_failWhenNoGameExist() { + assertFailsWith<LobbyNotFoundException> { + destinationAccessValidator.hasAccess("", "/game/0") + } + } + + @Test + fun validate_failWhenReferencedLobbyDoesNotExist() { + createLobby("Test Game", "ownerUser1") + createLobby("Test Game 2", "ownerUser2") + assertFailsWith<LobbyNotFoundException> { + destinationAccessValidator.hasAccess("doesNotMatter", "/lobby/3") + } + } + + @Test + fun validate_failWhenReferencedGameDoesNotExist() { + createGame("Test Game 1", "user1", "user2", "user3") + createGame("Test Game 2", "user4", "user5", "user6") + assertFailsWith<LobbyNotFoundException> { + destinationAccessValidator.hasAccess("doesNotMatter", "/game/3") + } + } + + @Test + fun validate_failWhenUserIsNotPartOfReferencedLobby() { + createLobby("Test Game", "ownerUser") + destinationAccessValidator.hasAccess("userNotInLobby", "/lobby/0") + } + + @Test + fun validate_failWhenUserIsNotPartOfReferencedGame() { + createGame("Test Game", "ownerUser", "otherUser1", "otherUser2") + destinationAccessValidator.hasAccess("userNotInGame", "/game/0") + } + + @Test + fun validate_successWhenUserIsOwnerOfReferencedLobby() { + createLobby("Test Game 1", "user1") + assertTrue(destinationAccessValidator.hasAccess("user1", "/lobby/0")) + createLobby("Test Game 2", "user2") + assertTrue(destinationAccessValidator.hasAccess("user2", "/lobby/1")) + } + + @Test + fun validate_successWhenUserIsMemberOfReferencedLobby() { + createLobby("Test Game 1", "user1", "user2") + assertTrue(destinationAccessValidator.hasAccess("user2", "/lobby/0")) + createLobby("Test Game 2", "user3", "user4") + assertTrue(destinationAccessValidator.hasAccess("user4", "/lobby/1")) + } + + @Test + fun validate_successWhenUserIsOwnerOfReferencedGame() { + createGame("Test Game 1", "owner1", "user2", "user3") + assertTrue(destinationAccessValidator.hasAccess("owner1", "/game/0")) + createGame("Test Game 2", "owner4", "user5", "user6") + assertTrue(destinationAccessValidator.hasAccess("owner4", "/game/1")) + } + + @Test + fun validate_successWhenUserIsMemberOfReferencedGame() { + createGame("Test Game 1", "owner1", "user2", "user3") + assertTrue(destinationAccessValidator.hasAccess("user2", "/game/0")) + createGame("Test Game 2", "owner4", "user5", "user6") + assertTrue(destinationAccessValidator.hasAccess("user6", "/game/1")) + } +} |