Skip to content

Commit

Permalink
what if we do the test 5 times
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin Berman committed Jan 21, 2025
1 parent 9ec28bc commit 1bd1af1
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public static Future<Void> sleep(Vertx vertx, long milliseconds) {
vertx = Vertx.currentContext().owner();
}
var promise = Promise.<Long>promise();
vertx.setTimer(milliseconds, promise::complete);
vertx.setTimer(milliseconds, promise::tryComplete);
return promise.future().mapEmpty();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ public void removeGameAndRecordReplay(@NotNull String gameId) {
if (gameContext.getStatus() == GameStatus.RUNNING) {
gameContext.loseBothPlayers();
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import net.demilich.metastone.game.behaviour.GameStateValueBehaviour;
import net.demilich.metastone.game.cards.Attribute;
import net.demilich.metastone.game.cards.Card;
import net.demilich.metastone.game.cards.CardArrayList;
import net.demilich.metastone.game.cards.CardCatalogue;
import net.demilich.metastone.game.decks.GameDeck;
import net.demilich.metastone.game.entities.Entity;
Expand Down Expand Up @@ -59,7 +58,8 @@
import static com.hiddenswitch.framework.Games.ADDRESS_IS_IN_GAME;
import static io.micrometer.core.instrument.Metrics.globalRegistry;
import static io.vertx.await.Async.await;
import static io.vertx.core.CompositeFuture.all;
import static io.vertx.core.Future.all;
import static io.vertx.core.Future.join;
import static java.util.stream.Collectors.toList;

/**
Expand All @@ -80,7 +80,7 @@ public class ServerGameContext extends GameContext implements Server {
private final transient Lock lock = new ReentrantLock();
private final transient Map<Integer, Promise<Client>> clientsReady = new ConcurrentHashMap<>();
private final transient List<Client> clients = new CopyOnWriteArrayList<>();
private final transient List<Promise> registrationsReady = new CopyOnWriteArrayList<>();
private final transient List<Promise<Void>> registrationsReady = new CopyOnWriteArrayList<>();
private final transient Promise<Void> initialization = Promise.promise();
private final Context context;
private final List<MessageConsumer<String>> inGameConsumers = new ArrayList<>();
Expand All @@ -91,13 +91,13 @@ public class ServerGameContext extends GameContext implements Server {
private final Deque<Trigger> gameTriggers = new ConcurrentLinkedDeque<>();
private final Scheduler scheduler;
private final AtomicInteger notificationCounter = new AtomicInteger(0);
private final AtomicBoolean closed = new AtomicBoolean();
private final AtomicBoolean endGameCalled = new AtomicBoolean();
private transient Long turnTimerId;
private boolean isRunning = false;
private Long timerStartTimeMillis;
private Long timerLengthMillis;
private boolean interrupted;
private final AtomicBoolean closed = new AtomicBoolean();
private final AtomicBoolean endGameCalled = new AtomicBoolean();

/**
* {@inheritDoc}
Expand Down Expand Up @@ -413,16 +413,16 @@ public void init() {
if (!clientsReady.values().stream().allMatch(fut -> fut.future().isComplete())) {
// If this is interrupted, it will bubble up to the general interrupt handler
try {
bothClientsReady = all(clientsReady.values().stream().map(Promise::future).collect(toList()));
var res = await(CompositeFuture.any(sleep(timeout), bothClientsReady));
bothClientsReady = Future.all(clientsReady.values().stream().map(Promise::future).collect(toList()));
var res = await(Future.any(sleep(timeout), bothClientsReady));

if (res.isComplete(0)) {
//timed out
bothClientsReady = Future.failedFuture(new TimeoutException("timed out waiting for user"));
} else if (res.isComplete(1)) {
// succeeded
} else {
bothClientsReady = Future.failedFuture("some other issue");
bothClientsReady = Future.failedFuture(bothClientsReady.cause());
}
} catch (Throwable t) {
bothClientsReady = Future.failedFuture(t);
Expand All @@ -436,7 +436,7 @@ public void init() {
// lead to a double loss
for (var entry : clientsReady.entrySet()) {
if (!entry.getValue().future().isComplete()) {
LOGGER.debug("init {}: Game prematurely ended because player id={} did not connect in {}ms", getGameId(), entry.getKey(), timeout);
LOGGER.error("init {}: Game prematurely ended because {} (player id={} did not connect in {}ms)", bothClientsReady.cause(), getGameId(), entry.getKey(), timeout);
getLogic().concede(entry.getKey());
}
}
Expand Down Expand Up @@ -511,7 +511,7 @@ public void init() {
}

// If this is interrupted, it'll bubble up to the general interrupt handler
var simultaneousMulligans = await(CompositeFuture.join(mulligansActive.future(), mulligansNonActive.future()));
var simultaneousMulligans = await(join(mulligansActive.future(), mulligansNonActive.future()));

// If we got this far, we should cancel the time
if (mulliganTimerId != null) {
Expand Down Expand Up @@ -864,7 +864,7 @@ protected void endGame() {
return;
}

LOGGER.error("endGame {}: calling end game", gameId);
LOGGER.debug("endGame {}: calling end game", gameId);

if (turnTimerId != null) {
scheduler.cancelTimer(turnTimerId);
Expand Down Expand Up @@ -1091,18 +1091,13 @@ public boolean isRunning() {
* Causes both players to lose the game. <b>Never deadlocks.</b>
* <p>
* This method is appropriate to call as a bail-out error procedure when the game context is being modified externally by editing or otherwise.
* <p>
* Ending the game requires the lock.
*/

public void loseBothPlayers() {
try {
currentContext.set(this);
getLogic().loseBothPlayers();
endGame();
} finally {
// This should be a no-op in the new engineering of this
}
// todo: should this suppress taking actions?
// maybe the rule should be that if your hero is destroyed, you cannot take actions, but that could have unintended side effects
currentContext.set(this);
getLogic().loseBothPlayers();
endGame();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.vertx.junit5.VertxTestContext;
import net.demilich.metastone.game.logic.GameLogic;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
Expand Down Expand Up @@ -613,19 +614,19 @@ public void testManyClientsMatchmakeAcrossInstances(VertxTestContext testContext
.onComplete(testContext.succeedingThenComplete());
}

@Test
@RepeatedTest(5)
public void testBotQueueWorksAfterDisconnect(Vertx vertx, VertxTestContext testContext) {
var client = new Client(vertx);
var queueId = UUID.randomUUID().toString();
System.getProperties().setProperty(Games.GAMES_DEFAULT_NO_ACTIVITY_TIMEOUT, "10000");
System.getProperties().setProperty(Games.GAMES_DEFAULT_NO_ACTIVITY_TIMEOUT, "4000");
startServices(vertx)
.compose(v -> Matchmaking.createQueue(createSinglePlayerQueue(queueId)))
.compose(v -> client.createAndLogin())
.compose(v -> client.matchmake(queueId))
.compose(response -> {
var gameId1 = response.getUnityConnection().getGameId();
return client.connectToGame()
.compose(v -> Environment.sleep(vertx, 10000L * 2))
.compose(v -> Environment.sleep(vertx, 4000L * 2))
.compose(v -> client.matchmake(queueId))
.compose(response2 -> {
var gameId2 = response2.getUnityConnection().getGameId();
Expand Down

0 comments on commit 1bd1af1

Please sign in to comment.