diff --git a/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotConfig.scala b/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotConfig.scala index be32a29..002c436 100644 --- a/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotConfig.scala +++ b/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotConfig.scala @@ -20,8 +20,8 @@ object TournamentBotConfig: tournamentId <- env.get("TOURNAMENT_ID").filter(_.nonEmpty) token <- env.get("TOURNAMENT_BOT_TOKEN").filter(_.nonEmpty) botId <- jwtSubject(token) - serverUrl = env.getOrElse("TOURNAMENT_SERVER_URL", "http://localhost:8089") - difficulty = env.getOrElse("TOURNAMENT_BOT_DIFFICULTY", "medium") + serverUrl = env.getOrElse("TOURNAMENT_SERVER_URL", "http://localhost:8089") + difficulty = env.getOrElse("TOURNAMENT_BOT_DIFFICULTY", "medium") yield TournamentBotConfig(serverUrl, tournamentId, token, botId, difficulty) def jwtSubject(token: String): Option[String] = diff --git a/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala b/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala index 6455380..6c29e25 100644 --- a/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala +++ b/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala @@ -134,7 +134,8 @@ class TournamentBotGamePlayer: .foreach { line => parse(line).foreach: node => node.path("type").asText() match - case "move" => maybeMove(cfg, gameId, color, node.path("turn").asText(), "ongoing", node.path("fen").asText()) + case "move" => + maybeMove(cfg, gameId, color, node.path("turn").asText(), "ongoing", node.path("fen").asText()) case "gameEnd" => log.infof("Game %s ended — status=%s", gameId, node.path("status").asText()); done = true case _ => () } diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/domain/Tournament.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/domain/Tournament.scala index 5198c8b..523eb64 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/domain/Tournament.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/domain/Tournament.scala @@ -14,10 +14,10 @@ class Tournament: @Column(nullable = false) var fullName: String = uninitialized - var nbRounds: Int = 0 - var clockLimit: Int = 0 + var nbRounds: Int = 0 + var clockLimit: Int = 0 var clockIncrement: Int = 0 - var rated: Boolean = true + var rated: Boolean = true @Column(nullable = false) var status: String = "created" @@ -27,7 +27,7 @@ class Tournament: @Column(nullable = false) var createdBy: String = uninitialized - var startsAt: Instant = uninitialized - var winnerId: String = uninitialized + var startsAt: Instant = uninitialized + var winnerId: String = uninitialized var winnerName: String = uninitialized // scalafix:on diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentPairing.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentPairing.scala index 79a7d25..0b22f2d 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentPairing.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentPairing.scala @@ -15,8 +15,8 @@ class TournamentPairing: @Column(nullable = false) var tournamentId: String = uninitialized - var round: Int = 0 - var whiteId: String = uninitialized + var round: Int = 0 + var whiteId: String = uninitialized var whiteName: String = uninitialized @Column(nullable = false) @@ -25,7 +25,7 @@ class TournamentPairing: @Column(nullable = false) var blackName: String = uninitialized - var gameId: String = uninitialized - var winner: String = uninitialized + var gameId: String = uninitialized + var winner: String = uninitialized var moveList: String = uninitialized // scalafix:on diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentParticipant.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentParticipant.scala index 3b5651a..19306e2 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentParticipant.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/domain/TournamentParticipant.scala @@ -21,11 +21,11 @@ class TournamentParticipant: @Column(nullable = false) var botName: String = uninitialized - var points: Double = 0.0 + var points: Double = 0.0 var tieBreak: Double = 0.0 - var nbGames: Int = 0 - var wins: Int = 0 - var draws: Int = 0 - var losses: Int = 0 - var byeCount: Int = 0 + var nbGames: Int = 0 + var wins: Int = 0 + var draws: Int = 0 + var losses: Int = 0 + var byeCount: Int = 0 // scalafix:on diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/error/TournamentError.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/error/TournamentError.scala index 06c2734..40ab777 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/error/TournamentError.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/error/TournamentError.scala @@ -1,10 +1,10 @@ package de.nowchess.tournament.error enum TournamentError(val message: String): - case NotFound(id: String) extends TournamentError(s"Tournament $id not found") - case NotDirector extends TournamentError("Not the tournament director") + case NotFound(id: String) extends TournamentError(s"Tournament $id not found") + case NotDirector extends TournamentError("Not the tournament director") case WrongStatus(expected: String) extends TournamentError(s"Tournament must be in $expected status") - case AlreadyJoined extends TournamentError("Already joined this tournament") - case NotJoined extends TournamentError("Not joined this tournament") - case NotEnoughParticipants extends TournamentError("Need at least 2 participants to start") - case NotABot extends TournamentError("Only bot accounts can join tournaments") + case AlreadyJoined extends TournamentError("Already joined this tournament") + case NotJoined extends TournamentError("Not joined this tournament") + case NotEnoughParticipants extends TournamentError("Need at least 2 participants to start") + case NotABot extends TournamentError("Only bot accounts can join tournaments") diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/redis/GameResultStreamListener.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/redis/GameResultStreamListener.scala index 33c0e01..c634313 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/redis/GameResultStreamListener.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/redis/GameResultStreamListener.scala @@ -21,11 +21,11 @@ import java.util.UUID @ApplicationScoped class GameResultStreamListener: // scalafix:off DisableSyntax.var - @Inject var redis: RedisDataSource = uninitialized - @Inject var objectMapper: ObjectMapper = uninitialized - @Inject var tournamentService: TournamentService = uninitialized - @Inject var executor: ManagedExecutor = uninitialized - @Inject var redisConfig: RedisConfig = uninitialized + @Inject var redis: RedisDataSource = uninitialized + @Inject var objectMapper: ObjectMapper = uninitialized + @Inject var tournamentService: TournamentService = uninitialized + @Inject var executor: ManagedExecutor = uninitialized + @Inject var redisConfig: RedisConfig = uninitialized // scalafix:on private val log = Logger.getLogger(classOf[GameResultStreamListener]) @@ -37,8 +37,9 @@ class GameResultStreamListener: @PostConstruct def startListening(): Unit = createGroupIfAbsent() - executor.submit(new Runnable: - def run(): Unit = pollLoop() + executor.submit( + new Runnable: + def run(): Unit = pollLoop(), ) log.infof("Tournament result listener started (consumer=%s)", consumerId) @@ -49,17 +50,21 @@ class GameResultStreamListener: case Success(_) => () private def pollLoop(): Unit = + // scalafix:off DisableSyntax.var var running = true + // scalafix:on DisableSyntax.var while running do Try { - val messages = redis.stream(classOf[String]).xreadgroup( - groupName, - consumerId, - streamKey, - ">", - new XReadGroupArgs().count(10).block(java.time.Duration.ofSeconds(2)), - ) - if messages != null then messages.forEach(msg => handleMessage(msg)) + val messages = redis + .stream(classOf[String]) + .xreadgroup( + groupName, + consumerId, + streamKey, + ">", + new XReadGroupArgs().count(10).block(java.time.Duration.ofSeconds(2)), + ) + Option(messages).foreach(_.forEach(msg => handleMessage(msg))) } match case Failure(ex) if isInterrupted(ex) => Thread.currentThread().interrupt() @@ -68,8 +73,12 @@ class GameResultStreamListener: case Success(_) => () private def isInterrupted(ex: Throwable): Boolean = - ex.isInstanceOf[InterruptedException] || - (ex.getCause != null && ex.getCause.isInstanceOf[InterruptedException]) + ex match + case _: InterruptedException => true + case _ => + Option(ex.getCause) match + case Some(_: InterruptedException) => true + case _ => false private def handleMessage(msg: StreamMessage[String, String, String]): Unit = val json = msg.payload().get("data") diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/repository/PairingRepository.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/repository/PairingRepository.scala index 31edcd6..63da013 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/repository/PairingRepository.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/repository/PairingRepository.scala @@ -41,7 +41,7 @@ class PairingRepository: .headOption def persist(p: TournamentPairing): TournamentPairing = - if p.id == null then + if Option(p.id).isEmpty then em.persist(p) p else em.merge(p) diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/repository/ParticipantRepository.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/repository/ParticipantRepository.scala index d9b6ba6..e77e30e 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/repository/ParticipantRepository.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/repository/ParticipantRepository.scala @@ -34,7 +34,7 @@ class ParticipantRepository: .headOption def persist(p: TournamentParticipant): TournamentParticipant = - if p.id == null then + if Option(p.id).isEmpty then em.persist(p) p else em.merge(p) diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/resource/TournamentResource.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/resource/TournamentResource.scala index a33165d..9925812 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/resource/TournamentResource.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/resource/TournamentResource.scala @@ -119,9 +119,13 @@ class TournamentResource: tournamentService.get(id) match case None => Response.status(Response.Status.NOT_FOUND).entity("").build() case Some(_) => - val ndjson = tournamentService.getResults(id).take(nb).map { r => - s"""{"rank":${r.rank},"points":${r.points},"tieBreak":${r.tieBreak},"bot":{"id":"${r.bot.id}","name":"${r.bot.name}"},"nbGames":${r.nbGames},"wins":${r.wins},"draws":${r.draws},"losses":${r.losses}}""" - }.mkString("\n") + val ndjson = tournamentService + .getResults(id) + .take(nb) + .map { r => + s"""{"rank":${r.rank},"points":${r.points},"tieBreak":${r.tieBreak},"bot":{"id":"${r.bot.id}","name":"${r.bot.name}"},"nbGames":${r.nbGames},"wins":${r.wins},"draws":${r.draws},"losses":${r.losses}}""" + } + .mkString("\n") Response.ok(ndjson).`type`("application/x-ndjson").build() @GET diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/service/SwissPairingService.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/service/SwissPairingService.scala index cf2fa01..51720d3 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/service/SwissPairingService.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/service/SwissPairingService.scala @@ -1,6 +1,6 @@ package de.nowchess.tournament.service -import de.nowchess.tournament.domain.{TournamentParticipant, TournamentPairing} +import de.nowchess.tournament.domain.{TournamentPairing, TournamentParticipant} import java.util.concurrent.ThreadLocalRandom object SwissPairingService: @@ -9,9 +9,9 @@ object SwissPairingService: participants: List[TournamentParticipant], pastPairings: List[TournamentPairing], ): (List[(TournamentParticipant, TournamentParticipant)], Option[TournamentParticipant]) = - val sorted = sortParticipants(participants) + val sorted = sortParticipants(participants) val (remaining, byeOpt) = extractByePlayer(sorted) - val pairs = buildPairs(remaining, pastPairings) + val pairs = buildPairs(remaining, pastPairings) (pairs, byeOpt) private def sortParticipants(participants: List[TournamentParticipant]): List[TournamentParticipant] = @@ -37,16 +37,21 @@ object SwissPairingService: ): List[(TournamentParticipant, TournamentParticipant)] = val arr = players.toArray resolveConflicts(arr, pastPairings) - arr.grouped(2).flatMap { - case Array(a, b) => Some(assignColors(a, b)) - case _ => None - }.toList + arr + .grouped(2) + .flatMap { + case Array(a, b) => Some(assignColors(a, b)) + case _ => None + } + .toList private def resolveConflicts(arr: Array[TournamentParticipant], pastPairings: List[TournamentPairing]): Unit = + // scalafix:off DisableSyntax.var var i = 0 + // scalafix:on DisableSyntax.var while i < arr.length - 1 do if havePlayedBefore(arr(i), arr(i + 1), pastPairings) && i + 2 < arr.length then - val tmp = arr(i + 1) + val tmp = arr(i + 1) arr(i + 1) = arr(i + 2) arr(i + 2) = tmp i += 2 diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentService.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentService.scala index e34f06d..95d86bb 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentService.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentService.scala @@ -3,7 +3,16 @@ package de.nowchess.tournament.service import de.nowchess.tournament.client.{CoreCreateGameRequest, CoreGameClient, CorePlayerInfo, CoreTimeControl} import de.nowchess.tournament.config.RedisConfig import de.nowchess.tournament.domain.{Tournament, TournamentPairing, TournamentParticipant} -import de.nowchess.tournament.dto.{BotRef, Clock, CreateTournamentForm, PairingDto, ResultDto, Standing, TournamentDto, Variant} +import de.nowchess.tournament.dto.{ + BotRef, + Clock, + CreateTournamentForm, + PairingDto, + ResultDto, + Standing, + TournamentDto, + Variant, +} import de.nowchess.tournament.error.TournamentError import de.nowchess.tournament.repository.{PairingRepository, ParticipantRepository, TournamentRepository} import io.quarkus.redis.datasource.RedisDataSource @@ -66,8 +75,7 @@ class TournamentService: t <- tournamentRepository.findOptById(id).toRight(TournamentError.NotFound(id)) _ <- Either.cond(t.createdBy == userId, (), TournamentError.NotDirector) _ <- Either.cond(t.status == "created", (), TournamentError.WrongStatus("created")) - yield - tournamentRepository.delete(t) + yield tournamentRepository.delete(t) @Transactional def join(id: String, botId: String, botName: String): Either[TournamentError, Unit] = @@ -115,7 +123,7 @@ class TournamentService: Either.cond(ps.size >= 2, ps, TournamentError.NotEnoughParticipants) private def startRound(t: Tournament, round: Int, participants: List[TournamentParticipant]): Unit = - val pastPairings = pairingRepository.findByTournamentId(t.id) + val pastPairings = pairingRepository.findByTournamentId(t.id) val (pairs, byeOpt) = SwissPairingService.computePairings(participants, pastPairings) byeOpt.foreach(bye => createByePairing(t.id, round, bye)) pairs.foreach { case (white, black) => createRealPairing(t.id, round, white, black, t) } @@ -159,8 +167,16 @@ class TournamentService: pairing.blackName = black.botName pairing.gameId = resp.gameId pairingRepository.persist(pairing) - streamManager.publishToBot(tournamentId, white.botId, s"""{"type":"gameStart","round":$round,"gameId":"${resp.gameId}","color":"white"}""") - streamManager.publishToBot(tournamentId, black.botId, s"""{"type":"gameStart","round":$round,"gameId":"${resp.gameId}","color":"black"}""") + streamManager.publishToBot( + tournamentId, + white.botId, + s"""{"type":"gameStart","round":$round,"gameId":"${resp.gameId}","color":"white"}""", + ) + streamManager.publishToBot( + tournamentId, + black.botId, + s"""{"type":"gameStart","round":$round,"gameId":"${resp.gameId}","color":"black"}""", + ) publishBotGameStart(white.botName, resp.gameId, "white", white.botId) publishBotGameStart(black.botName, resp.gameId, "black", black.botId) @@ -171,7 +187,8 @@ class TournamentService: botAccountId: String, ): Unit = val channel = s"${redisConfig.prefix}:bot:$botName:events" - val payload = s"""{"type":"gameStart","gameId":"$gameId","playingAs":"$playingAs","difficulty":1500,"botAccountId":"$botAccountId"}""" + val payload = + s"""{"type":"gameStart","gameId":"$gameId","playingAs":"$playingAs","difficulty":1500,"botAccountId":"$botAccountId"}""" Try(redis.pubsub(classOf[String]).publish(channel, payload)) match case Failure(ex) => log.warnf(ex, "Failed to publish gameStart to bot channel %s", channel) case Success(_) => () @@ -212,7 +229,7 @@ class TournamentService: private def checkRoundCompletion(tournamentId: String): Unit = tournamentRepository.findOptById(tournamentId).foreach { t => val roundPairings = pairingRepository.findByTournamentIdAndRound(tournamentId, t.currentRound) - val allDone = roundPairings.nonEmpty && roundPairings.forall(p => Option(p.winner).isDefined) + val allDone = roundPairings.nonEmpty && roundPairings.forall(p => Option(p.winner).isDefined) if allDone then onRoundComplete(t) } @@ -282,7 +299,7 @@ class TournamentService: status = t.status, round = t.currentRound, standing = Standing(1, standings), - winner = if t.winnerId != null then Some(BotRef(t.winnerId, t.winnerName)) else None, + winner = Option(t.winnerId).map(id => BotRef(id, t.winnerName)), ) private def toPairingDto(p: TournamentPairing): PairingDto = diff --git a/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentStreamManager.scala b/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentStreamManager.scala index 8204d44..2379b24 100644 --- a/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentStreamManager.scala +++ b/modules/tournament/src/main/scala/de/nowchess/tournament/service/TournamentStreamManager.scala @@ -14,8 +14,12 @@ class TournamentStreamManager: private def botKey(tournamentId: String, botId: String): String = s"${tournamentId}:${botId}" def register(tournamentId: String, botId: String, emitter: MultiEmitter[? >: String]): Unit = - tournamentEmitters.computeIfAbsent(tournamentId, _ => new CopyOnWriteArrayList[MultiEmitter[? >: String]]()).add(emitter) - botEmitters.computeIfAbsent(botKey(tournamentId, botId), _ => new CopyOnWriteArrayList[MultiEmitter[? >: String]]()).add(emitter) + tournamentEmitters + .computeIfAbsent(tournamentId, _ => new CopyOnWriteArrayList[MultiEmitter[? >: String]]()) + .add(emitter) + botEmitters + .computeIfAbsent(botKey(tournamentId, botId), _ => new CopyOnWriteArrayList[MultiEmitter[? >: String]]()) + .add(emitter) def unregister(tournamentId: String, botId: String, emitter: MultiEmitter[? >: String]): Unit = Option(tournamentEmitters.get(tournamentId)).foreach(_.remove(emitter)) diff --git a/modules/tournament/src/test/scala/de/nowchess/tournament/resource/H2TestProfile.scala b/modules/tournament/src/test/scala/de/nowchess/tournament/resource/H2TestProfile.scala index 951ea49..6777080 100644 --- a/modules/tournament/src/test/scala/de/nowchess/tournament/resource/H2TestProfile.scala +++ b/modules/tournament/src/test/scala/de/nowchess/tournament/resource/H2TestProfile.scala @@ -7,9 +7,14 @@ class H2TestProfile extends QuarkusTestProfile: override def getConfigOverrides(): JMap[String, String] = JMap.of( - "quarkus.datasource.db-kind", "h2", - "quarkus.datasource.jdbc.url", "jdbc:h2:mem:nowchess-tournament;DB_CLOSE_DELAY=-1", - "quarkus.datasource.username", "sa", - "quarkus.datasource.password", "", - "quarkus.hibernate-orm.schema-management.strategy", "drop-and-create", + "quarkus.datasource.db-kind", + "h2", + "quarkus.datasource.jdbc.url", + "jdbc:h2:mem:nowchess-tournament;DB_CLOSE_DELAY=-1", + "quarkus.datasource.username", + "sa", + "quarkus.datasource.password", + "", + "quarkus.hibernate-orm.schema-management.strategy", + "drop-and-create", ) diff --git a/modules/tournament/src/test/scala/de/nowchess/tournament/resource/TournamentResourceTest.scala b/modules/tournament/src/test/scala/de/nowchess/tournament/resource/TournamentResourceTest.scala index de159db..830748a 100644 --- a/modules/tournament/src/test/scala/de/nowchess/tournament/resource/TournamentResourceTest.scala +++ b/modules/tournament/src/test/scala/de/nowchess/tournament/resource/TournamentResourceTest.scala @@ -46,8 +46,12 @@ class TournamentResourceTest: .formParam("clockLimit", 300) .formParam("clockIncrement", 5) .formParam("rated", true) - .when().post("/api/tournament") - .`then`().statusCode(201).extract().path[String]("id") + .when() + .post("/api/tournament") + .`then`() + .statusCode(201) + .extract() + .path[String]("id") private def postAndCheck(token: String, path: String, expectedStatus: Int): ValidatableResponse = authed(token).when().post(path).`then`().statusCode(expectedStatus) @@ -70,25 +74,35 @@ class TournamentResourceTest: .formParam("clockLimit", 300) .formParam("clockIncrement", 5) .formParam("rated", true) - .when().post("/api/tournament") - .`then`().statusCode(201) + .when() + .post("/api/tournament") + .`then`() + .statusCode(201) .body("fullName", is("Test Tour")) .body("status", is("created")) @Test def returns401WhenUnauthenticated(): Unit = - RestAssured.`given`().contentType(ContentType.URLENC) + RestAssured + .`given`() + .contentType(ContentType.URLENC) .formParam("name", "Test Tour") .formParam("nbRounds", 3) .formParam("clockLimit", 300) .formParam("clockIncrement", 5) - .when().post("/api/tournament") - .`then`().statusCode(401) + .when() + .post("/api/tournament") + .`then`() + .statusCode(401) @Test def returnsEmptyListsOnFreshStart(): Unit = - RestAssured.`given`().when().get("/api/tournament") - .`then`().statusCode(200) + RestAssured + .`given`() + .when() + .get("/api/tournament") + .`then`() + .statusCode(200) .body("created", notNullValue()) .body("started", notNullValue()) .body("finished", notNullValue()) @@ -96,8 +110,12 @@ class TournamentResourceTest: @Test def returnsCreatedTournamentInCreatedList(): Unit = val id = createTournament(directorToken("director-list"), "ListTour") - RestAssured.`given`().when().get("/api/tournament") - .`then`().statusCode(200) + RestAssured + .`given`() + .when() + .get("/api/tournament") + .`then`() + .statusCode(200) .body("created.id", hasItem(id)) @Test @@ -107,8 +125,12 @@ class TournamentResourceTest: @Test def returnsTournamentWithStandings(): Unit = val id = createTournament(directorToken("dir-get"), "GetTour") - RestAssured.`given`().when().get(s"/api/tournament/$id") - .`then`().statusCode(200) + RestAssured + .`given`() + .when() + .get(s"/api/tournament/$id") + .`then`() + .statusCode(200) .body("id", is(id)) .body("standing", notNullValue()) @@ -136,8 +158,10 @@ class TournamentResourceTest: def botJoinsSuccessfully(): Unit = val id = createTournament(directorToken("dir-join"), "JoinTour") authed(botToken("joinbot-1", "JoinBot1")) - .when().post(s"/api/tournament/$id/join") - .`then`().statusCode(200) + .when() + .post(s"/api/tournament/$id/join") + .`then`() + .statusCode(200) .body("ok", is(true)) @Test @@ -166,8 +190,11 @@ class TournamentResourceTest: val id = createTournament(directorToken("dir-wd"), "WdTour") val bt = botToken("wdbot-1", "WdBot1") botJoin(id, "wdbot-1", "WdBot1") - authed(bt).when().post(s"/api/tournament/$id/withdraw") - .`then`().statusCode(200) + authed(bt) + .when() + .post(s"/api/tournament/$id/withdraw") + .`then`() + .statusCode(200) .body("ok", is(true)) @Test @@ -201,8 +228,12 @@ class TournamentResourceTest: @Test def resultsReturns200WithNdjsonContentType(): Unit = val id = createTournament(directorToken("dir-res"), "ResTour") - RestAssured.`given`().when().get(s"/api/tournament/$id/results") - .`then`().statusCode(200) + RestAssured + .`given`() + .when() + .get(s"/api/tournament/$id/results") + .`then`() + .statusCode(200) .contentType("application/x-ndjson") @Test @@ -226,8 +257,11 @@ class TournamentResourceTest: @Test def returnsNdjsonWhenAcceptApplicationXNdjson(): Unit = val id = createTournament(directorToken("dir-ndjson"), "NdjsonTour") - RestAssured.`given`() + RestAssured + .`given`() .header("Accept", "application/x-ndjson") - .when().get(s"/api/tournament/$id/export/games") - .`then`().statusCode(200) + .when() + .get(s"/api/tournament/$id/export/games") + .`then`() + .statusCode(200) .contentType("application/x-ndjson") diff --git a/modules/tournament/src/test/scala/de/nowchess/tournament/service/SwissPairingServiceTest.scala b/modules/tournament/src/test/scala/de/nowchess/tournament/service/SwissPairingServiceTest.scala index 9b03166..ae58c8c 100644 --- a/modules/tournament/src/test/scala/de/nowchess/tournament/service/SwissPairingServiceTest.scala +++ b/modules/tournament/src/test/scala/de/nowchess/tournament/service/SwissPairingServiceTest.scala @@ -6,7 +6,12 @@ import org.junit.jupiter.api.Assertions.* class SwissPairingServiceTest: - private def makeParticipant(botId: String, botName: String, points: Double = 0.0, byeCount: Int = 0): TournamentParticipant = + private def makeParticipant( + botId: String, + botName: String, + points: Double = 0.0, + byeCount: Int = 0, + ): TournamentParticipant = val p = new TournamentParticipant() p.botId = botId p.botName = botName @@ -16,21 +21,21 @@ class SwissPairingServiceTest: @Test def pairs2PlayersRandomlyAssignsColors(): Unit = - val p1 = makeParticipant("b1", "BotOne") - val p2 = makeParticipant("b2", "BotTwo") + val p1 = makeParticipant("b1", "BotOne") + val p2 = makeParticipant("b2", "BotTwo") val (pairs, bye) = SwissPairingService.computePairings(List(p1, p2), Nil) assertEquals(1, pairs.size) assertTrue(bye.isEmpty) val (white, black) = pairs.head - val ids = Set(white.botId, black.botId) + val ids = Set(white.botId, black.botId) assertEquals(Set("b1", "b2"), ids) @Test def pairs4PlayersTopVsEachOther(): Unit = - val p1 = makeParticipant("b1", "A", points = 2.0) - val p2 = makeParticipant("b2", "B", points = 1.5) - val p3 = makeParticipant("b3", "C", points = 1.0) - val p4 = makeParticipant("b4", "D", points = 0.0) + val p1 = makeParticipant("b1", "A", points = 2.0) + val p2 = makeParticipant("b2", "B", points = 1.5) + val p3 = makeParticipant("b3", "C", points = 1.0) + val p4 = makeParticipant("b4", "D", points = 0.0) val (pairs, bye) = SwissPairingService.computePairings(List(p1, p2, p3, p4), Nil) assertEquals(2, pairs.size) assertTrue(bye.isEmpty) @@ -41,9 +46,9 @@ class SwissPairingServiceTest: @Test def oddCountLowestRankedGetsBye(): Unit = - val p1 = makeParticipant("b1", "A", points = 2.0) - val p2 = makeParticipant("b2", "B", points = 1.0) - val p3 = makeParticipant("b3", "C", points = 0.0) + val p1 = makeParticipant("b1", "A", points = 2.0) + val p2 = makeParticipant("b2", "B", points = 1.0) + val p3 = makeParticipant("b3", "C", points = 0.0) val (pairs, bye) = SwissPairingService.computePairings(List(p1, p2, p3), Nil) assertEquals(1, pairs.size) assertTrue(bye.isDefined) @@ -51,22 +56,22 @@ class SwissPairingServiceTest: @Test def avoidsRematchSwapsWhenPairAlreadyPlayed(): Unit = - val p1 = makeParticipant("b1", "A", points = 2.0) - val p2 = makeParticipant("b2", "B", points = 1.5) - val p3 = makeParticipant("b3", "C", points = 1.5) - val p4 = makeParticipant("b4", "D", points = 0.0) + val p1 = makeParticipant("b1", "A", points = 2.0) + val p2 = makeParticipant("b2", "B", points = 1.5) + val p3 = makeParticipant("b3", "C", points = 1.5) + val p4 = makeParticipant("b4", "D", points = 0.0) val pastPairing = new TournamentPairing() pastPairing.whiteId = "b1" pastPairing.blackId = "b2" val (pairs, _) = SwissPairingService.computePairings(List(p1, p2, p3, p4), List(pastPairing)) - val pair1Ids = Set(pairs(0)._1.botId, pairs(0)._2.botId) + val pair1Ids = Set(pairs(0)._1.botId, pairs(0)._2.botId) assertFalse(pair1Ids == Set("b1", "b2"), "b1 and b2 should not be paired again") @Test def playerWithFewerByesGetsTheByeFirst(): Unit = - val p1 = makeParticipant("b1", "A", points = 1.0, byeCount = 1) - val p2 = makeParticipant("b2", "B", points = 0.5, byeCount = 0) - val p3 = makeParticipant("b3", "C", points = 0.0, byeCount = 0) + val p1 = makeParticipant("b1", "A", points = 1.0, byeCount = 1) + val p2 = makeParticipant("b2", "B", points = 0.5, byeCount = 0) + val p3 = makeParticipant("b3", "C", points = 0.0, byeCount = 0) val (pairs, bye) = SwissPairingService.computePairings(List(p1, p2, p3), Nil) assertEquals(1, pairs.size) assertTrue(bye.isDefined)