forked from External/mage
tests: improved load tests (improved progress bar, added effects stats)
This commit is contained in:
parent
f5b901beb4
commit
3405b51aaf
7 changed files with 55 additions and 24 deletions
|
|
@ -62,7 +62,11 @@ public class GameView implements Serializable {
|
||||||
private final int turn;
|
private final int turn;
|
||||||
private boolean special = false;
|
private boolean special = false;
|
||||||
private final boolean rollbackTurnsAllowed;
|
private final boolean rollbackTurnsAllowed;
|
||||||
|
|
||||||
|
// for debug only
|
||||||
|
// TODO: implement and support in admin tools
|
||||||
private int totalErrorsCount;
|
private int totalErrorsCount;
|
||||||
|
private int totalEffectsCount;
|
||||||
|
|
||||||
public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) {
|
public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) {
|
||||||
Player createdForPlayer = null;
|
Player createdForPlayer = null;
|
||||||
|
|
@ -209,6 +213,7 @@ public class GameView implements Serializable {
|
||||||
}
|
}
|
||||||
this.rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed;
|
this.rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed;
|
||||||
this.totalErrorsCount = game.getTotalErrorsCount();
|
this.totalErrorsCount = game.getTotalErrorsCount();
|
||||||
|
this.totalEffectsCount = game.getTotalEffectsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPaid(UUID uuid, StackAbility stackAbility) {
|
private void checkPaid(UUID uuid, StackAbility stackAbility) {
|
||||||
|
|
@ -349,4 +354,8 @@ public class GameView implements Serializable {
|
||||||
public int getTotalErrorsCount() {
|
public int getTotalErrorsCount() {
|
||||||
return this.totalErrorsCount;
|
return this.totalErrorsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTotalEffectsCount() {
|
||||||
|
return this.totalEffectsCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1001,10 +1001,10 @@ public class MageServerImpl implements MageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleException(Exception ex) throws MageException {
|
public void handleException(Exception ex) throws MageException {
|
||||||
if (!ex.getMessage().equals("No message")) {
|
if (ex.getMessage() != null && !ex.getMessage().equals("No message")) {
|
||||||
logger.fatal("", ex);
|
|
||||||
throw new MageException("Server error: " + ex.getMessage());
|
throw new MageException("Server error: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
logger.error("unknown error", ex); // TODO: on logs spamming (e.g. connection problems) move it inside condition block above
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public class LoadCallbackClient implements CallbackClient {
|
||||||
|
|
||||||
private final String logsPrefix;
|
private final String logsPrefix;
|
||||||
private final Boolean showLogsAsHtml; // original game logs in HTML, but it can be converted to txt for more readable console
|
private final Boolean showLogsAsHtml; // original game logs in HTML, but it can be converted to txt for more readable console
|
||||||
private String globalProgress = ""; // progress [=20, +21, +17], AI game #9: ---
|
private String globalProgress = ""; // progress 33% [=20, +21, +17], AI game #9: ---
|
||||||
|
|
||||||
public LoadCallbackClient(boolean joinGameChat, String logsPrefix, Boolean showLogsAsHtml) {
|
public LoadCallbackClient(boolean joinGameChat, String logsPrefix, Boolean showLogsAsHtml) {
|
||||||
this.joinGameChat = joinGameChat;
|
this.joinGameChat = joinGameChat;
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,7 @@ public class LoadTest {
|
||||||
long randomSeed = RandomUtil.nextInt();
|
long randomSeed = RandomUtil.nextInt();
|
||||||
LoadTestGameResult gameResult = gameResults.createGame(0, "test game", randomSeed);
|
LoadTestGameResult gameResult = gameResults.createGame(0, "test game", randomSeed);
|
||||||
TasksProgress tasksProgress = new TasksProgress();
|
TasksProgress tasksProgress = new TasksProgress();
|
||||||
tasksProgress.update(1, true, 0);
|
tasksProgress.update(1, false, 0);
|
||||||
playTwoAIGame("Single AI game", 1, tasksProgress, randomSeed, "WGUBR", TEST_AI_RANDOM_DECK_SETS, gameResult);
|
playTwoAIGame("Single AI game", 1, tasksProgress, randomSeed, "WGUBR", TEST_AI_RANDOM_DECK_SETS, gameResult);
|
||||||
|
|
||||||
printGameResults(gameResults);
|
printGameResults(gameResults);
|
||||||
|
|
@ -333,12 +333,13 @@ public class LoadTest {
|
||||||
// play multiple AI games with CLIENT side code (catch every GameView changes from the server)
|
// play multiple AI games with CLIENT side code (catch every GameView changes from the server)
|
||||||
|
|
||||||
int singleGameSID = 0; // set sid for same deck games, set 0 for random decks
|
int singleGameSID = 0; // set sid for same deck games, set 0 for random decks
|
||||||
int gamesAmount = 5; // games per run
|
|
||||||
boolean isRunParallel = true; // can generate too much logs in test run, so search server logs for possible errors
|
int runTotalGames = 10;
|
||||||
|
int runMaxParallelGames = 5; // use 1 to run one by one (warning, it's limited by COMPUTER_MAX_THREADS_FOR_SIMULATIONS)
|
||||||
|
|
||||||
ExecutorService executerService;
|
ExecutorService executerService;
|
||||||
if (isRunParallel) {
|
if (runMaxParallelGames > 1) {
|
||||||
executerService = Executors.newFixedThreadPool(gamesAmount, new XmageThreadFactory(ThreadUtils.THREAD_PREFIX_TESTS_AI_VS_AI_GAMES));
|
executerService = Executors.newFixedThreadPool(runMaxParallelGames, new XmageThreadFactory(ThreadUtils.THREAD_PREFIX_TESTS_AI_VS_AI_GAMES));
|
||||||
} else {
|
} else {
|
||||||
executerService = Executors.newSingleThreadExecutor(new XmageThreadFactory(ThreadUtils.THREAD_PREFIX_TESTS_AI_VS_AI_GAMES));
|
executerService = Executors.newSingleThreadExecutor(new XmageThreadFactory(ThreadUtils.THREAD_PREFIX_TESTS_AI_VS_AI_GAMES));
|
||||||
}
|
}
|
||||||
|
|
@ -346,11 +347,11 @@ public class LoadTest {
|
||||||
// save random seeds for repeated results (in decks generating)
|
// save random seeds for repeated results (in decks generating)
|
||||||
List<Integer> seedsList = new ArrayList<>();
|
List<Integer> seedsList = new ArrayList<>();
|
||||||
if (singleGameSID != 0) {
|
if (singleGameSID != 0) {
|
||||||
for (int i = 1; i <= gamesAmount; i++) {
|
for (int i = 1; i <= runTotalGames; i++) {
|
||||||
seedsList.add(singleGameSID);
|
seedsList.add(singleGameSID);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 1; i <= gamesAmount; i++) {
|
for (int i = 1; i <= runTotalGames; i++) {
|
||||||
seedsList.add(RandomUtil.nextInt());
|
seedsList.add(RandomUtil.nextInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -360,7 +361,7 @@ public class LoadTest {
|
||||||
TasksProgress tasksProgress = new TasksProgress();
|
TasksProgress tasksProgress = new TasksProgress();
|
||||||
for (int i = 0; i < seedsList.size(); i++) {
|
for (int i = 0; i < seedsList.size(); i++) {
|
||||||
int gameIndex = i;
|
int gameIndex = i;
|
||||||
tasksProgress.update(gameIndex + 1, true, 0);
|
tasksProgress.update(gameIndex + 1, false, 0);
|
||||||
long randomSeed = seedsList.get(i);
|
long randomSeed = seedsList.get(i);
|
||||||
logger.info("Game " + (i + 1) + " of " + seedsList.size() + ", RANDOM seed: " + randomSeed);
|
logger.info("Game " + (i + 1) + " of " + seedsList.size() + ", RANDOM seed: " + randomSeed);
|
||||||
Future gameTask = executerService.submit(() -> {
|
Future gameTask = executerService.submit(() -> {
|
||||||
|
|
@ -369,12 +370,12 @@ public class LoadTest {
|
||||||
playTwoAIGame(gameName, gameIndex + 1, tasksProgress, randomSeed, TEST_AI_RANDOM_DECK_COLORS_FOR_AI_GAME, TEST_AI_RANDOM_DECK_SETS, gameResult);
|
playTwoAIGame(gameName, gameIndex + 1, tasksProgress, randomSeed, TEST_AI_RANDOM_DECK_COLORS_FOR_AI_GAME, TEST_AI_RANDOM_DECK_SETS, gameResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isRunParallel) {
|
if (runMaxParallelGames <= 1) {
|
||||||
// run one by one
|
// run one by one
|
||||||
gameTask.get();
|
gameTask.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isRunParallel) {
|
if (runMaxParallelGames > 1) {
|
||||||
// run parallel
|
// run parallel
|
||||||
executerService.shutdown();
|
executerService.shutdown();
|
||||||
Assert.assertTrue(executerService.awaitTermination(1, TimeUnit.HOURS));
|
Assert.assertTrue(executerService.awaitTermination(1, TimeUnit.HOURS));
|
||||||
|
|
@ -601,14 +602,18 @@ public class LoadTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInfo() {
|
private void updateInfo() {
|
||||||
// example: progress [=00, +01, +01, =12, =15, =01, +61]
|
// example: progress 70% [=00, +01, +01, =12, =15, =01, +61]
|
||||||
|
|
||||||
|
int completed = this.finishes.values().stream().mapToInt(x -> x ? 1 : 0).sum();
|
||||||
|
int completedPercent = this.finishes.size() == 0 ? 0 : completed * 100 / this.finishes.size();
|
||||||
|
|
||||||
String res = this.finishes.keySet().stream()
|
String res = this.finishes.keySet().stream()
|
||||||
.map(taskNumber -> String.format("%s%02d",
|
.map(taskNumber -> String.format("%s%02d",
|
||||||
this.finishes.getOrDefault(taskNumber, false) ? "=" : "+",
|
this.finishes.getOrDefault(taskNumber, false) ? "=" : "+",
|
||||||
this.turns.getOrDefault(taskNumber, 0)
|
this.turns.getOrDefault(taskNumber, 0)
|
||||||
))
|
))
|
||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
this.info = String.format("progress [%s]", res);
|
this.info = String.format("progress %d%% [%s]", completedPercent, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInfo() {
|
public String getInfo() {
|
||||||
|
|
@ -877,12 +882,16 @@ public class LoadTest {
|
||||||
public int getTotalErrorsCount() {
|
public int getTotalErrorsCount() {
|
||||||
return finalGameView == null ? 0 : this.finalGameView.getTotalErrorsCount();
|
return finalGameView == null ? 0 : this.finalGameView.getTotalErrorsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTotalEffectsCount() {
|
||||||
|
return finalGameView == null ? 0 : this.finalGameView.getTotalEffectsCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LoadTestGameResultsList extends HashMap<Integer, LoadTestGameResult> {
|
private static class LoadTestGameResultsList extends HashMap<Integer, LoadTestGameResult> {
|
||||||
|
|
||||||
private static final String tableFormatHeader = "|%-10s|%-15s|%-20s|%-10s|%-10s|%-10s|%-10s|%-15s|%-15s|%-10s|%n";
|
private static final String tableFormatHeader = "|%-10s|%-15s|%-20s|%-10s|%-10s|%-10s|%-10s|%-10s|%-15s|%-15s|%-10s|%n";
|
||||||
private static final String tableFormatData = "|%-10s|%15s|%20s|%10s|%10s|%10s|%10s|%15s|%15s|%10s|%n";
|
private static final String tableFormatData = "|%-10s|%15s|%20s|%10s|%10s|%10s|%10s|%10s|%15s|%15s|%10s|%n";
|
||||||
|
|
||||||
public LoadTestGameResult createGame(int index, String name, long randomSeed) {
|
public LoadTestGameResult createGame(int index, String name, long randomSeed) {
|
||||||
if (this.containsKey(index)) {
|
if (this.containsKey(index)) {
|
||||||
|
|
@ -899,6 +908,7 @@ public class LoadTest {
|
||||||
"name",
|
"name",
|
||||||
"random sid",
|
"random sid",
|
||||||
"errors",
|
"errors",
|
||||||
|
"effects",
|
||||||
"turn",
|
"turn",
|
||||||
"life p1",
|
"life p1",
|
||||||
"life p2",
|
"life p2",
|
||||||
|
|
@ -920,6 +930,7 @@ public class LoadTest {
|
||||||
gameResult.name, //"name",
|
gameResult.name, //"name",
|
||||||
String.valueOf(gameResult.randomSeed), // "random sid",
|
String.valueOf(gameResult.randomSeed), // "random sid",
|
||||||
String.valueOf(gameResult.getTotalErrorsCount()), // "errors",
|
String.valueOf(gameResult.getTotalErrorsCount()), // "errors",
|
||||||
|
String.valueOf(gameResult.getTotalEffectsCount()), // "effects",
|
||||||
String.valueOf(gameResult.getTurn()), //"turn",
|
String.valueOf(gameResult.getTurn()), //"turn",
|
||||||
String.valueOf(gameResult.getLife1()), //"life p1",
|
String.valueOf(gameResult.getLife1()), //"life p1",
|
||||||
String.valueOf(gameResult.getLife2()), //"life p2",
|
String.valueOf(gameResult.getLife2()), //"life p2",
|
||||||
|
|
@ -937,6 +948,7 @@ public class LoadTest {
|
||||||
String.valueOf(this.size()), //"name",
|
String.valueOf(this.size()), //"name",
|
||||||
"total, secs: " + String.format("%.3f", (float) this.getTotalDurationMs() / 1000), // "random sid",
|
"total, secs: " + String.format("%.3f", (float) this.getTotalDurationMs() / 1000), // "random sid",
|
||||||
String.valueOf(this.getTotalErrorsCount()), // errors
|
String.valueOf(this.getTotalErrorsCount()), // errors
|
||||||
|
String.valueOf(this.getAvgEffectsCount()), // effects
|
||||||
String.valueOf(this.getAvgTurn()), // turn
|
String.valueOf(this.getAvgTurn()), // turn
|
||||||
String.valueOf(this.getAvgLife1()), // life p1
|
String.valueOf(this.getAvgLife1()), // life p1
|
||||||
String.valueOf(this.getAvgLife2()), // life p2
|
String.valueOf(this.getAvgLife2()), // life p2
|
||||||
|
|
@ -952,6 +964,10 @@ public class LoadTest {
|
||||||
return this.values().stream().mapToInt(LoadTestGameResult::getTotalErrorsCount).sum();
|
return this.values().stream().mapToInt(LoadTestGameResult::getTotalErrorsCount).sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getAvgEffectsCount() {
|
||||||
|
return this.size() == 0 ? 0 : this.values().stream().mapToInt(LoadTestGameResult::getTotalEffectsCount).sum() / this.size();
|
||||||
|
}
|
||||||
|
|
||||||
private int getAvgTurn() {
|
private int getAvgTurn() {
|
||||||
return this.size() == 0 ? 0 : this.values().stream().mapToInt(LoadTestGameResult::getTurn).sum() / this.size();
|
return this.size() == 0 ? 0 : this.values().stream().mapToInt(LoadTestGameResult::getTurn).sum() / this.size();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1487,8 +1487,12 @@ public class ContinuousEffects implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTotalEffectsCount() {
|
||||||
|
return allEffectsLists.stream().mapToInt(ContinuousEffectsList::size).sum();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Effects: " + allEffectsLists.stream().mapToInt(ContinuousEffectsList::size).sum();
|
return "Effects: " + getTotalEffectsCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,9 @@ public interface Game extends MageItem, Serializable, Copyable<Game> {
|
||||||
|
|
||||||
Player getLosingPlayer();
|
Player getLosingPlayer();
|
||||||
|
|
||||||
int getTotalErrorsCount();
|
int getTotalErrorsCount(); // debug only
|
||||||
|
|
||||||
|
int getTotalEffectsCount(); // debug only
|
||||||
|
|
||||||
//client event methods
|
//client event methods
|
||||||
void addTableEventListener(Listener<TableEvent> listener);
|
void addTableEventListener(Listener<TableEvent> listener);
|
||||||
|
|
|
||||||
|
|
@ -3547,11 +3547,6 @@ public abstract class GameImpl implements Game {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void removeCreaturesFromCombat() {
|
|
||||||
//20091005 - 511.3
|
|
||||||
getCombat().endCombat(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContinuousEffects getContinuousEffects() {
|
public ContinuousEffects getContinuousEffects() {
|
||||||
return state.getContinuousEffects();
|
return state.getContinuousEffects();
|
||||||
|
|
@ -3694,6 +3689,11 @@ public abstract class GameImpl implements Game {
|
||||||
return this.totalErrorsCount.get();
|
return this.totalErrorsCount.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalEffectsCount() {
|
||||||
|
return this.getContinuousEffects().getTotalEffectsCount();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cheat(UUID ownerId, Map<Zone, String> commands) {
|
public void cheat(UUID ownerId, Map<Zone, String> commands) {
|
||||||
if (commands != null) {
|
if (commands != null) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue