Skip to content

Commit e4aeeb0

Browse files
committed
feat: include gameTimeout in plugin
1 parent 1b495d7 commit e4aeeb0

File tree

11 files changed

+55
-38
lines changed

11 files changed

+55
-38
lines changed

GUIDELINES.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@ This document captures development standards and architecture decisions of this
55
## Testing
66

77
Unsere Unittests nutzen das [Kotest-Framework](https://kotest.io) mit [JUnit](https://junit.org) im Hintergrund.
8-
Dabei setzen wir auf die [WordSpec](https://kotest.io/styles/#word-spec), da man damit semantisch übersichtlich sowohl einfache Tests als auch Behavior Driven Development umsetzen kann.
9-
10-
Bisherige Tests nutzen die StringSpec, welche jedoch schnell unübersichtlich wird da sie keine Verschachtelung erlaubt, und im server-modul gibt es noch einige JUnit5-Tests.
8+
Dabei setzen wir auf [WordSpec](https://kotest.io/styles/#word-spec),
9+
da man damit semantisch übersichtlich
10+
sowohl einfache Tests als auch Behavior Driven Development umsetzen kann.
11+
Für Tests von Algorithmen ohne Logik/Verhalten
12+
kann auch [FunSpec](https://kotest.io/styles/#fun-spec) nützlich sein
13+
14+
Viele Tests nutzen noch die StringSpec,
15+
welche jedoch schnell unübersichtlich wird,
16+
da sie keine Verschachtelung erlaubt.
17+
Im Server gibt es außerdem noch einige JUnit5-Tests.
1118
Diese sollten bei größeren Änderungen direkt zum neuen Stil migriert werden.
1219

1320
## XStream

helpers/test-client/src/sc/TestClient.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import java.io.IOException;
1919
import java.util.Arrays;
2020
import java.util.List;
21-
import java.util.ServiceLoader;
2221
import java.util.StringTokenizer;
2322
import java.util.concurrent.ExecutorService;
2423
import java.util.concurrent.Executors;
@@ -42,7 +41,7 @@
4241
public class TestClient extends XStreamClient {
4342
private static final Logger logger = (Logger) LoggerFactory.getLogger(TestClient.class);
4443

45-
private static final String gameType = IGamePlugin.loadPluginId();
44+
private static final IGamePlugin plugin = IGamePlugin.loadPlugin();
4645
private static final ClientPlayer[] players = {new ClientPlayer(), new ClientPlayer()};
4746
private static final File logDir = new File("log").getAbsoluteFile();
4847

@@ -281,8 +280,7 @@ protected void onObject(@NotNull ProtocolMessage message) {
281280
logger.error("{} crashed, look into {}", player.name, logDir);
282281
exit(2);
283282
}
284-
// TODO move timeout to GamePlugin and obtain it
285-
if (slept > 200.000) {
283+
if (slept > plugin.getGameTimeout()) {
286284
logger.error("The game seems to hang, exiting!");
287285
exit(2);
288286
}
@@ -332,7 +330,7 @@ private void prepareNewClients() {
332330
for (int i = 0; i < 2; i++)
333331
slots[(finishedTests + i) % 2] = new SlotDescriptor(players[i].name, players[i].canTimeout);
334332
logger.debug("Prepared client slots: " + Arrays.toString(slots));
335-
send(new PrepareGameRequest(gameType, slots[0], slots[1], false));
333+
send(new PrepareGameRequest(plugin.getId(), slots[0], slots[1], false));
336334
}
337335

338336
private static void exit(int status) {

plugin/src/client/sc/plugin2021/AbstractClient.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package sc.plugin2021
22

33
import org.slf4j.LoggerFactory
4+
import sc.api.plugins.IGamePlugin
45
import sc.api.plugins.IGameState
56
import sc.framework.plugins.protocol.MoveRequest
67
import sc.networking.clients.AbstractLobbyClientListener
@@ -102,7 +103,7 @@ abstract class AbstractClient(
102103
/** [start] and join any game with the appropriate [gameType]. */
103104
fun joinAnyGame() {
104105
start()
105-
client.joinRoomRequest(GamePlugin.PLUGIN_UUID)
106+
client.joinRoomRequest(GamePlugin.PLUGIN_ID)
106107
}
107108

108109
override fun onGameLeft(roomId: String) {

plugin/src/server/sc/plugin2021/Game.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import sc.shared.PlayerScore
1414
import sc.shared.ScoreCause
1515
import sc.shared.WinCondition
1616

17-
class Game(override val currentState: GameState = GameState()): AbstractGame<Player>(GamePlugin.PLUGIN_UUID) {
17+
class Game(override val currentState: GameState = GameState()): AbstractGame<Player>(GamePlugin.PLUGIN_ID) {
1818
companion object {
1919
val logger = LoggerFactory.getLogger(Game::class.java)
2020
}

plugin/src/server/sc/plugin2021/GamePlugin.kt

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,35 @@ package sc.plugin2021
33
import sc.api.plugins.IGameInstance
44
import sc.api.plugins.IGamePlugin
55
import sc.api.plugins.IGameState
6-
import sc.api.plugins.host.GameLoader
6+
import sc.plugin2021.util.Constants
77
import sc.plugins.PluginDescriptor
88
import sc.shared.ScoreAggregation
99
import sc.shared.ScoreDefinition
1010
import sc.shared.ScoreFragment
11-
import java.io.File
1211

13-
@PluginDescriptor(name = "Blokus", uuid = GamePlugin.PLUGIN_UUID)
12+
@PluginDescriptor(name = "Blokus", uuid = GamePlugin.PLUGIN_ID)
1413
class GamePlugin: IGamePlugin {
1514
companion object {
16-
const val PLUGIN_UUID = "swc_2021_blokus"
15+
const val PLUGIN_ID = "swc_2021_blokus"
16+
val scoreDefinition: ScoreDefinition =
17+
ScoreDefinition(arrayOf(
18+
ScoreFragment("Gewinner"),
19+
ScoreFragment("\u2205 Punkte", ScoreAggregation.AVERAGE)
20+
))
1721
}
1822

19-
override fun id() = PLUGIN_UUID
23+
override val id = PLUGIN_ID
24+
25+
override val scoreDefinition =
26+
Companion.scoreDefinition
27+
28+
override val gameTimeout: Int =
29+
Constants.GAME_TIMEOUT
2030

2131
override fun createGame(): IGameInstance =
2232
Game()
2333

2434
override fun createGameFromState(state: IGameState): IGameInstance =
2535
Game(state as GameState)
2636

27-
override val scoreDefinition: ScoreDefinition =
28-
ScoreDefinition(arrayOf(
29-
ScoreFragment("Gewinner"),
30-
ScoreFragment("\u2205 Punkte", ScoreAggregation.AVERAGE)
31-
))
32-
3337
}

plugin/src/shared/sc/plugin2021/util/Constants.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ object Constants {
2323
const val ROUND_LIMIT = 25
2424

2525
/** Zeit (in ms), die für einen Zug zur Verfügung steht. */
26-
const val SOFT_TIMEOUT = 2000L
26+
const val SOFT_TIMEOUT = 2_000
2727
/** Zeit (in ms), ab dem eine Zuganfrage abgebrochen wird. */
28-
const val HARD_TIMEOUT = 10000L
28+
const val HARD_TIMEOUT = 10_000
2929

30-
// Max game length: turns(ROUND_LIMIT * 2) * SOFT_TIMEOUT, one second buffer per round
30+
// Max game length: turns(=ROUND_LIMIT*2) * SOFT_TIMEOUT, one second buffer per round
3131
/** Zeit (in ms), die ein Spiel höchstens dauern sollte. */
3232
@JvmField
3333
val GAME_TIMEOUT = TOTAL_PIECE_SHAPES * COLORS * SOFT_TIMEOUT

plugin/src/test/sc/plugin2021/GameTest.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import sc.plugin2021.util.GameRuleLogic
1818
import sc.shared.PlayerScore
1919
import sc.shared.ScoreCause
2020
import java.math.BigDecimal
21+
import kotlin.time.ExperimentalTime
22+
import kotlin.time.milliseconds
2123

24+
@OptIn(ExperimentalTime::class)
2225
class GameTest: WordSpec({
2326
isolationMode = IsolationMode.SingleInstance
2427
val startGame = {
@@ -28,7 +31,7 @@ class GameTest: WordSpec({
2831
game.start()
2932
Pair(game, game.currentState)
3033
}
31-
"A Game start with two players" When {
34+
"A Game started with two players" When {
3235
"played normally" should {
3336
val (game, state) = startGame()
3437

@@ -47,7 +50,7 @@ class GameTest: WordSpec({
4750
}
4851
})
4952

50-
"finish without issues" {
53+
"finish without issues".config(invocationTimeout = Constants.GAME_TIMEOUT.milliseconds) {
5154
while (true) {
5255
try {
5356
val condition = game.checkWinCondition()

sdk/src/server-api/sc/api/plugins/IGamePlugin.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import sc.shared.ScoreDefinition
55
import java.util.ServiceLoader
66

77
interface IGamePlugin: IPlugin {
8-
fun id(): String
8+
val id: String
9+
val scoreDefinition: ScoreDefinition
10+
val gameTimeout: Int
11+
912
/** @return eine neues Spiel dieses Typs. */
1013
fun createGame(): IGameInstance
1114
fun createGameFromState(state: IGameState): IGameInstance
1215

13-
val scoreDefinition: ScoreDefinition
14-
1516
companion object {
1617
@JvmStatic
1718
fun loadPlugin(): IGamePlugin {
@@ -23,6 +24,6 @@ interface IGamePlugin: IPlugin {
2324

2425
@JvmStatic
2526
fun loadPluginId(): String =
26-
loadPlugin().id()
27+
loadPlugin().id
2728
}
2829
}

sdk/src/server-api/sc/framework/plugins/ActionTimeout.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ public class ActionTimeout {
2121
private long startTimestamp = 0;
2222
private long stopTimestamp = 0;
2323

24-
private static final long DEFAULT_HARD_TIMEOUT = 10000;
25-
private static final long DEFAULT_SOFT_TIMEOUT = 5000;
24+
private static final int DEFAULT_HARD_TIMEOUT = 10000;
25+
private static final int DEFAULT_SOFT_TIMEOUT = 5000;
2626

2727
private enum Status {
2828
NEW, STARTED, STOPPED
@@ -32,11 +32,11 @@ public ActionTimeout(boolean canTimeout) {
3232
this(canTimeout, DEFAULT_HARD_TIMEOUT, DEFAULT_SOFT_TIMEOUT);
3333
}
3434

35-
public ActionTimeout(boolean canTimeout, long hardTimeoutInMilliseconds) {
35+
public ActionTimeout(boolean canTimeout, int hardTimeoutInMilliseconds) {
3636
this(canTimeout, hardTimeoutInMilliseconds, hardTimeoutInMilliseconds);
3737
}
3838

39-
public ActionTimeout(boolean canTimeout, long hardTimeoutInMilliseconds, long softTimeoutInMilliseconds) {
39+
public ActionTimeout(boolean canTimeout, int hardTimeoutInMilliseconds, int softTimeoutInMilliseconds) {
4040
if (hardTimeoutInMilliseconds < softTimeoutInMilliseconds) {
4141
throw new IllegalArgumentException(
4242
"HardTimeout must be greater or equal the SoftTimeout");

server/test/sc/server/plugins/TestGame.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ data class TestGame(
5757
override fun loadGameInfo(gameInfo: Any) {}
5858

5959
override fun getTimeoutFor(player: Player): ActionTimeout =
60-
ActionTimeout(false, 100000000L, 20000000L)
60+
ActionTimeout(false)
6161

6262
companion object {
6363
private val logger = LoggerFactory.getLogger(TestGame::class.java)

0 commit comments

Comments
 (0)