diff --git a/server/src/main/kotlin/delta/codecharacter/server/pvp_game/PvPGameService.kt b/server/src/main/kotlin/delta/codecharacter/server/pvp_game/PvPGameService.kt index f10a2b5..fa2aeae 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/pvp_game/PvPGameService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/pvp_game/PvPGameService.kt @@ -62,6 +62,7 @@ class PvPGameService( } if(gameStatusUpdateEntity.gameResultPlayer1 == null || gameStatusUpdateEntity.gameResultPlayer2 == null) { val newPvPGameEntity = oldPvPGameEntity.copy(status = gameStatusUpdateEntity.gameStatus) + println("newPvPGameEntity: $newPvPGameEntity") return pvPGameRepository.save(newPvPGameEntity) } @@ -87,7 +88,7 @@ class PvPGameService( status = gameStatus ) - val pvPGame: PvPGameEntity = pvPGameRepository.save(newPvPGameEntity) + val pvPGame = pvPGameRepository.save(newPvPGameEntity) pvPGameLogService.savePvPGameLog(pvPGame.matchId, gameResultPlayer1.log, gameResultPlayer2.log) return pvPGame } diff --git a/server/src/main/kotlin/delta/codecharacter/server/pvp_game/pvp_game_log/PvPGameLogService.kt b/server/src/main/kotlin/delta/codecharacter/server/pvp_game/pvp_game_log/PvPGameLogService.kt index f0f395f..4601a0a 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/pvp_game/pvp_game_log/PvPGameLogService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/pvp_game/pvp_game_log/PvPGameLogService.kt @@ -1,6 +1,7 @@ package delta.codecharacter.server.pvp_game.pvp_game_log import delta.codecharacter.server.match.MatchRepository +import delta.codecharacter.server.match.PvPMatchRepository import delta.codecharacter.server.user.public_user.PublicUserEntity import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.annotation.Id @@ -10,12 +11,17 @@ import java.util.UUID @Service class PvPGameLogService( @Autowired private val pvPGameLogRepository: PvPGameLogRepository, - @Autowired private val matchRepository: MatchRepository + @Autowired private val pvPMatchRepository: PvPMatchRepository, ) { fun getPlayerLog(gameId: UUID, userId: UUID): String { + val match = pvPMatchRepository.findById(gameId) + + if (!match.isPresent) { + return "" + } + val pvPGameLog = pvPGameLogRepository.findById(gameId) - val match = matchRepository.findById(gameId) val player1 : PublicUserEntity = match.get().player1 val player2 : PublicUserEntity = match.get().player2 diff --git a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt index cb1a426..f8ce282 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt @@ -33,6 +33,19 @@ class TestAttributes { loginType = LoginType.PASSWORD, isProfileComplete = true, ) + + val opponent = + UserEntity( + id = UUID.randomUUID(), + password = "password", + email = "opponent@test.com", + isEnabled = true, + isAccountNonExpired = true, + isAccountNonLocked = true, + loginType = LoginType.PASSWORD, + isProfileComplete = true, + ) + val dailyChallengeCode = DailyChallengeEntity( id = UUID.randomUUID(), @@ -63,6 +76,24 @@ class TestAttributes { dailyChallengeHistory = hashMapOf(0 to DailyChallengeHistory(0.0, dailyChallengeCode)), tutorialLevel = 1 ) + + val publicOpponent = + PublicUserEntity( + userId = opponent.id, + username = "TestOpponentUser", + name = "Test Opponent User", + country = "Test Country", + college = "Test College", + avatarId = 1, + rating = 1000.0, + wins = 4, + losses = 2, + ties = 1, + tier = TierTypeDto.TIER_PRACTICE, + score = 0.0, + dailyChallengeHistory = hashMapOf(0 to DailyChallengeHistory(0.0, dailyChallengeCode)), + tutorialLevel = 1 + ) } } diff --git a/server/src/test/kotlin/delta/codecharacter/server/pvp_game/PvPGameControllerIntegrationTest.kt b/server/src/test/kotlin/delta/codecharacter/server/pvp_game/PvPGameControllerIntegrationTest.kt new file mode 100644 index 0000000..c78b8f6 --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/pvp_game/PvPGameControllerIntegrationTest.kt @@ -0,0 +1,121 @@ +package delta.codecharacter.server.pvp_game + +import com.fasterxml.jackson.databind.ObjectMapper +import delta.codecharacter.server.TestAttributes +import delta.codecharacter.server.WithMockCustomUser +import delta.codecharacter.server.match.MatchModeEnum +import delta.codecharacter.server.match.MatchVerdictEnum +import delta.codecharacter.server.match.PvPMatchEntity +import delta.codecharacter.server.pvp_game.pvp_game_log.PvPGameLogEntity +import delta.codecharacter.server.user.UserEntity +import delta.codecharacter.server.user.public_user.PublicUserEntity +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +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.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.dropCollection +import org.springframework.http.MediaType +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import java.time.Instant +import java.util.UUID + +@AutoConfigureMockMvc +@SpringBootTest +internal class PvPGameControllerIntegrationTest(@Autowired val mockMvc: MockMvc) { + @Autowired private lateinit var mongoTemplate: MongoTemplate + + @Autowired private lateinit var jackson2ObjectMapperBuilder: Jackson2ObjectMapperBuilder + private lateinit var mapper: ObjectMapper + + @BeforeEach + fun setUp() { + mapper = jackson2ObjectMapperBuilder.build() + mongoTemplate.save(TestAttributes.user) + mongoTemplate.save(TestAttributes.opponent) + mongoTemplate.save(TestAttributes.publicUser) + mongoTemplate.save(TestAttributes.publicOpponent) + + val context = SecurityContextHolder.createEmptyContext() + val auth: Authentication = + UsernamePasswordAuthenticationToken( + TestAttributes.user, TestAttributes.user.password, TestAttributes.user.authorities + ) + context.authentication = auth + SecurityContextHolder.setContext(context) + } + + @Test + @WithMockCustomUser + fun `should get pvp game log`() { + val pvPGameEntity = + PvPGameEntity( + matchId = UUID.randomUUID(), + destructionPlayer1 = 100.0, + destructionPlayer2 = 100.0, + coinsUsedPlayer1 = 100, + coinsUsedPlayer2 = 100, + status = PvPGameStatusEnum.EXECUTED, + ) + mongoTemplate.save(pvPGameEntity) + + val pvPMatchEntity = + PvPMatchEntity( + id = pvPGameEntity.matchId, + player1 = TestAttributes.publicUser, + player2 = TestAttributes.publicOpponent, + game = pvPGameEntity, + mode = MatchModeEnum.PVP, + verdict = MatchVerdictEnum.PLAYER1, + createdAt = Instant.now(), + totalPoints = 100, + ) + mongoTemplate.save(pvPMatchEntity) + + val pvPGameLogEntity = PvPGameLogEntity(gameId = pvPGameEntity.matchId, player1Log = "game log player 1", player2Log = "game log player 2") + mongoTemplate.save(pvPGameLogEntity) + + mockMvc + .get("/pvpgames/${pvPGameEntity.matchId}/logs") { + contentType = MediaType.APPLICATION_JSON + } + .andExpect { + status { isOk() } + content { contentType(MediaType.APPLICATION_JSON) } + content { string(pvPGameLogEntity.player1Log) } + } + } + + @Test + @WithMockCustomUser + fun `should return empty string when pvp game or match not found`() { + val randomUUID = UUID.randomUUID() + + mockMvc.get("/pvpgames/${randomUUID}/logs") { contentType = MediaType.APPLICATION_JSON }.andExpect { + status { isOk() } + content { contentType(MediaType.APPLICATION_JSON) } + content { string("") } + } + } + + @AfterEach + fun tearDown() { + mongoTemplate.dropCollection() + mongoTemplate.dropCollection() + mongoTemplate.dropCollection() + mongoTemplate.dropCollection() + mongoTemplate.dropCollection() + + SecurityContextHolder.clearContext() + } +} diff --git a/server/src/test/kotlin/delta/codecharacter/server/pvp_game/PvPGameServiceTest.kt b/server/src/test/kotlin/delta/codecharacter/server/pvp_game/PvPGameServiceTest.kt new file mode 100644 index 0000000..2de6e8b --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/pvp_game/PvPGameServiceTest.kt @@ -0,0 +1,171 @@ +package delta.codecharacter.server.pvp_game + +import com.fasterxml.jackson.databind.ObjectMapper +import delta.codecharacter.server.code.LanguageEnum +import delta.codecharacter.server.config.GameConfiguration +import delta.codecharacter.server.exception.CustomException +import delta.codecharacter.server.params.GameCode +import delta.codecharacter.server.params.GameParameters +import delta.codecharacter.server.pvp_game.pvp_game_log.PvPGameLogService +import delta.codecharacter.server.pvp_game.queue.entities.PvPGameRequestEntity +import delta.codecharacter.server.pvp_game.queue.entities.PvPGameResultEntity +import delta.codecharacter.server.pvp_game.queue.entities.PvPGameStatusUpdateEntity +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.amqp.rabbit.core.RabbitTemplate +import java.util.UUID +import java.util.Optional +import io.mockk.confirmVerified +import io.mockk.every +import io.mockk.verify +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertThrows +import org.springframework.http.HttpStatus + +internal class PvPGameServiceTest { + private lateinit var pvPGameRepository: PvPGameRepository + private lateinit var pvPGameService: PvPGameService + private lateinit var pvPGameLogService: PvPGameLogService + private lateinit var rabbitTemplate: RabbitTemplate + private lateinit var mapper: ObjectMapper + private lateinit var gameParameters: GameParameters + + + @BeforeEach + fun setUp() { + pvPGameRepository = mockk(relaxed = true) + pvPGameLogService = mockk(relaxed = true) + rabbitTemplate = mockk(relaxed = true) + mapper = ObjectMapper() + val gameConfiguration = GameConfiguration() + gameParameters = gameConfiguration.gameParameters() + + pvPGameService = PvPGameService(pvPGameRepository, pvPGameLogService, rabbitTemplate, gameParameters) + } + + @Test + fun `should return pvp game by id`() { + val pvPGameEntity = mockk() + val gameId = UUID.randomUUID() // gameId and matchId are the same for PvP Game + + every { pvPGameRepository.findById(any()) } returns Optional.of(pvPGameEntity) + + val result = pvPGameService.getPvPGame(gameId) + assertEquals(pvPGameEntity, result) + + verify { pvPGameRepository.findById(gameId) } + confirmVerified(pvPGameRepository) + } + + @Test + @Throws(CustomException::class) + fun `should throw exception if pvp game not found`() { + val gameId = UUID.randomUUID() + + every { pvPGameRepository.findById(any()) } returns Optional.empty() + + val exception = assertThrows(CustomException::class.java) { + pvPGameService.getPvPGame(gameId) + } + + assertEquals(exception.status, HttpStatus.NOT_FOUND) + + verify { pvPGameRepository.findById(gameId) } + confirmVerified(pvPGameRepository) + } + + @Test + fun `should create pvp game request`() { + val pvPGame = mockk() + val matchId = UUID.randomUUID() + + val expectedPvPGameRequest = + PvPGameRequestEntity( + gameId = matchId, + player1 = GameCode("player1 code", LanguageEnum.CPP), + player2 = GameCode("player2 code", LanguageEnum.JAVA), + parameters = gameParameters, + ) + + every {pvPGame.matchId} returns matchId + every { + rabbitTemplate.convertAndSend( + "gamePvPRequestQueue", + mapper.writeValueAsString(expectedPvPGameRequest) + ) + } returns Unit + + pvPGameService.sendPvPGameRequest(pvPGame, expectedPvPGameRequest.player1, expectedPvPGameRequest.player2) + + verify { + rabbitTemplate.convertAndSend( + "gamePvPRequestQueue", + mapper.writeValueAsString(expectedPvPGameRequest) + ) + } + confirmVerified(rabbitTemplate) + } + + @Test + fun `should receive pvp game status update with result`() { + val pvPGame = + PvPGameEntity( + matchId = UUID.randomUUID(), + destructionPlayer1 = 100.0, + destructionPlayer2 = 100.0, + coinsUsedPlayer1 = 100, + coinsUsedPlayer2 = 100, + status = PvPGameStatusEnum.IDLE, + ) + val pvPGameStatusUpdate = + PvPGameStatusUpdateEntity( + gameId = pvPGame.matchId, + gameStatus = PvPGameStatusEnum.EXECUTED, + gameResultPlayer1 = + PvPGameResultEntity( + coinsUsed = 0, + destructionPercentage = 0.0, + hasErrors = false, + log = "player1 log" + ), + gameResultPlayer2 = + PvPGameResultEntity( + coinsUsed = 0, + destructionPercentage = 0.0, + hasErrors = false, + log = "player2 log" + ), + ) + + val updatedPvPGameEntity = + PvPGameEntity( + matchId = pvPGame.matchId, + destructionPlayer1 = pvPGameStatusUpdate.gameResultPlayer1!!.destructionPercentage, + destructionPlayer2 = pvPGameStatusUpdate.gameResultPlayer2!!.destructionPercentage, + coinsUsedPlayer1 = pvPGameStatusUpdate.gameResultPlayer1!!.coinsUsed, + coinsUsedPlayer2 = pvPGameStatusUpdate.gameResultPlayer2!!.coinsUsed, + status = pvPGameStatusUpdate.gameStatus, + ) + + every { pvPGameRepository.findById(pvPGame.matchId) } returns Optional.of(pvPGame) + every { pvPGameRepository.save(updatedPvPGameEntity) } returns updatedPvPGameEntity + + pvPGameService.updateGameStatus(mapper.writeValueAsString(pvPGameStatusUpdate)) + + verify { pvPGameRepository.findById(pvPGame.matchId) } + verify { + pvPGameRepository.save( + PvPGameEntity ( + matchId = pvPGame.matchId, + destructionPlayer1 = pvPGameStatusUpdate.gameResultPlayer1!!.destructionPercentage, + destructionPlayer2 = pvPGameStatusUpdate.gameResultPlayer2!!.destructionPercentage, + coinsUsedPlayer1 = pvPGameStatusUpdate.gameResultPlayer1!!.coinsUsed, + coinsUsedPlayer2 = pvPGameStatusUpdate.gameResultPlayer2!!.coinsUsed, + status = pvPGameStatusUpdate.gameStatus, + ) + ) + } + confirmVerified(pvPGameRepository) + } +} diff --git a/server/src/test/kotlin/delta/codecharacter/server/pvp_game/pvp_game_log/PvPGameLogServiceTest.kt b/server/src/test/kotlin/delta/codecharacter/server/pvp_game/pvp_game_log/PvPGameLogServiceTest.kt new file mode 100644 index 0000000..e4849f3 --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/pvp_game/pvp_game_log/PvPGameLogServiceTest.kt @@ -0,0 +1,71 @@ +package delta.codecharacter.server.pvp_game.pvp_game_log + +import delta.codecharacter.server.TestAttributes +import delta.codecharacter.server.match.PvPMatchEntity +import delta.codecharacter.server.match.PvPMatchRepository +import io.mockk.confirmVerified +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import java.util.Optional +import java.util.UUID + +internal class PvPGameLogServiceTest { + private lateinit var pvPGameLogRepository: PvPGameLogRepository + private lateinit var pvPMatchRepository: PvPMatchRepository + private lateinit var pvPGameLogService: PvPGameLogService + private lateinit var pvPMatchEntity: PvPMatchEntity + + @BeforeEach + fun setUp() { + pvPGameLogRepository = mockk() + pvPMatchRepository = mockk() + pvPMatchEntity = mockk() + + pvPGameLogService = PvPGameLogService(pvPGameLogRepository, pvPMatchRepository) + } + + @Test + fun `should return pvp game log`() { + val gameId = UUID.randomUUID() + val player1Id = UUID.randomUUID() + val player2Id = UUID.randomUUID() + + val player1 = TestAttributes.publicUser.copy(userId = player1Id, username = "player1") + val player2 = TestAttributes.publicUser.copy(userId = player2Id, username = "player2") + + val pvpMatchEntity = mockk() + every { pvpMatchEntity.player1 } returns player1 + every { pvpMatchEntity.player2 } returns player2 + + val pvPGameLogEntity = mockk() + val expectedPvPGameLogPlayer1 = "pvp game log player 1" + val expectedPvPGameLogPlayer2 = "pvp game log player 2" + + every { pvPGameLogRepository.findById(gameId) } returns Optional.of(pvPGameLogEntity) + every { pvPMatchRepository.findById(gameId) } returns Optional.of(pvpMatchEntity) + every { pvPGameLogEntity.player1Log } returns expectedPvPGameLogPlayer1 + every { pvPGameLogEntity.player2Log } returns expectedPvPGameLogPlayer2 + + + val pvPGameLogPlayer1 = pvPGameLogService.getPlayerLog(gameId, player1Id) + val pvPGameLogPlayer2 = pvPGameLogService.getPlayerLog(gameId, player2Id) + + assertEquals(expectedPvPGameLogPlayer1, pvPGameLogPlayer1) + assertEquals(expectedPvPGameLogPlayer2, pvPGameLogPlayer2) + + verify { pvpMatchEntity.player1 } + verify { pvpMatchEntity.player2 } + + verify { pvPGameLogRepository.findById(gameId) } + verify { pvPMatchRepository.findById(gameId) } + verify { pvPGameLogEntity.player1Log } + verify { pvPGameLogEntity.player2Log } + + confirmVerified(pvPGameLogRepository) + } + +}