diff --git a/client/src/test/kotlin/http/SessionApiTest.kt b/client/src/test/kotlin/http/SessionApiTest.kt index 84e641e..32c3301 100644 --- a/client/src/test/kotlin/http/SessionApiTest.kt +++ b/client/src/test/kotlin/http/SessionApiTest.kt @@ -140,6 +140,18 @@ class SessionApiTest : AbstractClientTest() { } } + @Test + fun `should send a finish session request and clear the session id`() { + ClientGlobals.httpClient.sessionId = UUID.randomUUID() + + val httpClient = mockk(relaxed = true) + SessionApi(httpClient).finishSession() + + verify { httpClient.doCall(HttpMethod.POST, Routes.FINISH_SESSION) } + + ClientGlobals.httpClient.sessionId shouldBe null + } + private fun mockHttpClient(response: ApiResponse): HttpClient { val httpClient = mockk(relaxed = true) every { diff --git a/server/src/main/kotlin/routes/session/SessionService.kt b/server/src/main/kotlin/routes/session/SessionService.kt index 85337ec..7118892 100644 --- a/server/src/main/kotlin/routes/session/SessionService.kt +++ b/server/src/main/kotlin/routes/session/SessionService.kt @@ -13,7 +13,6 @@ import java.util.* import `object`.Room import routes.ClientException import store.Store -import util.ColourGenerator import util.OnlineConstants import util.ServerGlobals import utils.Achievement @@ -79,9 +78,6 @@ class SessionService( val usc = uscStore.get(session.ip) usc.destroyNotificationSockets() - // Need to remove them from rooms too - ColourGenerator.freeUpColour(usc.colour) - val rooms: List = ServerGlobals.server.getRooms() rooms.forEach { room -> room.removeFromObservers(usc.name) diff --git a/server/src/main/kotlin/util/ServerGlobals.kt b/server/src/main/kotlin/util/ServerGlobals.kt index fa97935..2925181 100644 --- a/server/src/main/kotlin/util/ServerGlobals.kt +++ b/server/src/main/kotlin/util/ServerGlobals.kt @@ -33,6 +33,6 @@ object ServerGlobals { val server: EntropyServer = EntropyServer() - @JvmField val lobbyService: LobbyService = LobbyService(server, sessionStore, uscStore) - @JvmField val sessionService = SessionService(sessionStore, uscStore) + @JvmField var lobbyService: LobbyService = LobbyService(server, sessionStore, uscStore) + @JvmField var sessionService = SessionService(sessionStore, uscStore) } diff --git a/server/src/test/kotlin/routes/session/SessionControllerTest.kt b/server/src/test/kotlin/routes/session/SessionControllerTest.kt index 11eef3a..4261cda 100644 --- a/server/src/test/kotlin/routes/session/SessionControllerTest.kt +++ b/server/src/test/kotlin/routes/session/SessionControllerTest.kt @@ -14,7 +14,9 @@ import testCore.shouldMatchJson import util.ApplicationTest import util.OnlineConstants import util.ServerGlobals.sessionStore +import util.ServerGlobals.uscStore import util.makeSession +import util.makeUserConnection class SessionControllerTest : ApplicationTest() { @Test @@ -36,6 +38,27 @@ class SessionControllerTest : ApplicationTest() { .trimIndent() } + @Test + fun `Should reject a finish session call without a session`() = testApplication { + val response = client.post(Routes.FINISH_SESSION, ::buildFinishSessionRequest) + response.status shouldBe HttpStatusCode.Unauthorized + } + + @Test + fun `Should be able to finish a session`() = testApplication { + val session = makeSession(achievementCount = 4) + val usc = makeUserConnection(session) + sessionStore.put(session) + uscStore.put(usc) + + val response = + client.post(Routes.FINISH_SESSION) { buildFinishSessionRequest(this, session.id) } + response.status shouldBe HttpStatusCode.NoContent + + sessionStore.count() shouldBe 0 + uscStore.count() shouldBe 0 + } + @Test fun `Should reject an update achievement call without a session`() = testApplication { val response = client.post(Routes.ACHIEVEMENT_COUNT, ::buildAchievementUpdateRequest) @@ -57,6 +80,10 @@ class SessionControllerTest : ApplicationTest() { updatedSession.achievementCount shouldBe 8 } + private fun buildFinishSessionRequest(builder: HttpRequestBuilder, sessionId: UUID? = null) { + sessionId?.let { builder.header(CustomHeader.SESSION_ID, sessionId) } + } + private fun buildAchievementUpdateRequest( builder: HttpRequestBuilder, sessionId: UUID? = null, diff --git a/server/src/test/kotlin/routes/session/SessionServiceTest.kt b/server/src/test/kotlin/routes/session/SessionServiceTest.kt index aa306c1..884c514 100644 --- a/server/src/test/kotlin/routes/session/SessionServiceTest.kt +++ b/server/src/test/kotlin/routes/session/SessionServiceTest.kt @@ -7,6 +7,7 @@ import http.UPDATE_REQUIRED import http.dto.BeginSessionRequest import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder import io.kotest.matchers.shouldBe import io.ktor.http.* @@ -19,6 +20,7 @@ import testCore.AbstractTest import testCore.only import util.OnlineConstants import util.makeSession +import util.makeUserConnection import utils.Achievement class SessionServiceTest : AbstractTest() { @@ -151,6 +153,23 @@ class SessionServiceTest : AbstractTest() { store.get(session.id).achievementCount shouldBe session.achievementCount } + @Test + fun `Should support finishing a session`() { + val sessionA = makeSession(ip = "1.2.3.4") + val uscA = makeUserConnection(sessionA) + + val sessionB = makeSession(ip = "5.6.7.8") + val uscB = makeUserConnection(sessionB) + val (service, sessionStore, uscStore) = makeService() + sessionStore.putAll(sessionA, sessionB) + uscStore.putAll(uscA, uscB) + + service.finishSession(sessionA) + + sessionStore.getAll().shouldContainExactly(sessionB) + uscStore.getAll().shouldContainExactly(uscB) + } + @Test fun `Should support updating achievement count`() { val session = makeSession(achievementCount = 5) diff --git a/server/src/test/kotlin/store/AbstractStoreTest.kt b/server/src/test/kotlin/store/AbstractStoreTest.kt index c2821ee..572e0de 100644 --- a/server/src/test/kotlin/store/AbstractStoreTest.kt +++ b/server/src/test/kotlin/store/AbstractStoreTest.kt @@ -82,4 +82,17 @@ abstract class AbstractStoreTest> { store.find(makeIdA()) shouldBe makeItemA() store.find(makeIdB()) shouldBe null } + + @Test + fun `Should be able to count items`() { + val store = makeStore() + store.count() shouldBe 0 + + store.put(makeItemA()) + store.put(makeItemB()) + store.count() shouldBe 2 + + store.remove(makeIdA()) + store.count() shouldBe 1 + } } diff --git a/server/src/test/kotlin/util/ApplicationTest.kt b/server/src/test/kotlin/util/ApplicationTest.kt index dc0c99f..dc812ed 100644 --- a/server/src/test/kotlin/util/ApplicationTest.kt +++ b/server/src/test/kotlin/util/ApplicationTest.kt @@ -1,15 +1,21 @@ package util import org.junit.jupiter.api.BeforeEach +import routes.lobby.LobbyService +import routes.session.SessionService import store.MemoryUserConnectionStore import store.SessionStore import testCore.AbstractTest +import util.ServerGlobals.sessionStore +import util.ServerGlobals.uscStore /** Clear down stores between tests. Can be replaced with proper DI once legacy code is gone */ abstract class ApplicationTest : AbstractTest() { @BeforeEach fun beforeEach() { - ServerGlobals.sessionStore = SessionStore() - ServerGlobals.uscStore = MemoryUserConnectionStore() + sessionStore = SessionStore() + uscStore = MemoryUserConnectionStore() + ServerGlobals.lobbyService = LobbyService(ServerGlobals.server, sessionStore, uscStore) + ServerGlobals.sessionService = SessionService(sessionStore, uscStore) } } diff --git a/server/src/test/kotlin/util/TestFactory.kt b/server/src/test/kotlin/util/TestFactory.kt index 99d78f7..171f8d1 100644 --- a/server/src/test/kotlin/util/TestFactory.kt +++ b/server/src/test/kotlin/util/TestFactory.kt @@ -1,6 +1,7 @@ package util import auth.Session +import auth.UserConnection import game.GameMode import game.GameSettings import java.util.* @@ -10,9 +11,11 @@ fun makeSession( name: String = "Alyssa", ip: String = "1.2.3.4", achievementCount: Int = 4, - apiVersion: Int = OnlineConstants.API_VERSION + apiVersion: Int = OnlineConstants.API_VERSION, ) = Session(id, name, ip, achievementCount, apiVersion) +fun makeUserConnection(session: Session) = UserConnection(session.ip, session.name) + fun makeGameSettings( mode: GameMode = GameMode.Entropy, jokerQuantity: Int = 0, @@ -21,7 +24,7 @@ fun makeGameSettings( includeStars: Boolean = false, negativeJacks: Boolean = false, cardReveal: Boolean = false, - illegalAllowed: Boolean = true + illegalAllowed: Boolean = true, ) = GameSettings( mode, @@ -31,5 +34,5 @@ fun makeGameSettings( includeStars, negativeJacks, cardReveal, - illegalAllowed + illegalAllowed, )