Skip to content

Commit

Permalink
Feature/update game info (#136)
Browse files Browse the repository at this point in the history
* feature: update game registration

* feature: update game registration usecase

* test: update game registration

* chore: coding format

* refactor: coding style

* fix: test failed issue
  • Loading branch information
lohas1107 authored Aug 6, 2023
1 parent d5a1af0 commit 4d0daa5
Show file tree
Hide file tree
Showing 10 changed files with 307 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ interface GameRegistrationRepository {
fun existsByUniqueName(uniqueName: String): Boolean
fun findGameRegistrations(): List<GameRegistration>
fun findById(id: Id): GameRegistration?
fun updateGame(gameRegistration: GameRegistration): GameRegistration
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package tw.waterballsa.gaas.application.usecases

import tw.waterballsa.gaas.application.eventbus.EventBus
import tw.waterballsa.gaas.application.repositories.GameRegistrationRepository
import tw.waterballsa.gaas.domain.GameRegistration
import tw.waterballsa.gaas.events.GameRegistrationUpdatedEvent
import tw.waterballsa.gaas.exceptions.NotFoundException.Companion.notFound
import tw.waterballsa.gaas.exceptions.PlatformException
import tw.waterballsa.gaas.exceptions.enums.PlatformError.GAME_EXISTS
import tw.waterballsa.gaas.exceptions.enums.PlatformError.GAME_NOT_FOUND
import javax.inject.Named

@Named
class UpdateGameRegistrationUseCase(
private val gameRegistrationRepository: GameRegistrationRepository,
private val eventBus: EventBus,
) {

fun execute(request: Request, presenter: Presenter) {
with(request) {
validateGameExist()
validateUniqueNameDuplicated()
val gameRegistration = updateGameRegistration()

val event = gameRegistration.toGameRegistrationUpdatedEvent()
presenter.present(event)
eventBus.broadcast(event)
}
}

private fun Request.validateGameExist() {
gameRegistrationRepository.findById(gameId)
?: throw notFound(GAME_NOT_FOUND, GameRegistration::class).id(gameId)
}

private fun Request.validateUniqueNameDuplicated() {
gameRegistrationRepository.findGameRegistrationByUniqueName(uniqueName)
?.takeIf { it.id != gameId }
?.let {
throw PlatformException(
GAME_EXISTS,
"$uniqueName already exists",
)
}
}

private fun Request.updateGameRegistration(): GameRegistration =
gameRegistrationRepository.updateGame(toGameRegistration())

data class Request(
val gameId: GameRegistration.Id,
val uniqueName: String,
val displayName: String,
val shortDescription: String,
val rule: String,
val imageUrl: String,
val minPlayers: Int,
val maxPlayers: Int,
val frontEndUrl: String,
val backEndUrl: String,
) {
fun toGameRegistration(): GameRegistration = GameRegistration(
gameId,
uniqueName,
displayName,
shortDescription,
rule,
imageUrl,
minPlayers,
maxPlayers,
frontEndUrl,
backEndUrl,
)
}
}

private fun GameRegistration.toGameRegistrationUpdatedEvent(): GameRegistrationUpdatedEvent =
GameRegistrationUpdatedEvent(
id!!,
uniqueName,
displayName,
shortDescription,
rule,
imageUrl,
minPlayers,
maxPlayers,
frontEndUrl,
backEndUrl,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package tw.waterballsa.gaas.events

import tw.waterballsa.gaas.domain.GameRegistration

class GameRegistrationUpdatedEvent(
val id: GameRegistration.Id,
val uniqueName: String,
val displayName: String,
val shortDescription: String,
val rule: String,
val imageUrl: String,
val minPlayers: Int,
val maxPlayers: Int,
val frontEndUrl: String,
val backEndUrl: String,
) : DomainEvent()
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@ import org.springframework.web.bind.annotation.*
import tw.waterballsa.gaas.application.usecases.GetGameRegistrationsUsecase
import tw.waterballsa.gaas.application.usecases.Presenter
import tw.waterballsa.gaas.application.usecases.RegisterGameUsecase
import tw.waterballsa.gaas.application.usecases.UpdateGameRegistrationUseCase
import tw.waterballsa.gaas.domain.GameRegistration
import tw.waterballsa.gaas.domain.GameRegistration.*
import tw.waterballsa.gaas.events.DomainEvent
import tw.waterballsa.gaas.events.RegisteredGameEvent
import tw.waterballsa.gaas.spring.controllers.GetGameRegistrationPresenter.*
import tw.waterballsa.gaas.spring.controllers.presenter.UpdateGameRegistrationPresenter
import tw.waterballsa.gaas.spring.controllers.viewmodel.UpdateGameRegistrationViewModel
import tw.waterballsa.gaas.spring.extensions.getEvent

@RestController
@RequestMapping("/games")
class GameRegistrationController(
private val registerGameUsecase: RegisterGameUsecase,
private val getGameRegistrationsUsecase: GetGameRegistrationsUsecase
private val getGameRegistrationsUsecase: GetGameRegistrationsUsecase,
private val updateGameRegistrationUseCase: UpdateGameRegistrationUseCase
) {

@PostMapping
Expand All @@ -36,6 +40,17 @@ class GameRegistrationController(
return presenter.viewModel
}

@PutMapping("/{gameId}")
fun updateGameRegistration(
@PathVariable gameId: String,
@RequestBody updateGameRegistrationRequest: UpdateGameRegistrationRequest
): UpdateGameRegistrationViewModel {
val request = updateGameRegistrationRequest.toRequest(gameId)
val presenter = UpdateGameRegistrationPresenter()
updateGameRegistrationUseCase.execute(request, presenter)
return presenter.viewModel
}

class RegisterGameRequest(
private val uniqueName: String,
private val displayName: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package tw.waterballsa.gaas.spring.controllers

import tw.waterballsa.gaas.application.usecases.UpdateGameRegistrationUseCase
import tw.waterballsa.gaas.domain.GameRegistration

data class UpdateGameRegistrationRequest(
private val uniqueName: String,
private val displayName: String,
private val shortDescription: String,
private val rule: String,
private val imageUrl: String,
private val minPlayers: Int,
private val maxPlayers: Int,
private val frontEndUrl: String,
private val backEndUrl: String,
) {
fun toRequest(gameId: String): UpdateGameRegistrationUseCase.Request = UpdateGameRegistrationUseCase.Request(
GameRegistration.Id(gameId),
uniqueName,
displayName,
shortDescription,
rule,
imageUrl,
minPlayers,
maxPlayers,
frontEndUrl,
backEndUrl
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package tw.waterballsa.gaas.spring.controllers.presenter

import tw.waterballsa.gaas.application.usecases.Presenter
import tw.waterballsa.gaas.events.DomainEvent
import tw.waterballsa.gaas.events.GameRegistrationUpdatedEvent
import tw.waterballsa.gaas.spring.controllers.viewmodel.UpdateGameRegistrationViewModel
import tw.waterballsa.gaas.spring.extensions.getEvent

class UpdateGameRegistrationPresenter : Presenter {

lateinit var viewModel: UpdateGameRegistrationViewModel
private set

override fun present(vararg events: DomainEvent) {
viewModel = events.getEvent(GameRegistrationUpdatedEvent::class)!!.toViewModel()
}

private fun GameRegistrationUpdatedEvent.toViewModel(): UpdateGameRegistrationViewModel =
UpdateGameRegistrationViewModel(
id,
uniqueName,
displayName,
shortDescription,
rule,
imageUrl,
minPlayers,
maxPlayers,
frontEndUrl,
backEndUrl
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package tw.waterballsa.gaas.spring.controllers.viewmodel

import tw.waterballsa.gaas.domain.GameRegistration

data class UpdateGameRegistrationViewModel(
val id: GameRegistration.Id,
val uniqueName: String,
val displayName: String,
val shortDescription: String,
val rule: String,
val imageUrl: String,
val minPlayers: Int,
val maxPlayers: Int,
val frontEndUrl: String,
val backEndUrl: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ class SpringGameRegistrationRepository(

override fun findById(id: Id): GameRegistration? =
gameRegistrationDAO.findById(id.value).mapOrNull(GameRegistrationData::toDomain)

override fun updateGame(gameRegistration: GameRegistration): GameRegistration =
gameRegistrationDAO.save(gameRegistration.toData()).toDomain()
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.http.MediaType.APPLICATION_JSON
import org.springframework.test.web.servlet.ResultActions
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
import tw.waterballsa.gaas.application.repositories.GameRegistrationRepository
import tw.waterballsa.gaas.domain.GameRegistration
import tw.waterballsa.gaas.spring.controllers.GetGameRegistrationPresenter.*
import tw.waterballsa.gaas.spring.controllers.RegisterGamePresenter.RegisterGameViewModel
import tw.waterballsa.gaas.spring.controllers.viewmodel.UpdateGameRegistrationViewModel
import tw.waterballsa.gaas.spring.it.AbstractSpringBootTest
import tw.waterballsa.gaas.spring.models.TestGameRegistrationRequest
import java.util.UUID.randomUUID
Expand Down Expand Up @@ -89,6 +89,65 @@ class GameRegistrationControllerTest @Autowired constructor(
getGamesViewModels.forEachIndexed { i, model -> model.validateWithGameRegistration(gameRegistrations[i]) }
}

@Test
fun givenBig2HasRegistered_whenUpdateGameRegistrationWithWrongId_thenShouldReturnGameRegistrationNotFound() {
givenGameHasRegistered("big2", "Big2")
whenUpdateGameRegistration(
"not-exist-game-id",
TestGameRegistrationRequest(
"big2",
"updated big2",
"updated big2 description",
"updated big2 rules",
"updated big2 image url",
3,
8,
"updated big2 frontend url",
"updated big2 backend url",
))
.thenShouldReturnGameRegistrationNotFound()
}

@Test
fun givenBig2AndUnoHasRegistered_whenUpdateBig2UniqueNameAsUno_thenShouldReturnGameAlreadyExists() {
val big2GameId = givenGameHasRegistered("big2", "Big2")
val unoGameId = givenGameHasRegistered("uno", "UNO")

whenUpdateGameRegistration(
big2GameId.value,
TestGameRegistrationRequest(
"uno",
"updated big2",
"updated big2 description",
"updated big2 rules",
"updated big2 image url",
3,
8,
"updated big2 frontend url",
"updated big2 backend url",
))
.thenShouldReturnGameAlreadyExists()
}

@Test
fun givenBig2HasRegistered_whenUpdateGameRegistrationWithRightIdAndUniqueName_thenUpdateGameRegistrationSuccessfully() {
val big2GameId = givenGameHasRegistered("big2", "Big2")
val updateGameRegistrationRequest = TestGameRegistrationRequest(
"big2",
"updated big2",
"updated big2 description",
"updated big2 rules",
"updated big2 image url",
3,
8,
"updated big2 frontend url",
"updated big2 backend url",
)

whenUpdateGameRegistration(big2GameId.value, updateGameRegistrationRequest)
.thenUpdateGameRegistrationSuccessfully(updateGameRegistrationRequest)
}

private fun createGameRegistrationRequest(
uniqueName: String,
displayName: String,
Expand Down Expand Up @@ -202,4 +261,45 @@ class GameRegistrationControllerTest @Autowired constructor(
assertThat(it.maxPlayers).isEqualTo(maxPlayers)
}
}

private fun givenGameHasRegistered(uniqueName: String, displayName: String): GameRegistration.Id {
val createGameRegistrationRequest = createGameRegistrationRequest(uniqueName, displayName)
return registerGameSuccessfully(createGameRegistrationRequest).id
}

private fun whenUpdateGameRegistration(gameId: String, updateGameRegistrationRequest: TestGameRegistrationRequest): ResultActions {
return mockMvc.perform(put("/games/$gameId")
.withJson(updateGameRegistrationRequest)
)
}

private fun ResultActions.thenShouldReturnGameRegistrationNotFound() {
andExpect(status().isNotFound)
.andExpect(jsonPath("$.message").value("Resource (GameRegistration) not found (id = Id(value=not-exist-game-id))."))
}

private fun ResultActions.thenShouldReturnGameAlreadyExists() {
andExpect(status().isBadRequest)
.andExpect(jsonPath("$.message").value("uno already exists"))
}

private fun ResultActions.thenUpdateGameRegistrationSuccessfully(request: TestGameRegistrationRequest) {
val view = andExpect(status().isOk)
.getBody(UpdateGameRegistrationViewModel::class.java)

gameRegistrationRepository.findById(view.id)
.also {
assertThat(it).isNotNull
assertThat(it!!.uniqueName).isEqualTo(request.uniqueName)
assertThat(it.displayName).isEqualTo(request.displayName)
assertThat(it.shortDescription).isEqualTo(request.shortDescription)
assertThat(it.rule).isEqualTo(request.rule)
assertThat(it.imageUrl).isEqualTo(request.imageUrl)
assertThat(it.minPlayers).isEqualTo(request.minPlayers)
assertThat(it.maxPlayers).isEqualTo(request.maxPlayers)
assertThat(it.frontEndUrl).isEqualTo(request.frontEndUrl)
assertThat(it.backEndUrl).isEqualTo(request.backEndUrl)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,13 @@ class RoomControllerTest @Autowired constructor(

@BeforeEach
fun setUp() {
userRepository.deleteAll()
roomRepository.deleteAll()

testUser = createUser(mockUser)
testGame = registerGame()
}

@AfterEach
fun cleanUp() {
roomRepository.deleteAll()
userRepository.deleteAll()
}

@Test
fun givenUserIsInTheLobby_WhenUserCreateARoom_ThenShouldSucceed() {
val request = createRoomRequest()
Expand Down

0 comments on commit 4d0daa5

Please sign in to comment.