diff --git a/server/src/main/kotlin/delta/codecharacter/server/leaderboard/LeaderBoardEnum.kt b/server/src/main/kotlin/delta/codecharacter/server/leaderboard/LeaderBoardEnum.kt deleted file mode 100644 index 439270e7..00000000 --- a/server/src/main/kotlin/delta/codecharacter/server/leaderboard/LeaderBoardEnum.kt +++ /dev/null @@ -1,9 +0,0 @@ -package delta.codecharacter.server.leaderboard - -enum class LeaderBoardEnum { - TIER1, - TIER2, - TIER3, - TIER4, - TIER_PRACTICE -} diff --git a/server/src/main/kotlin/delta/codecharacter/server/match/MatchService.kt b/server/src/main/kotlin/delta/codecharacter/server/match/MatchService.kt index 0f06529c..7a2949ba 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/match/MatchService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/match/MatchService.kt @@ -115,7 +115,11 @@ class MatchService( if (userId == opponentId) { throw CustomException(HttpStatus.BAD_REQUEST, "You cannot play against yourself") } - + if (publicOpponent.tier == TierTypeDto.TIER1) { + throw CustomException( + HttpStatus.BAD_REQUEST, "Opponent cannot be a tier 1 player in manual match" + ) + } val (userLanguage, userCode) = lockedCodeService.getLockedCode(userId) val userMap = lockedMapService.getLockedMap(userId) @@ -328,20 +332,21 @@ class MatchService( val finishedMatch = match.copy(verdict = verdict) val (newUserRating, newOpponentRating) = ratingHistoryService.updateRating(match.player1.userId, match.player2.userId, verdict) + if (!(match.mode == MatchModeEnum.MANUAL && (match.player1.tier == TierTypeDto.TIER1))) { - publicUserService.updatePublicRating( - userId = match.player1.userId, - isInitiator = true, - verdict = verdict, - newRating = newUserRating - ) - publicUserService.updatePublicRating( - userId = match.player2.userId, - isInitiator = false, - verdict = verdict, - newRating = newOpponentRating - ) - + publicUserService.updatePublicRating( + userId = match.player1.userId, + isInitiator = true, + verdict = verdict, + newRating = newUserRating + ) + publicUserService.updatePublicRating( + userId = match.player2.userId, + isInitiator = false, + verdict = verdict, + newRating = newOpponentRating + ) + } if (match.mode == MatchModeEnum.MANUAL) { notificationService.sendNotification( match.player1.userId, diff --git a/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt b/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt index 9a5a7fb0..8958209e 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt @@ -1,7 +1,25 @@ package delta.codecharacter.server.schedulers import delta.codecharacter.server.user.public_user.PublicUserService +import org.slf4j.Logger +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired +import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service -@Service class SchedulingService(@Autowired private val publicUserService: PublicUserService) +@Service +class SchedulingService(@Autowired private val publicUserService: PublicUserService) { + private val logger: Logger = LoggerFactory.getLogger(SchedulingService::class.java) + + @Scheduled(cron = "\${environment.registration-time}", zone = "GMT") + fun updateTempLeaderboard() { + logger.info("Practice phase ended!!") + publicUserService.resetRatingsAfterPracticePhase() + publicUserService.updateLeaderboardAfterPracticePhase() + } + @Scheduled(cron = "\${environment.update-time}", zone = "GMT") + fun promoteAndDemoteUserTiers() { + logger.info("LeaderBoard Tier Promotion and Demotion started") + publicUserService.promoteTiers() + } +} diff --git a/server/src/main/kotlin/delta/codecharacter/server/user/UserService.kt b/server/src/main/kotlin/delta/codecharacter/server/user/UserService.kt index 0228c3b8..7d01ed1f 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/user/UserService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/user/UserService.kt @@ -179,8 +179,11 @@ class UserService( .POST(HttpRequest.BodyPublishers.noBody()) .build() val response = client.send(request, HttpResponse.BodyHandlers.ofString()) - val json = JsonObject(response.body()) - return json.toBsonDocument().getBoolean("success").value + val json = JsonObject(response.body()).toBsonDocument() + return ( + json.getBoolean("success").value && + (json.getDouble("score").value.compareTo(0.5) >= 0) + ) } catch (e: Exception) { e.printStackTrace() return false diff --git a/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserEntity.kt b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserEntity.kt index 2f82c10f..32413839 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserEntity.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserEntity.kt @@ -1,6 +1,6 @@ package delta.codecharacter.server.user.public_user -import delta.codecharacter.server.leaderboard.LeaderBoardEnum +import delta.codecharacter.dtos.TierTypeDto import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.index.Indexed import org.springframework.data.mongodb.core.mapping.Document @@ -14,7 +14,7 @@ data class PublicUserEntity( val country: String, val college: String, val avatarId: Int, - val tier: LeaderBoardEnum, + val tier: TierTypeDto, val tutorialLevel: Int, val rating: Double, val wins: Int, diff --git a/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserRepository.kt b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserRepository.kt index d09d43d4..09883522 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserRepository.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserRepository.kt @@ -1,9 +1,13 @@ package delta.codecharacter.server.user.public_user +import delta.codecharacter.dtos.TierTypeDto +import org.springframework.data.domain.PageRequest import org.springframework.data.mongodb.repository.MongoRepository import java.util.Optional import java.util.UUID interface PublicUserRepository : MongoRepository { fun findByUsername(username: String): Optional + + fun findAllByTier(tier: TierTypeDto?, pageRequest: PageRequest): List } diff --git a/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserService.kt b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserService.kt index 4640a2eb..189960bf 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserService.kt @@ -10,8 +10,9 @@ import delta.codecharacter.dtos.UpdateCurrentUserProfileDto import delta.codecharacter.dtos.UserStatsDto import delta.codecharacter.server.daily_challenge.DailyChallengeEntity import delta.codecharacter.server.exception.CustomException -import delta.codecharacter.server.leaderboard.LeaderBoardEnum import delta.codecharacter.server.match.MatchVerdictEnum +import org.slf4j.Logger +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.data.domain.PageRequest @@ -25,6 +26,10 @@ import java.util.UUID class PublicUserService(@Autowired private val publicUserRepository: PublicUserRepository) { @Value("\${environment.no-of-tutorial-level}") private lateinit var totalTutorialLevels: Number + @Value("\${environment.tier-1-players}") private var tier1Players: Number = 1 + @Value("\${environment.top-players}") private var topPlayer: Number = 1 + private val logger: Logger = LoggerFactory.getLogger(PublicUserService::class.java) + fun create( userId: UUID, username: String, @@ -46,16 +51,76 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR losses = 0, ties = 0, score = 0.0, - tier = LeaderBoardEnum.TIER_PRACTICE, + tier = TierTypeDto.TIER_PRACTICE, tutorialLevel = 1, dailyChallengeHistory = HashMap() ) publicUserRepository.save(publicUser) } + fun updateLeaderboardAfterPracticePhase() { + val publicUsers = publicUserRepository.findAll() + publicUsers.forEachIndexed { index, user -> + if (index < tier1Players.toInt()) { + publicUserRepository.save(user.copy(tier = TierTypeDto.TIER1)) + } else { + publicUserRepository.save(user.copy(tier = TierTypeDto.TIER2)) + } + } + logger.info("Leaderboard tier set during the start of game phase") + } + + fun resetRatingsAfterPracticePhase() { + logger.info("Reset ratings after practice phase starts") + val users = publicUserRepository.findAll() + users.forEach { user -> + publicUserRepository.save(user.copy(rating = 1500.0, wins = 0, ties = 0, losses = 0)) + } + logger.info("Reset ratings after practice phase has ended") + } + + fun promoteTiers() { + val topPlayersInTier2 = + publicUserRepository.findAllByTier( + TierTypeDto.TIER2, + PageRequest.of(0, topPlayer.toInt(), Sort.by(Sort.Order.desc("rating"))) + ) + val bottomPlayersInTier1 = + publicUserRepository.findAllByTier( + TierTypeDto.TIER1, + PageRequest.of(0, topPlayer.toInt(), Sort.by(Sort.Order.asc("rating"))) + ) + topPlayersInTier2.forEach { users -> + val updatedToTier1User = publicUserRepository.save(users.copy(tier = TierTypeDto.TIER1)) + if (updatedToTier1User.tier == TierTypeDto.TIER1) { + logger.info("UserName ${updatedToTier1User.username} got promoted to TIER1") + } else { + logger.error( + "Error occurred while updating ${updatedToTier1User.username} (UserName) to TIER1" + ) + } + } + bottomPlayersInTier1.forEach { users -> + val updateToTier2User = publicUserRepository.save(users.copy(tier = TierTypeDto.TIER2)) + if (updateToTier2User.tier == TierTypeDto.TIER2) { + logger.info("UserName ${updateToTier2User.username} got demoted to TIER2") + } else { + logger.error( + "Error occurred while updating ${updateToTier2User.username} (UserName) to TIER2" + ) + } + } + } + fun getLeaderboard(page: Int?, size: Int?, tier: TierTypeDto?): List { - val pageRequest = PageRequest.of(page ?: 0, size ?: 10, Sort.by(Sort.Direction.DESC, "rating")) - return publicUserRepository.findAll(pageRequest).content.map { + val pageRequest = PageRequest.of(page ?: 0, size ?: 10, Sort.by(Sort.Order.desc("rating"))) + val publicUsers = + if (tier == null) { + publicUserRepository.findAll(pageRequest).content + } else { + publicUserRepository.findAllByTier(tier, pageRequest) + } + return publicUsers.map { LeaderboardEntryDto( user = PublicUserDto( @@ -72,7 +137,7 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR wins = it.wins, losses = it.losses, ties = it.ties - ) + ), ) } } diff --git a/server/src/main/resources/application.docker.example.yml b/server/src/main/resources/application.docker.example.yml index 2cf6df8a..195336d6 100644 --- a/server/src/main/resources/application.docker.example.yml +++ b/server/src/main/resources/application.docker.example.yml @@ -30,6 +30,11 @@ environment: event-start-date: YYYY-MM-DDTHH:MM:SSZ reCaptcha-key: your-recaptcha-key no-of-tutorial-level: 0 + registration-time: "* * * * * *" + game-start-time: "* * * * * *" + tier-1-players: 20 + top-players: 5 + update-time: "*/20 * * * * *" server: compression: diff --git a/server/src/main/resources/application.example.yml b/server/src/main/resources/application.example.yml index 76840f16..0191fc02 100644 --- a/server/src/main/resources/application.example.yml +++ b/server/src/main/resources/application.example.yml @@ -28,6 +28,11 @@ environment: event-start-date: YYYY-MM-DDTHH:MM:SSZ reCaptcha-key: your-recaptcha-key no-of-tutorial-level: 0 + registration-time: "* * * * * *" + game-start-time: "* * * * * *" + tier-1-players: 20 + top-players: 5 + update-time: "*/20 * * * * *" server: compression: diff --git a/server/src/main/resources/player_code b/server/src/main/resources/player_code index e0f86331..16fbce4e 160000 --- a/server/src/main/resources/player_code +++ b/server/src/main/resources/player_code @@ -1 +1 @@ -Subproject commit e0f863311c745db79ec59fdd4fdd5005d8914964 +Subproject commit 16fbce4e8d3df4ba3dedb1c4622651184ac6adb7 diff --git a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt index 7f958d91..cb1a4261 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt @@ -2,8 +2,8 @@ package delta.codecharacter.server import delta.codecharacter.dtos.ChallengeTypeDto import delta.codecharacter.dtos.DailyChallengeObjectDto +import delta.codecharacter.dtos.TierTypeDto import delta.codecharacter.server.daily_challenge.DailyChallengeEntity -import delta.codecharacter.server.leaderboard.LeaderBoardEnum import delta.codecharacter.server.user.LoginType import delta.codecharacter.server.user.UserEntity import delta.codecharacter.server.user.public_user.DailyChallengeHistory @@ -58,7 +58,7 @@ class TestAttributes { wins = 4, losses = 2, ties = 1, - tier = LeaderBoardEnum.TIER_PRACTICE, + 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/leaderboard/LeaderboardControllerIntegrationTest.kt b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt new file mode 100644 index 00000000..331328c1 --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt @@ -0,0 +1,125 @@ +package delta.codecharacter.server.leaderboard + +import com.fasterxml.jackson.databind.ObjectMapper +import delta.codecharacter.dtos.LeaderboardEntryDto +import delta.codecharacter.dtos.PublicUserDto +import delta.codecharacter.dtos.TierTypeDto +import delta.codecharacter.dtos.UserStatsDto +import delta.codecharacter.server.TestAttributes +import delta.codecharacter.server.WithMockCustomUser +import delta.codecharacter.server.user.public_user.PublicUserEntity +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.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import java.math.BigDecimal + +@AutoConfigureMockMvc +@SpringBootTest +internal class LeaderboardControllerIntegrationTest(@Autowired val mockMvc: MockMvc) { + + @Autowired private lateinit var jackson2ObjectMapperBuilder: Jackson2ObjectMapperBuilder + private lateinit var mapper: ObjectMapper + + @Autowired private lateinit var mongoTemplate: MongoTemplate + + @BeforeEach + fun setUp() { + mapper = jackson2ObjectMapperBuilder.build() + mongoTemplate.save(TestAttributes.publicUser) + } + + @Test + @WithMockCustomUser + fun `should get leaderboard when tier type is either TIER_PRACTICE , TIER1 and TIER2`() { + val testUser = TestAttributes.publicUser.copy(tier = TierTypeDto.TIER1) + mongoTemplate.save(testUser) + val expectedDto = + listOf( + LeaderboardEntryDto( + user = + PublicUserDto( + username = testUser.username, + name = testUser.name, + tier = TierTypeDto.valueOf(testUser.tier.name), + country = testUser.country, + college = testUser.college, + avatarId = testUser.avatarId, + ), + stats = + UserStatsDto( + rating = BigDecimal(testUser.rating), + wins = testUser.wins, + losses = testUser.losses, + ties = testUser.ties + ), + ) + ) + mockMvc + .get("/leaderboard?page=0&size=2&tier=TIER1") { contentType = MediaType.APPLICATION_JSON } + .andExpect { + status { is2xxSuccessful() } + content { contentType(MediaType.APPLICATION_JSON) } + content { json(mapper.writeValueAsString(expectedDto)) } + } + } + + @Test + @WithMockCustomUser + fun `should get empty array for invalid tier type when leaderboard contains tier of different type`() { + val testUser = TestAttributes.publicUser.copy(tier = TierTypeDto.TIER1) + mongoTemplate.save(testUser) + val expectedDto = listOf() + mockMvc + .get("/leaderboard?page=0&size=2&tier=TIER2") { contentType = MediaType.APPLICATION_JSON } + .andExpect { + status { is2xxSuccessful() } + content { contentType(MediaType.APPLICATION_JSON) } + content { json(mapper.writeValueAsString(expectedDto)) } + } + } + + @Test + @WithMockCustomUser + fun `should return all entries when tier not found`() { + val testUser = TestAttributes.publicUser + val expectedDto = + listOf( + LeaderboardEntryDto( + user = + PublicUserDto( + username = testUser.username, + name = testUser.name, + tier = TierTypeDto.valueOf(testUser.tier.name), + country = testUser.country, + college = testUser.college, + avatarId = testUser.avatarId, + ), + stats = + UserStatsDto( + rating = BigDecimal(testUser.rating), + wins = testUser.wins, + losses = testUser.losses, + ties = testUser.ties + ), + ) + ) + mockMvc.get("/leaderboard") { contentType = MediaType.APPLICATION_JSON }.andExpect { + status { is2xxSuccessful() } + content { contentType(MediaType.APPLICATION_JSON) } + content { json(mapper.writeValueAsString(expectedDto)) } + } + } + @AfterEach + fun tearDown() { + mongoTemplate.dropCollection() + } +} diff --git a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardTest.kt b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardTest.kt new file mode 100644 index 00000000..a81daaae --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardTest.kt @@ -0,0 +1,139 @@ +package delta.codecharacter.server.leaderboard + +import delta.codecharacter.dtos.TierTypeDto +import delta.codecharacter.server.TestAttributes +import delta.codecharacter.server.user.public_user.DailyChallengeHistory +import delta.codecharacter.server.user.public_user.PublicUserEntity +import delta.codecharacter.server.user.public_user.PublicUserRepository +import delta.codecharacter.server.user.public_user.PublicUserService +import io.mockk.confirmVerified +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import java.util.UUID + +internal class LeaderboardTest { + + private lateinit var publicUserRepository: PublicUserRepository + private lateinit var publicUserService: PublicUserService + private lateinit var publicUserEntity: PublicUserEntity + + private var user1 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser1", + name = "test user", + country = "In", + college = "college", + avatarId = 1, + tier = TierTypeDto.TIER1, + tutorialLevel = 1, + rating = 2000.0, + wins = 0, + losses = 0, + ties = 0, + isActivated = true, + score = 0.0, + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), + ) + private var user2 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser2", + name = "test user", + country = "In", + college = "college", + avatarId = 1, + tier = TierTypeDto.TIER1, + tutorialLevel = 1, + rating = 1800.0, + wins = 0, + losses = 0, + ties = 0, + isActivated = true, + score = 0.0, + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), + ) + private var user3 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser3", + name = "test user", + country = "In", + college = "college", + avatarId = 1, + tier = TierTypeDto.TIER2, + tutorialLevel = 1, + rating = 1600.0, + wins = 0, + losses = 0, + ties = 0, + isActivated = true, + score = 0.0, + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), + ) + private var user4 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser4", + name = "test user", + country = "In", + college = "college", + avatarId = 1, + tier = TierTypeDto.TIER2, + tutorialLevel = 1, + rating = 1500.0, + wins = 0, + losses = 0, + ties = 0, + isActivated = true, + score = 0.0, + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), + ) + + @BeforeEach + fun setUp() { + publicUserRepository = mockk(relaxed = true) + publicUserService = PublicUserService(publicUserRepository) + publicUserEntity = mockk(relaxed = true) + } + @Test + fun `should get leaderboard by tiers`() { + + every { publicUserRepository.findAllByTier(TierTypeDto.TIER1, any()) } returns + listOf(user1, user2) + every { publicUserRepository.findAllByTier(TierTypeDto.TIER2, any()) } returns + listOf(user3, user4) + + publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER1).forEach { user -> + assertThat(user.user.tier).isEqualTo(TierTypeDto.TIER1) + } + publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER2).forEach { user -> + assertThat(user.user.tier).isEqualTo(TierTypeDto.TIER2) + } + + verify { publicUserRepository.findAllByTier(TierTypeDto.TIER1, any()) } + verify { publicUserRepository.findAllByTier(TierTypeDto.TIER2, any()) } + confirmVerified(publicUserRepository) + } + + @Test + fun `should promote and demote player tiers`() { + every { publicUserRepository.findAllByTier(TierTypeDto.TIER1, any()) } returns + listOf(user2, user1) + every { publicUserRepository.findAllByTier(TierTypeDto.TIER2, any()) } returns + listOf(user3, user4) + every { publicUserRepository.save(any()) } returns publicUserEntity + publicUserService.promoteTiers() + verify { publicUserRepository.save(any()) } + verify { publicUserRepository.findAllByTier(any(), any()) } + confirmVerified(publicUserRepository) + } +} diff --git a/server/src/test/kotlin/delta/codecharacter/server/match/MatchServiceTest.kt b/server/src/test/kotlin/delta/codecharacter/server/match/MatchServiceTest.kt index e6e028de..b5c0571f 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/match/MatchServiceTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/match/MatchServiceTest.kt @@ -8,6 +8,7 @@ import delta.codecharacter.dtos.DailyChallengeMatchRequestDto import delta.codecharacter.dtos.GameMapRevisionDto import delta.codecharacter.dtos.LanguageDto import delta.codecharacter.dtos.MatchModeDto +import delta.codecharacter.dtos.TierTypeDto import delta.codecharacter.server.TestAttributes import delta.codecharacter.server.code.LanguageEnum import delta.codecharacter.server.code.code_revision.CodeRevisionService @@ -280,6 +281,42 @@ internal class MatchServiceTest { ) } + @Test + @Throws(CustomException::class) + fun `should throw bad request if the opponent player belongs to tier 1 in manual match`() { + val playerId = UUID.randomUUID() + val opponentId = UUID.randomUUID() + val opponentPublicUser = + TestAttributes.publicUser.copy( + userId = opponentId, username = "opponent", tier = TierTypeDto.TIER1 + ) + val userCode = Pair(LanguageEnum.CPP, "user-code") + val opponentCode = Pair(LanguageEnum.PYTHON, "opponent-code") + val userMap = "user-map" + val opponentMap = "opponent-map" + every { publicUserService.getPublicUserByUsername(opponentPublicUser.username) } returns + opponentPublicUser + every { lockedCodeService.getLockedCode(playerId) } returns userCode + every { lockedCodeService.getLockedCode(opponentId) } returns opponentCode + every { lockedMapService.getLockedMap(playerId) } returns userMap + every { lockedMapService.getLockedMap(opponentId) } returns opponentMap + every { gameService.createGame(any()) } returns mockk() + every { matchRepository.save(any()) } returns mockk() + every { gameService.sendGameRequest(any(), userCode.second, userCode.first, userMap) } returns + Unit + every { + gameService.sendGameRequest(any(), opponentCode.second, opponentCode.first, opponentMap) + } returns Unit + + val exception = + assertThrows { + matchService.createDualMatch(playerId, opponentPublicUser.username) + } + + assertThat(exception.status).isEqualTo(HttpStatus.BAD_REQUEST) + assertThat(exception.message).isEqualTo("Opponent cannot be a tier 1 player in manual match") + } + @Test fun `should create auto match`() { val userId = UUID.randomUUID()