From 1958e4e828942f86c60b5694c32af11660ba3372 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Tue, 7 Feb 2023 21:08:36 +0530 Subject: [PATCH 01/18] fix: resolved conflicts --- .../schedulers/LeaderboardScheduling.kt | 23 ++++++++ .../user/public_user/PublicUserEntity.kt | 4 +- .../user/public_user/PublicUserService.kt | 50 +++++++++++++++-- .../main/resources/application.example.yml | 2 + .../server/scheduler/SchedulingServiceTest.kt | 55 +++++++++++++++++++ 5 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt create mode 100644 server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt diff --git a/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt b/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt new file mode 100644 index 00000000..62ddd4df --- /dev/null +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt @@ -0,0 +1,23 @@ +package delta.codecharacter.server.schedulers + +import delta.codecharacter.server.user.public_user.PublicUserService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service + +@Service +class LeaderboardScheduling(@Autowired private val publicUserService: PublicUserService) { + @Value("\${environment.registration-time}") val registrationDate: String = "" + @Value("\${environment.game-start-time}") val eventDate: String = "" + + @Scheduled(cron = "\${environment.registration-time}") + fun updateTempLeaderboard() { + publicUserService.updateTempLeaderboardByTier() + } + + @Scheduled(cron = "\${environment.game-start-time}") + fun updateLeaderboard() { + publicUserService.updateLeaderboard() + } +} 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/PublicUserService.kt b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserService.kt index 4640a2eb..5dca922e 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,7 +10,6 @@ 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.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value @@ -46,16 +45,16 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR losses = 0, ties = 0, score = 0.0, - tier = LeaderBoardEnum.TIER_PRACTICE, + tier = TierTypeDto.TIER_PRACTICE, + isDailyChallengeCompleted = false, tutorialLevel = 1, dailyChallengeHistory = HashMap() ) publicUserRepository.save(publicUser) } - 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 { + fun getLeaderboardList(): List { + return publicUserRepository.findAll().map { LeaderboardEntryDto( user = PublicUserDto( @@ -72,11 +71,50 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR wins = it.wins, losses = it.losses, ties = it.ties - ) + ), ) } } + fun updateLeaderboard(leaderboardList: List) { + val leaderboardSize = leaderboardList.size + for (i in 0 until leaderboardSize) { + val user = publicUserRepository.findByUsername(leaderboardList[i].user.username).get() + if (i < 0.2 * leaderboardSize) { + publicUserRepository.save(user.copy(tier = TierTypeDto.TIER1)) + } else { + publicUserRepository.save(user.copy(tier = TierTypeDto.TIER2)) + } + } + } + + fun updateTempLeaderboardByTier() { + updateLeaderboard(getLeaderboardList()) + } + + fun updateLeaderboard() { + val leaderboardList = getLeaderboardList().sortedBy { it.stats.rating }.reversed() + updateLeaderboard(leaderboardList) + } + + fun getLeaderboardByTier(tier: TierTypeDto?): List { + val leaderboardList = getLeaderboardList().sortedBy { it.stats.rating }.reversed() + val leaderboardSize = leaderboardList.size + return if (tier == TierTypeDto.TIER1) { + leaderboardList.subList(0, (0.2 * leaderboardSize).toInt()) + } else { + leaderboardList.subList((0.2 * leaderboardSize).toInt(), leaderboardList.size) + } + } + + fun getLeaderboard(page: Int?, size: Int?, tier: TierTypeDto?): List { + val leaderboardEntry = getLeaderboardByTier(tier) + if (size!! > leaderboardEntry.size) { + return leaderboardEntry + } + return leaderboardEntry.subList(page!! * size, (page * size) + size) + } + fun getDailyChallengeLeaderboard( page: Int?, size: Int? diff --git a/server/src/main/resources/application.example.yml b/server/src/main/resources/application.example.yml index 76840f16..e60ec093 100644 --- a/server/src/main/resources/application.example.yml +++ b/server/src/main/resources/application.example.yml @@ -28,6 +28,8 @@ environment: event-start-date: YYYY-MM-DDTHH:MM:SSZ reCaptcha-key: your-recaptcha-key no-of-tutorial-level: 0 + registration-time: * * * * * * + game-start-time: * * * * * * server: compression: diff --git a/server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt b/server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt new file mode 100644 index 00000000..7b8d9750 --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt @@ -0,0 +1,55 @@ +package delta.codecharacter.server.scheduler + +import delta.codecharacter.server.schedulers.SchedulingService +import delta.codecharacter.server.user.public_user.PublicUserRepository +import delta.codecharacter.server.user.public_user.PublicUserService +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.runs +import io.mockk.verify +import org.awaitility.kotlin.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import java.time.Duration + +internal class SchedulingServiceTest { + + private lateinit var publicUserService: PublicUserService + private lateinit var schedulingService: SchedulingService + private lateinit var publicUserRepository: PublicUserRepository + @BeforeEach + fun setUp() { + publicUserRepository = mockk(relaxed = true) + publicUserService = PublicUserService(publicUserRepository) + schedulingService = SchedulingService(publicUserService) + } + + @Test + fun `should promote user tiers`() { + schedulingService.promoteAndDemoteUserTiers() + await.atMost(Duration.ofSeconds(1)).untilAsserted { + verify(atLeast = 1) { publicUserService.promoteTiers() } + } + } + + @Test + fun `should update user tiers based on ratings`() { + every { publicUserService.updateTierForUser() } just runs + schedulingService.updateLeaderboard() + await.atMost(Duration.ofSeconds(1)).untilAsserted { + verify { publicUserService.updateTierForUser() } + } + } + + @Test + fun `should reset ratings and update tiers after register phase`() { + every { publicUserService.resetRatingsAfterPracticePhase() } just runs + every { publicUserService.updateLeaderboardAfterPracticePhase() } just runs + schedulingService.updateLeaderboardAfterPracticePhase() + await.atMost(Duration.ofSeconds(1)).untilAsserted { + verify { publicUserService.resetRatingsAfterPracticePhase() } + verify { publicUserService.updateLeaderboardAfterPracticePhase() } + } + } +} From c60f499630800ec0b5d85c50765901c097fe0d49 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Wed, 8 Feb 2023 16:50:00 +0530 Subject: [PATCH 02/18] update to recaptcha v3 --- .../kotlin/delta/codecharacter/server/user/UserService.kt | 7 +++++-- .../codecharacter/server/SecurityTestConfiguration.kt | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) 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..3fd394d8 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/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt index 7f958d91..83c69eaa 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt @@ -4,6 +4,7 @@ import delta.codecharacter.dtos.ChallengeTypeDto import delta.codecharacter.dtos.DailyChallengeObjectDto import delta.codecharacter.server.daily_challenge.DailyChallengeEntity import delta.codecharacter.server.leaderboard.LeaderBoardEnum +import delta.codecharacter.dtos.TierTypeDto import delta.codecharacter.server.user.LoginType import delta.codecharacter.server.user.UserEntity import delta.codecharacter.server.user.public_user.DailyChallengeHistory @@ -58,7 +59,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 From d6fd545984c52204c3679915492501ddf201ddf6 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Thu, 9 Feb 2023 17:29:56 +0530 Subject: [PATCH 03/18] fix: formatting --- .../codecharacter/server/schedulers/LeaderboardScheduling.kt | 3 --- server/src/main/resources/application.example.yml | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt b/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt index 62ddd4df..19bff642 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt @@ -2,14 +2,11 @@ package delta.codecharacter.server.schedulers import delta.codecharacter.server.user.public_user.PublicUserService import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @Service class LeaderboardScheduling(@Autowired private val publicUserService: PublicUserService) { - @Value("\${environment.registration-time}") val registrationDate: String = "" - @Value("\${environment.game-start-time}") val eventDate: String = "" @Scheduled(cron = "\${environment.registration-time}") fun updateTempLeaderboard() { diff --git a/server/src/main/resources/application.example.yml b/server/src/main/resources/application.example.yml index e60ec093..aa707573 100644 --- a/server/src/main/resources/application.example.yml +++ b/server/src/main/resources/application.example.yml @@ -28,8 +28,8 @@ environment: event-start-date: YYYY-MM-DDTHH:MM:SSZ reCaptcha-key: your-recaptcha-key no-of-tutorial-level: 0 - registration-time: * * * * * * - game-start-time: * * * * * * + registration-time: "* * * * * *" + game-start-time: "* * * * * *" server: compression: From c6d043c32ff1aebb1e582faf7432d3b3642fc7d0 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Sat, 11 Feb 2023 15:36:57 +0530 Subject: [PATCH 04/18] fix: updateLeaderboard and pagination requests --- .../user/public_user/PublicUserService.kt | 64 +++++++------------ .../resources/application.docker.example.yml | 3 + .../main/resources/application.example.yml | 1 + 3 files changed, 27 insertions(+), 41 deletions(-) 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 5dca922e..7fb93210 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 @@ -24,6 +24,7 @@ import java.util.UUID class PublicUserService(@Autowired private val publicUserRepository: PublicUserRepository) { @Value("\${environment.no-of-tutorial-level}") private lateinit var totalTutorialLevels: Number + @Value("\${environment.top-n-players}") private val topPlayers: Int = 0 fun create( userId: UUID, username: String, @@ -53,8 +54,28 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR publicUserRepository.save(publicUser) } - fun getLeaderboardList(): List { - return publicUserRepository.findAll().map { + fun updateLeaderboard(publicUsers: List) { + for (i in publicUsers.indices) { + val user = publicUserRepository.findById(publicUsers[i].userId).get() + if (i < topPlayers) { + publicUserRepository.save(user.copy(tier = TierTypeDto.TIER1)) + } else { + publicUserRepository.save(user.copy(tier = TierTypeDto.TIER2)) + } + } + } + + fun updateTempLeaderboardByTier() { + updateLeaderboard(publicUserRepository.findAll()) + } + + fun updateLeaderboard() { + updateLeaderboard(publicUserRepository.findAll(Sort.by(Sort.Order.desc("rating")))) + } + + fun getLeaderboard(page: Int?, size: Int?, tier: TierTypeDto?): List { + val pageRequest = PageRequest.of(page ?: 0, size ?: 10, Sort.by(Sort.Order.desc("rating"))) + return publicUserRepository.findAll(pageRequest).content.filter { it.tier == tier }.map { LeaderboardEntryDto( user = PublicUserDto( @@ -76,45 +97,6 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR } } - fun updateLeaderboard(leaderboardList: List) { - val leaderboardSize = leaderboardList.size - for (i in 0 until leaderboardSize) { - val user = publicUserRepository.findByUsername(leaderboardList[i].user.username).get() - if (i < 0.2 * leaderboardSize) { - publicUserRepository.save(user.copy(tier = TierTypeDto.TIER1)) - } else { - publicUserRepository.save(user.copy(tier = TierTypeDto.TIER2)) - } - } - } - - fun updateTempLeaderboardByTier() { - updateLeaderboard(getLeaderboardList()) - } - - fun updateLeaderboard() { - val leaderboardList = getLeaderboardList().sortedBy { it.stats.rating }.reversed() - updateLeaderboard(leaderboardList) - } - - fun getLeaderboardByTier(tier: TierTypeDto?): List { - val leaderboardList = getLeaderboardList().sortedBy { it.stats.rating }.reversed() - val leaderboardSize = leaderboardList.size - return if (tier == TierTypeDto.TIER1) { - leaderboardList.subList(0, (0.2 * leaderboardSize).toInt()) - } else { - leaderboardList.subList((0.2 * leaderboardSize).toInt(), leaderboardList.size) - } - } - - fun getLeaderboard(page: Int?, size: Int?, tier: TierTypeDto?): List { - val leaderboardEntry = getLeaderboardByTier(tier) - if (size!! > leaderboardEntry.size) { - return leaderboardEntry - } - return leaderboardEntry.subList(page!! * size, (page * size) + size) - } - fun getDailyChallengeLeaderboard( page: Int?, size: Int? diff --git a/server/src/main/resources/application.docker.example.yml b/server/src/main/resources/application.docker.example.yml index 2cf6df8a..abf819fa 100644 --- a/server/src/main/resources/application.docker.example.yml +++ b/server/src/main/resources/application.docker.example.yml @@ -30,6 +30,9 @@ environment: event-start-date: YYYY-MM-DDTHH:MM:SSZ reCaptcha-key: your-recaptcha-key no-of-tutorial-level: 0 + registration-time: "* * * * * *" + game-start-time: "* * * * * *" + top-n-players: 5 server: compression: diff --git a/server/src/main/resources/application.example.yml b/server/src/main/resources/application.example.yml index aa707573..660eee9d 100644 --- a/server/src/main/resources/application.example.yml +++ b/server/src/main/resources/application.example.yml @@ -30,6 +30,7 @@ environment: no-of-tutorial-level: 0 registration-time: "* * * * * *" game-start-time: "* * * * * *" + top-n-players: 5 server: compression: From 635f9f2452cdd069deb021f76665c0290f6d73c7 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Tue, 14 Feb 2023 00:07:54 +0530 Subject: [PATCH 05/18] fix: changed function names and updated SchedulingService --- .../schedulers/LeaderboardScheduling.kt | 20 ------------------- .../server/schedulers/SchedulingService.kt | 19 +++++++++++++++++- .../codecharacter/server/user/UserService.kt | 2 +- .../user/public_user/PublicUserRepository.kt | 4 ++++ .../user/public_user/PublicUserService.kt | 17 ++++++++-------- 5 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt diff --git a/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt b/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt deleted file mode 100644 index 19bff642..00000000 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/LeaderboardScheduling.kt +++ /dev/null @@ -1,20 +0,0 @@ -package delta.codecharacter.server.schedulers - -import delta.codecharacter.server.user.public_user.PublicUserService -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.scheduling.annotation.Scheduled -import org.springframework.stereotype.Service - -@Service -class LeaderboardScheduling(@Autowired private val publicUserService: PublicUserService) { - - @Scheduled(cron = "\${environment.registration-time}") - fun updateTempLeaderboard() { - publicUserService.updateTempLeaderboardByTier() - } - - @Scheduled(cron = "\${environment.game-start-time}") - fun updateLeaderboard() { - publicUserService.updateLeaderboard() - } -} 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..a9baaae8 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt @@ -4,4 +4,21 @@ import delta.codecharacter.server.user.public_user.PublicUserService import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service -@Service class SchedulingService(@Autowired private val publicUserService: PublicUserService) +@Service +class SchedulingService(@Autowired private val publicUserService: PublicUserService) { + + @Scheduled(cron = "0 1 1 * * ?") + fun updateIsDailyChallengeCompleted() { + publicUserService.updateIsDailyChallengeComplete() + } + + @Scheduled(cron = "\${environment.registration-time}") + fun updateTempLeaderboard() { + publicUserService.updateLeaderboardAfterPracticePhase() + } + + @Scheduled(cron = "\${environment.game-start-time}") + fun updateLeaderboard() { + publicUserService.updateTierForUser() + } +} 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 3fd394d8..7d01ed1f 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/user/UserService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/user/UserService.kt @@ -182,7 +182,7 @@ class UserService( val json = JsonObject(response.body()).toBsonDocument() return ( json.getBoolean("success").value && - (json.getDouble("score").value.compareTo(0.5) > 0) + (json.getDouble("score").value.compareTo(0.5) >= 0) ) } catch (e: Exception) { e.printStackTrace() 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 7fb93210..bb2cab60 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 @@ -54,10 +54,9 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR publicUserRepository.save(publicUser) } - fun updateLeaderboard(publicUsers: List) { - for (i in publicUsers.indices) { - val user = publicUserRepository.findById(publicUsers[i].userId).get() - if (i < topPlayers) { + fun updateTiers(publicUsers: List) { + publicUsers.forEach { user -> + if (publicUsers.indexOf(user) < topPlayers) { publicUserRepository.save(user.copy(tier = TierTypeDto.TIER1)) } else { publicUserRepository.save(user.copy(tier = TierTypeDto.TIER2)) @@ -65,17 +64,17 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR } } - fun updateTempLeaderboardByTier() { - updateLeaderboard(publicUserRepository.findAll()) + fun updateLeaderboardAfterPracticePhase() { + updateTiers(publicUserRepository.findAll()) } - fun updateLeaderboard() { - updateLeaderboard(publicUserRepository.findAll(Sort.by(Sort.Order.desc("rating")))) + fun updateTierForUser() { + updateTiers(publicUserRepository.findAll(Sort.by(Sort.Order.desc("rating")))) } fun getLeaderboard(page: Int?, size: Int?, tier: TierTypeDto?): List { val pageRequest = PageRequest.of(page ?: 0, size ?: 10, Sort.by(Sort.Order.desc("rating"))) - return publicUserRepository.findAll(pageRequest).content.filter { it.tier == tier }.map { + return publicUserRepository.findAllByTier(tier, pageRequest).map { LeaderboardEntryDto( user = PublicUserDto( From 4d4c27327955a4824daecd0ce58d2283daa32be6 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Tue, 14 Feb 2023 20:43:35 +0530 Subject: [PATCH 06/18] feat: add timezone and reset ratings --- .../server/schedulers/SchedulingService.kt | 5 +++-- .../server/user/public_user/PublicUserService.kt | 13 +++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) 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 a9baaae8..a0567a30 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt @@ -12,12 +12,13 @@ class SchedulingService(@Autowired private val publicUserService: PublicUserServ publicUserService.updateIsDailyChallengeComplete() } - @Scheduled(cron = "\${environment.registration-time}") + @Scheduled(cron = "\${environment.registration-time}", zone = "GMT") fun updateTempLeaderboard() { + publicUserService.resetRatingsAfterPracticePhase() publicUserService.updateLeaderboardAfterPracticePhase() } - @Scheduled(cron = "\${environment.game-start-time}") + @Scheduled(cron = "\${environment.game-start-time}", zone = "GMT") fun updateLeaderboard() { publicUserService.updateTierForUser() } 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 bb2cab60..d2d15c51 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 @@ -24,7 +24,7 @@ import java.util.UUID class PublicUserService(@Autowired private val publicUserRepository: PublicUserRepository) { @Value("\${environment.no-of-tutorial-level}") private lateinit var totalTutorialLevels: Number - @Value("\${environment.top-n-players}") private val topPlayers: Int = 0 + @Value("\${environment.top-n-players}") private lateinit var topPlayers: Number fun create( userId: UUID, username: String, @@ -56,7 +56,7 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR fun updateTiers(publicUsers: List) { publicUsers.forEach { user -> - if (publicUsers.indexOf(user) < topPlayers) { + if (publicUsers.indexOf(user) < topPlayers.toInt()) { publicUserRepository.save(user.copy(tier = TierTypeDto.TIER1)) } else { publicUserRepository.save(user.copy(tier = TierTypeDto.TIER2)) @@ -68,6 +68,15 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR updateTiers(publicUserRepository.findAll()) } + fun resetRatingsAfterPracticePhase() { + val users = publicUserRepository.findAll() + users.forEach { user -> + publicUserRepository.save( + user.copy(rating = (1500).toDouble(), wins = 0, ties = 0, losses = 0) + ) + } + } + fun updateTierForUser() { updateTiers(publicUserRepository.findAll(Sort.by(Sort.Order.desc("rating")))) } From eb01c33d14123508df8a052800a20a092740b9d7 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Wed, 15 Feb 2023 22:40:28 +0530 Subject: [PATCH 07/18] feat: tier matches --- .../server/match/MatchService.kt | 33 ++++++++++-------- .../user/public_user/PublicUserService.kt | 4 +-- .../server/SecurityTestConfiguration.kt | 2 +- .../server/match/MatchServiceTest.kt | 34 +++++++++++++++++++ 4 files changed, 55 insertions(+), 18 deletions(-) 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/user/public_user/PublicUserService.kt b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserService.kt index d2d15c51..0eb3fe50 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 @@ -71,9 +71,7 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR fun resetRatingsAfterPracticePhase() { val users = publicUserRepository.findAll() users.forEach { user -> - publicUserRepository.save( - user.copy(rating = (1500).toDouble(), wins = 0, ties = 0, losses = 0) - ) + publicUserRepository.save(user.copy(rating = 1500.0, wins = 0, ties = 0, losses = 0)) } } diff --git a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt index 83c69eaa..9931395a 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt @@ -59,7 +59,7 @@ class TestAttributes { wins = 4, losses = 2, ties = 1, - tier = TierTypeDto.TIER_PRACTICE, + tier = TierTypeDto.TIER1, score = 0.0, dailyChallengeHistory = hashMapOf(0 to DailyChallengeHistory(0.0, dailyChallengeCode)), tutorialLevel = 1 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..b0e5b248 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/match/MatchServiceTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/match/MatchServiceTest.kt @@ -280,6 +280,40 @@ 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") + 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() From e5b0e1edd7a988e5e12aaef9b1f15f4d3a802c31 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Wed, 15 Feb 2023 23:19:26 +0530 Subject: [PATCH 08/18] fix: test errors --- .../delta/codecharacter/server/SecurityTestConfiguration.kt | 2 +- .../delta/codecharacter/server/match/MatchServiceTest.kt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt index 9931395a..83c69eaa 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt @@ -59,7 +59,7 @@ class TestAttributes { wins = 4, losses = 2, ties = 1, - tier = TierTypeDto.TIER1, + 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/match/MatchServiceTest.kt b/server/src/test/kotlin/delta/codecharacter/server/match/MatchServiceTest.kt index b0e5b248..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 @@ -286,7 +287,9 @@ internal class MatchServiceTest { val playerId = UUID.randomUUID() val opponentId = UUID.randomUUID() val opponentPublicUser = - TestAttributes.publicUser.copy(userId = opponentId, username = "opponent") + 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" From 4659c542f78a2fb58231fb9199ea95a168aa0b2a Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Sun, 19 Feb 2023 20:40:28 +0530 Subject: [PATCH 09/18] feat: promote/demote user tiers --- .../server/schedulers/SchedulingService.kt | 5 ++++ .../user/public_user/PublicUserService.kt | 24 +++++++++++++++++-- .../resources/application.docker.example.yml | 4 +++- .../main/resources/application.example.yml | 4 +++- 4 files changed, 33 insertions(+), 4 deletions(-) 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 a0567a30..cb4961d4 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt @@ -22,4 +22,9 @@ class SchedulingService(@Autowired private val publicUserService: PublicUserServ fun updateLeaderboard() { publicUserService.updateTierForUser() } + + @Scheduled(cron = "\${environment.update-time}", zone = "GMT") + fun promoteAndDemoteUserTiers() { + publicUserService.promoteTiers() + } } 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 0eb3fe50..fa9e58e3 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 @@ -24,7 +24,8 @@ import java.util.UUID class PublicUserService(@Autowired private val publicUserRepository: PublicUserRepository) { @Value("\${environment.no-of-tutorial-level}") private lateinit var totalTutorialLevels: Number - @Value("\${environment.top-n-players}") private lateinit var topPlayers: Number + @Value("\${environment.tier-1-players}") private lateinit var tier1Players: Number + @Value("\${environment.top-players}") private lateinit var topPlayer: Number fun create( userId: UUID, username: String, @@ -56,7 +57,7 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR fun updateTiers(publicUsers: List) { publicUsers.forEach { user -> - if (publicUsers.indexOf(user) < topPlayers.toInt()) { + if (publicUsers.indexOf(user) < tier1Players.toInt()) { publicUserRepository.save(user.copy(tier = TierTypeDto.TIER1)) } else { publicUserRepository.save(user.copy(tier = TierTypeDto.TIER2)) @@ -79,6 +80,25 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR updateTiers(publicUserRepository.findAll(Sort.by(Sort.Order.desc("rating")))) } + 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 -> + publicUserRepository.save(users.copy(tier = TierTypeDto.TIER1)) + } + bottomPlayersInTier1.forEach { users -> + publicUserRepository.save(users.copy(tier = TierTypeDto.TIER2)) + } + } + fun getLeaderboard(page: Int?, size: Int?, tier: TierTypeDto?): List { val pageRequest = PageRequest.of(page ?: 0, size ?: 10, Sort.by(Sort.Order.desc("rating"))) return publicUserRepository.findAllByTier(tier, pageRequest).map { diff --git a/server/src/main/resources/application.docker.example.yml b/server/src/main/resources/application.docker.example.yml index abf819fa..195336d6 100644 --- a/server/src/main/resources/application.docker.example.yml +++ b/server/src/main/resources/application.docker.example.yml @@ -32,7 +32,9 @@ environment: no-of-tutorial-level: 0 registration-time: "* * * * * *" game-start-time: "* * * * * *" - top-n-players: 5 + 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 660eee9d..0191fc02 100644 --- a/server/src/main/resources/application.example.yml +++ b/server/src/main/resources/application.example.yml @@ -30,7 +30,9 @@ environment: no-of-tutorial-level: 0 registration-time: "* * * * * *" game-start-time: "* * * * * *" - top-n-players: 5 + tier-1-players: 20 + top-players: 5 + update-time: "*/20 * * * * *" server: compression: From ffaee43c7e68238495056355490ba6d03fbabab8 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Sat, 25 Feb 2023 23:35:51 +0530 Subject: [PATCH 10/18] feat: leaderboard test --- .../server/leaderboard/leaderboardTest.kt | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt 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..d9177d36 --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt @@ -0,0 +1,109 @@ +package delta.codecharacter.server.leaderboard + +import delta.codecharacter.dtos.TierTypeDto +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.every +import io.mockk.mockk +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 + + @BeforeEach + fun setUp() { + publicUserRepository = mockk(relaxed = true) + publicUserService = PublicUserService(publicUserRepository) + publicUserEntity = mockk(relaxed = true) + } + @Test + fun `should get leaderboard by tiers`() { + val user1 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser", + 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, + isDailyChallengeCompleted = false + ) + val user2 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser", + 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, + isDailyChallengeCompleted = false + ) + val user3 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser", + 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, + isDailyChallengeCompleted = false + ) + val user4 = + PublicUserEntity( + userId = UUID.randomUUID(), + username = "testUser", + 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, + isDailyChallengeCompleted = false + ) + every { publicUserRepository.findAllByTier(TierTypeDto.TIER1, any()) } returns + listOf(user1, user2) + every { publicUserRepository.findAllByTier(TierTypeDto.TIER2, any()) } returns + listOf(user3, user4) + + val tier1Entries = publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER1) + val tier2Entries = publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER2) + tier1Entries.forEach { user -> assert(user.user.tier == TierTypeDto.TIER1) } + tier2Entries.forEach { user -> assert(user.user.tier == TierTypeDto.TIER2) } + } +} From 628ef43da45784d037f2f21b6aa5cf6db9f070b4 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Sun, 26 Feb 2023 20:18:14 +0530 Subject: [PATCH 11/18] feat: tests for update and promote tier functions --- .../user/public_user/PublicUserService.kt | 4 +- .../server/leaderboard/leaderboardTest.kt | 179 ++++++++++-------- 2 files changed, 105 insertions(+), 78 deletions(-) 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 fa9e58e3..6cf2f9bf 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 @@ -24,8 +24,8 @@ 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 lateinit var tier1Players: Number - @Value("\${environment.top-players}") private lateinit var topPlayer: Number + @Value("\${environment.tier-1-players}") private var tier1Players: Number = 1 + @Value("\${environment.top-players}") private var topPlayer: Number = 1 fun create( userId: UUID, username: String, diff --git a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt index d9177d36..79df20a9 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt @@ -4,8 +4,10 @@ import delta.codecharacter.dtos.TierTypeDto 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.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import java.util.UUID @@ -16,6 +18,79 @@ internal class leaderboardTest { 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, + isDailyChallengeCompleted = false + ) + 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, + isDailyChallengeCompleted = false + ) + 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, + isDailyChallengeCompleted = false + ) + 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, + isDailyChallengeCompleted = false + ) + @BeforeEach fun setUp() { publicUserRepository = mockk(relaxed = true) @@ -24,86 +99,38 @@ internal class leaderboardTest { } @Test fun `should get leaderboard by tiers`() { - val user1 = - PublicUserEntity( - userId = UUID.randomUUID(), - username = "testUser", - 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, - isDailyChallengeCompleted = false - ) - val user2 = - PublicUserEntity( - userId = UUID.randomUUID(), - username = "testUser", - 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, - isDailyChallengeCompleted = false - ) - val user3 = - PublicUserEntity( - userId = UUID.randomUUID(), - username = "testUser", - 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, - isDailyChallengeCompleted = false - ) - val user4 = - PublicUserEntity( - userId = UUID.randomUUID(), - username = "testUser", - 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, - isDailyChallengeCompleted = false - ) + every { publicUserRepository.findAllByTier(TierTypeDto.TIER1, any()) } returns listOf(user1, user2) every { publicUserRepository.findAllByTier(TierTypeDto.TIER2, any()) } returns listOf(user3, user4) - val tier1Entries = publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER1) - val tier2Entries = publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER2) - tier1Entries.forEach { user -> assert(user.user.tier == TierTypeDto.TIER1) } - tier2Entries.forEach { user -> assert(user.user.tier == TierTypeDto.TIER2) } + publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER1).forEach { user -> + assert(user.user.tier == TierTypeDto.TIER1) + } + publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER2).forEach { user -> + assert(user.user.tier == TierTypeDto.TIER2) + } + } + + @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) + } + + @Test + fun `should categorise leaderboard into tiers`() { + every { publicUserRepository.save(any()) } returns publicUserEntity + publicUserService.updateTiers(listOf(user1, user2, user3, user4)) + verify { publicUserRepository.save(any()) } + confirmVerified(publicUserRepository) } } From bc95fdeb99a96384f3864c1af7466c6e287d4391 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Mon, 27 Feb 2023 18:11:09 +0530 Subject: [PATCH 12/18] resolved conflicts --- .../server/schedulers/SchedulingService.kt | 6 +----- .../server/user/public_user/PublicUserService.kt | 1 - .../server/SecurityTestConfiguration.kt | 5 ++--- .../server/leaderboard/leaderboardTest.kt | 14 ++++++++++---- 4 files changed, 13 insertions(+), 13 deletions(-) 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 cb4961d4..bdc43c4f 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt @@ -2,16 +2,12 @@ package delta.codecharacter.server.schedulers import delta.codecharacter.server.user.public_user.PublicUserService 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) { - @Scheduled(cron = "0 1 1 * * ?") - fun updateIsDailyChallengeCompleted() { - publicUserService.updateIsDailyChallengeComplete() - } - @Scheduled(cron = "\${environment.registration-time}", zone = "GMT") fun updateTempLeaderboard() { publicUserService.resetRatingsAfterPracticePhase() 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 6cf2f9bf..aeeafd35 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 @@ -48,7 +48,6 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR ties = 0, score = 0.0, tier = TierTypeDto.TIER_PRACTICE, - isDailyChallengeCompleted = false, tutorialLevel = 1, dailyChallengeHistory = HashMap() ) diff --git a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt index 83c69eaa..51002d99 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt @@ -2,9 +2,8 @@ package delta.codecharacter.server import delta.codecharacter.dtos.ChallengeTypeDto import delta.codecharacter.dtos.DailyChallengeObjectDto -import delta.codecharacter.server.daily_challenge.DailyChallengeEntity -import delta.codecharacter.server.leaderboard.LeaderBoardEnum import delta.codecharacter.dtos.TierTypeDto +import delta.codecharacter.server.daily_challenge.DailyChallengeEntity import delta.codecharacter.server.user.LoginType import delta.codecharacter.server.user.UserEntity import delta.codecharacter.server.user.public_user.DailyChallengeHistory @@ -19,7 +18,7 @@ import org.springframework.security.core.context.SecurityContext import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.test.context.support.WithSecurityContext import org.springframework.security.test.context.support.WithSecurityContextFactory -import java.util.UUID +import java.util.* class TestAttributes { companion object { diff --git a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt index 79df20a9..b16f86cf 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt @@ -1,6 +1,8 @@ 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 @@ -34,7 +36,8 @@ internal class leaderboardTest { ties = 0, isActivated = true, score = 0.0, - isDailyChallengeCompleted = false + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), ) private var user2 = PublicUserEntity( @@ -52,7 +55,8 @@ internal class leaderboardTest { ties = 0, isActivated = true, score = 0.0, - isDailyChallengeCompleted = false + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), ) private var user3 = PublicUserEntity( @@ -70,7 +74,8 @@ internal class leaderboardTest { ties = 0, isActivated = true, score = 0.0, - isDailyChallengeCompleted = false + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), ) private var user4 = PublicUserEntity( @@ -88,7 +93,8 @@ internal class leaderboardTest { ties = 0, isActivated = true, score = 0.0, - isDailyChallengeCompleted = false + dailyChallengeHistory = + hashMapOf(0 to DailyChallengeHistory(0.0, TestAttributes.dailyChallengeCode)), ) @BeforeEach From 0c6f67f9fa928fcde7f00589dec0ce1fdb361dbd Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Mon, 27 Feb 2023 18:16:50 +0530 Subject: [PATCH 13/18] fix: formatting --- .../delta/codecharacter/server/SecurityTestConfiguration.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt index 51002d99..cb1a4261 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/SecurityTestConfiguration.kt @@ -18,7 +18,7 @@ import org.springframework.security.core.context.SecurityContext import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.test.context.support.WithSecurityContext import org.springframework.security.test.context.support.WithSecurityContextFactory -import java.util.* +import java.util.UUID class TestAttributes { companion object { From 1cfb260190910cd15b9b227495ecadf7397f9389 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Mon, 27 Feb 2023 18:28:39 +0530 Subject: [PATCH 14/18] fix: test errors --- .../server/scheduler/SchedulingServiceTest.kt | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt diff --git a/server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt b/server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt deleted file mode 100644 index 7b8d9750..00000000 --- a/server/src/test/kotlin/delta/codecharacter/server/scheduler/SchedulingServiceTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -package delta.codecharacter.server.scheduler - -import delta.codecharacter.server.schedulers.SchedulingService -import delta.codecharacter.server.user.public_user.PublicUserRepository -import delta.codecharacter.server.user.public_user.PublicUserService -import io.mockk.every -import io.mockk.just -import io.mockk.mockk -import io.mockk.runs -import io.mockk.verify -import org.awaitility.kotlin.await -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import java.time.Duration - -internal class SchedulingServiceTest { - - private lateinit var publicUserService: PublicUserService - private lateinit var schedulingService: SchedulingService - private lateinit var publicUserRepository: PublicUserRepository - @BeforeEach - fun setUp() { - publicUserRepository = mockk(relaxed = true) - publicUserService = PublicUserService(publicUserRepository) - schedulingService = SchedulingService(publicUserService) - } - - @Test - fun `should promote user tiers`() { - schedulingService.promoteAndDemoteUserTiers() - await.atMost(Duration.ofSeconds(1)).untilAsserted { - verify(atLeast = 1) { publicUserService.promoteTiers() } - } - } - - @Test - fun `should update user tiers based on ratings`() { - every { publicUserService.updateTierForUser() } just runs - schedulingService.updateLeaderboard() - await.atMost(Duration.ofSeconds(1)).untilAsserted { - verify { publicUserService.updateTierForUser() } - } - } - - @Test - fun `should reset ratings and update tiers after register phase`() { - every { publicUserService.resetRatingsAfterPracticePhase() } just runs - every { publicUserService.updateLeaderboardAfterPracticePhase() } just runs - schedulingService.updateLeaderboardAfterPracticePhase() - await.atMost(Duration.ofSeconds(1)).untilAsserted { - verify { publicUserService.resetRatingsAfterPracticePhase() } - verify { publicUserService.updateLeaderboardAfterPracticePhase() } - } - } -} From 62e7792d96400e09d22f4c6a4a27fe4e00a33012 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Mon, 27 Feb 2023 23:37:21 +0530 Subject: [PATCH 15/18] fix: leaderboard tests --- .../server/schedulers/SchedulingService.kt | 5 -- .../user/public_user/PublicUserService.kt | 4 -- .../LeaderboardControllerIntegrationTest.kt | 50 +++++++++++++++++++ ...{leaderboardTest.kt => LeaderboardTest.kt} | 10 +--- 4 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt rename server/src/test/kotlin/delta/codecharacter/server/leaderboard/{leaderboardTest.kt => LeaderboardTest.kt} (92%) 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 bdc43c4f..826d5d9e 100644 --- a/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt +++ b/server/src/main/kotlin/delta/codecharacter/server/schedulers/SchedulingService.kt @@ -14,11 +14,6 @@ class SchedulingService(@Autowired private val publicUserService: PublicUserServ publicUserService.updateLeaderboardAfterPracticePhase() } - @Scheduled(cron = "\${environment.game-start-time}", zone = "GMT") - fun updateLeaderboard() { - publicUserService.updateTierForUser() - } - @Scheduled(cron = "\${environment.update-time}", zone = "GMT") fun promoteAndDemoteUserTiers() { publicUserService.promoteTiers() 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 aeeafd35..80827bb0 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 @@ -75,10 +75,6 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR } } - fun updateTierForUser() { - updateTiers(publicUserRepository.findAll(Sort.by(Sort.Order.desc("rating")))) - } - fun promoteTiers() { val topPlayersInTier2 = publicUserRepository.findAllByTier( 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..71b4f643 --- /dev/null +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt @@ -0,0 +1,50 @@ +package delta.codecharacter.server.leaderboard + +import com.fasterxml.jackson.databind.ObjectMapper +import delta.codecharacter.dtos.LeaderboardEntryDto +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 + +@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 return empty list when leaderboard not found`() { + mockMvc.get("/leaderboard") { contentType = MediaType.APPLICATION_JSON }.andExpect { + status { is2xxSuccessful() } + content { contentType(MediaType.APPLICATION_JSON) } + content { listOf() } + } + } + + @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 similarity index 92% rename from server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt rename to server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardTest.kt index b16f86cf..1ee4b8fa 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/leaderboardTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardTest.kt @@ -14,7 +14,7 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import java.util.UUID -internal class leaderboardTest { +internal class LeaderboardTest { private lateinit var publicUserRepository: PublicUserRepository private lateinit var publicUserService: PublicUserService @@ -131,12 +131,4 @@ internal class leaderboardTest { verify { publicUserRepository.findAllByTier(any(), any()) } confirmVerified(publicUserRepository) } - - @Test - fun `should categorise leaderboard into tiers`() { - every { publicUserRepository.save(any()) } returns publicUserEntity - publicUserService.updateTiers(listOf(user1, user2, user3, user4)) - verify { publicUserRepository.save(any()) } - confirmVerified(publicUserRepository) - } } From 3ca853d6e2fcd9431836965f1474b1ef516cbf67 Mon Sep 17 00:00:00 2001 From: "https://github.com/Valliammai-SM" <112121074@nitt.edu> Date: Tue, 28 Feb 2023 00:42:10 +0530 Subject: [PATCH 16/18] leaderboardController tests --- .../user/public_user/PublicUserService.kt | 11 ++++ .../LeaderboardControllerIntegrationTest.kt | 53 +++++++++++++++++++ 2 files changed, 64 insertions(+) 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 80827bb0..561d6164 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 @@ -96,6 +96,17 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR fun getLeaderboard(page: Int?, size: Int?, tier: TierTypeDto?): List { val pageRequest = PageRequest.of(page ?: 0, size ?: 10, Sort.by(Sort.Order.desc("rating"))) + if (( + tier == TierTypeDto.TIER2 && + publicUserRepository.findAllByTier(TierTypeDto.TIER1, pageRequest).size == 0 + ) || + ( + tier == TierTypeDto.TIER1 && + publicUserRepository.findAllByTier(TierTypeDto.TIER2, pageRequest).size == 0 + ) + ) { + return listOf() + } return publicUserRepository.findAllByTier(tier, pageRequest).map { LeaderboardEntryDto( user = diff --git a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt index 71b4f643..f35ee966 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt @@ -2,6 +2,9 @@ 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 @@ -17,6 +20,8 @@ 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 +import java.util.UUID @AutoConfigureMockMvc @SpringBootTest @@ -33,6 +38,39 @@ internal class LeaderboardControllerIntegrationTest(@Autowired val mockMvc: Mock mongoTemplate.save(TestAttributes.publicUser) } + @Test + @WithMockCustomUser + fun `should get leaderboard`() { + val publicUserEntity = + TestAttributes.publicUser.copy(userId = UUID.randomUUID(), username = "opponent") + mongoTemplate.save(publicUserEntity) + + val leaderboardEntryDto = + LeaderboardEntryDto( + user = + PublicUserDto( + username = "TestUser", + name = "Test User", + country = "Test Country", + college = "Test College", + avatarId = 1, + tier = TierTypeDto.TIER_PRACTICE + ), + stats = + UserStatsDto( + rating = BigDecimal.valueOf(1000.0), + wins = 4, + losses = 2, + ties = 1, + ), + ) + mockMvc.get("/leaderboard") { contentType = MediaType.APPLICATION_JSON }.andExpect { + status { is2xxSuccessful() } + content { contentType(MediaType.APPLICATION_JSON) } + content { listOf(leaderboardEntryDto) } + } + } + @Test @WithMockCustomUser fun `should return empty list when leaderboard not found`() { @@ -43,6 +81,21 @@ internal class LeaderboardControllerIntegrationTest(@Autowired val mockMvc: Mock } } + @Test + @WithMockCustomUser + fun `should return empty list if all players belong to tier 1`() { + val publicUserEntity = + TestAttributes.publicUser.copy( + userId = UUID.randomUUID(), username = "opponent", tier = TierTypeDto.TIER1 + ) + mongoTemplate.save(publicUserEntity) + mockMvc.get("/leaderboard") { contentType = MediaType.APPLICATION_JSON }.andExpect { + status { is2xxSuccessful() } + content { contentType(MediaType.APPLICATION_JSON) } + content { listOf() } + } + } + @AfterEach fun tearDown() { mongoTemplate.dropCollection() From e7a7b17be7fec5902db02efefd4c0008bff0d155 Mon Sep 17 00:00:00 2001 From: Ram-20062003 Date: Tue, 28 Feb 2023 03:12:26 +0530 Subject: [PATCH 17/18] feat: add logger for scheduling and refactor tests and schedulers --- .../server/schedulers/SchedulingService.kt | 6 +- .../user/public_user/PublicUserService.kt | 55 +++++---- server/src/main/resources/player_code | 2 +- .../LeaderboardControllerIntegrationTest.kt | 106 +++++++++++------- .../server/leaderboard/LeaderboardTest.kt | 9 +- 5 files changed, 111 insertions(+), 67 deletions(-) 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 826d5d9e..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,21 +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) { + 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/public_user/PublicUserService.kt b/server/src/main/kotlin/delta/codecharacter/server/user/public_user/PublicUserService.kt index 561d6164..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 @@ -11,6 +11,8 @@ import delta.codecharacter.dtos.UserStatsDto import delta.codecharacter.server.daily_challenge.DailyChallengeEntity import delta.codecharacter.server.exception.CustomException 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 @@ -26,6 +28,8 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR @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, @@ -54,25 +58,25 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR publicUserRepository.save(publicUser) } - fun updateTiers(publicUsers: List) { - publicUsers.forEach { user -> - if (publicUsers.indexOf(user) < tier1Players.toInt()) { + 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)) } } - } - - fun updateLeaderboardAfterPracticePhase() { - updateTiers(publicUserRepository.findAll()) + 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() { @@ -87,27 +91,36 @@ class PublicUserService(@Autowired private val publicUserRepository: PublicUserR PageRequest.of(0, topPlayer.toInt(), Sort.by(Sort.Order.asc("rating"))) ) topPlayersInTier2.forEach { users -> - publicUserRepository.save(users.copy(tier = TierTypeDto.TIER1)) + 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 -> - publicUserRepository.save(users.copy(tier = TierTypeDto.TIER2)) + 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.Order.desc("rating"))) - if (( - tier == TierTypeDto.TIER2 && - publicUserRepository.findAllByTier(TierTypeDto.TIER1, pageRequest).size == 0 - ) || - ( - tier == TierTypeDto.TIER1 && - publicUserRepository.findAllByTier(TierTypeDto.TIER2, pageRequest).size == 0 - ) - ) { - return listOf() - } - return publicUserRepository.findAllByTier(tier, pageRequest).map { + val publicUsers = + if (tier == null) { + publicUserRepository.findAll(pageRequest).content + } else { + publicUserRepository.findAllByTier(tier, pageRequest) + } + return publicUsers.map { LeaderboardEntryDto( user = PublicUserDto( 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/leaderboard/LeaderboardControllerIntegrationTest.kt b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt index f35ee966..331328c1 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardControllerIntegrationTest.kt @@ -21,7 +21,6 @@ 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 -import java.util.UUID @AutoConfigureMockMvc @SpringBootTest @@ -40,62 +39,85 @@ internal class LeaderboardControllerIntegrationTest(@Autowired val mockMvc: Mock @Test @WithMockCustomUser - fun `should get leaderboard`() { - val publicUserEntity = - TestAttributes.publicUser.copy(userId = UUID.randomUUID(), username = "opponent") - mongoTemplate.save(publicUserEntity) - - val leaderboardEntryDto = - LeaderboardEntryDto( - user = - PublicUserDto( - username = "TestUser", - name = "Test User", - country = "Test Country", - college = "Test College", - avatarId = 1, - tier = TierTypeDto.TIER_PRACTICE - ), - stats = - UserStatsDto( - rating = BigDecimal.valueOf(1000.0), - wins = 4, - losses = 2, - ties = 1, - ), + 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") { contentType = MediaType.APPLICATION_JSON }.andExpect { - status { is2xxSuccessful() } - content { contentType(MediaType.APPLICATION_JSON) } - content { listOf(leaderboardEntryDto) } - } + 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 return empty list when leaderboard not found`() { - mockMvc.get("/leaderboard") { contentType = MediaType.APPLICATION_JSON }.andExpect { - status { is2xxSuccessful() } - content { contentType(MediaType.APPLICATION_JSON) } - content { listOf() } - } + 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 empty list if all players belong to tier 1`() { - val publicUserEntity = - TestAttributes.publicUser.copy( - userId = UUID.randomUUID(), username = "opponent", tier = TierTypeDto.TIER1 + 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 + ), + ) ) - mongoTemplate.save(publicUserEntity) mockMvc.get("/leaderboard") { contentType = MediaType.APPLICATION_JSON }.andExpect { status { is2xxSuccessful() } content { contentType(MediaType.APPLICATION_JSON) } - content { listOf() } + 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 index 1ee4b8fa..a81daaae 100644 --- a/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardTest.kt +++ b/server/src/test/kotlin/delta/codecharacter/server/leaderboard/LeaderboardTest.kt @@ -10,6 +10,7 @@ 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 @@ -112,11 +113,15 @@ internal class LeaderboardTest { listOf(user3, user4) publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER1).forEach { user -> - assert(user.user.tier == TierTypeDto.TIER1) + assertThat(user.user.tier).isEqualTo(TierTypeDto.TIER1) } publicUserService.getLeaderboard(0, 10, TierTypeDto.TIER2).forEach { user -> - assert(user.user.tier == TierTypeDto.TIER2) + assertThat(user.user.tier).isEqualTo(TierTypeDto.TIER2) } + + verify { publicUserRepository.findAllByTier(TierTypeDto.TIER1, any()) } + verify { publicUserRepository.findAllByTier(TierTypeDto.TIER2, any()) } + confirmVerified(publicUserRepository) } @Test From ccc3c26a8a70e52a07aadc5cc96e9f714d44bab3 Mon Sep 17 00:00:00 2001 From: Ram-20062003 Date: Tue, 28 Feb 2023 03:24:33 +0530 Subject: [PATCH 18/18] fix: remove leaderBoardEnum --- .../codecharacter/server/leaderboard/LeaderBoardEnum.kt | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 server/src/main/kotlin/delta/codecharacter/server/leaderboard/LeaderBoardEnum.kt 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 -}