package org.mage.test.load;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckCardLists;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.constants.ColoredManaSymbol;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchOptions;
import mage.player.ai.ComputerPlayer;
import mage.remote.Connection;
import mage.remote.Session;
import mage.remote.SessionImpl;
import mage.cards.Sets;
import mage.view.GameTypeView;
import mage.view.TableView;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.cards.decks.DeckCardInfo;
/**
* Intended to test Mage server under different load patterns.
*
* These tests do use server started separately, so Mage server should be started before running them.
* In case you want to debug these tests, use -Ddebug.mage that would disable client-server request timeout.
*
* Then it's also better to use -Xms256M -Xmx512M JVM options for these stests.
*
* @author noxx
*/
public class LoadTest {
/**
* Logger for tests
*/
private static final Logger log = Logger.getLogger(LoadTest.class);
/**
* First player's username
*/
private static final String TEST_USER_NAME = "player";
/**
* Second player's username
*/
private static final String TEST_USER_NAME_2 = "opponent";
/**
* Server connection setting.
*/
private static final String TEST_SERVER = "localhost";
/**
* Server connection setting.
*/
private static final int TEST_PORT = 17171;
/**
* Server connection setting.
*/
private static final String TEST_PROXY_TYPE = "None";
/**
* Determines how many times test will be executed in a row.
*/
private static final int EXECUTION_COUNT = 100;
/**
* Determines how many times test will be executed in a row.
*/
private static final int EXECUTION_COUNT_PLAY_GAME = 100;
/**
* Tests connecting with two players, creating game and starting it.
*
* Executes the test EXECUTION_COUNT times.
*
* @throws Exception
*/
@Test
@Ignore
public void testStartGame() throws Exception {
DeckCardLists deckList = createDeck();
for (int i = 0; i < EXECUTION_COUNT; i++) {
Connection connection = createConnection(TEST_USER_NAME + i);
SimpleMageClient mageClient = new SimpleMageClient();
Session session = new SessionImpl(mageClient);
session.connect(connection);
UUID roomId = session.getMainRoomId();
GameTypeView gameTypeView = session.getGameTypes().get(0);
log.info("Game type view: " + gameTypeView.getName());
MatchOptions options = createGameOptions(gameTypeView, session);
TableView table = session.createTable(roomId, options);
if (!session.joinTable(roomId, table.getTableId(), TEST_USER_NAME + i, "Human", 1, deckList,"")) {
log.error("Error while joining table");
Assert.assertTrue("Error while joining table", false);
return;
}
/*** Connect with a second player ***/
Connection connection2 = createConnection(TEST_USER_NAME_2 + i);
SimpleMageClient mageClient2 = new SimpleMageClient();
Session session2 = new SessionImpl(mageClient2);
session2.connect(connection2);
UUID roomId2 = session2.getMainRoomId();
// connect to the table with the same deck
if (!session2.joinTable(roomId2, table.getTableId(), TEST_USER_NAME_2 + i, "Human", 1, deckList,"")) {
log.error("Error while joining table");
Assert.assertTrue("Error while joining table", false);
return;
}
/*** Start game ***/
session.startMatch(roomId, table.getTableId());
Thread.sleep(100);
}
}
/**
* Tests 10 simple games played one after another.
*/
@Test
@Ignore
public void testSimpleGame() throws Exception {
final DeckCardLists deckList = createDeck();
for (int i = 0; i < EXECUTION_COUNT_PLAY_GAME; i++) {
final int j = i;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
testSimpleGame0(deckList, j);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
t.join();
}
}
/**
* Tests simple game till the end (game over).
* Players do nothing but skip phases and discard cards at the end.
*
* This results in a game that lasts until there is no cards in library.
*/
private boolean testSimpleGame0(DeckCardLists deckList, int i) throws InterruptedException {
Connection connection = createConnection(TEST_USER_NAME + i);
SimpleMageClient mageClient = new SimpleMageClient();
Session session = new SessionImpl(mageClient);
session.connect(connection);
mageClient.setSession(session);
UUID roomId = session.getMainRoomId();
GameTypeView gameTypeView = session.getGameTypes().get(0);
log.info("Game type view: " + gameTypeView.getName());
MatchOptions options = createGameOptions(gameTypeView, session);
TableView table = session.createTable(roomId, options);
if (!session.joinTable(roomId, table.getTableId(), TEST_USER_NAME + i, "Human", 1, deckList,"")) {
log.error("Error while joining table");
Assert.assertTrue("Error while joining table", false);
return true;
}
/*** Connect with a second player ***/
Connection connection2 = createConnection(TEST_USER_NAME_2 + i);
SimpleMageClient mageClient2 = new SimpleMageClient();
Session session2 = new SessionImpl(mageClient2);
session2.connect(connection2);
mageClient2.setSession(session2);
UUID roomId2 = session2.getMainRoomId();
// connect to the table with the same deck
if (!session2.joinTable(roomId2, table.getTableId(), TEST_USER_NAME_2 + i, "Human", 1, deckList,"")) {
log.error("Error while joining table");
Assert.assertTrue("Error while joining table", false);
return true;
}
/*** Start game ***/
session.startMatch(roomId, table.getTableId());
while (!mageClient.isGameOver()) {
Thread.sleep(1000);
}
return false;
}
/**
* Tests playing the whole game.
* Player use cheat to add lands, creatures and other cards.
* Then play only lands, one of them plays 1 damage targeting player.
*
* This results in 40 turns of the game.
*/
@Test
@Ignore
public void testPlayGame() throws Exception {
//TODO: to be implemented
}
/**
* Creates connection to the server.
* Server should run independently.
*
* @param username
* @return
*/
private Connection createConnection(String username) {
Connection connection = new Connection();
connection.setUsername(username);
connection.setHost(TEST_SERVER);
connection.setPort(TEST_PORT);
Connection.ProxyType proxyType = Connection.ProxyType.valueByText(TEST_PROXY_TYPE);
connection.setProxyType(proxyType);
return connection;
}
/**
* Returns random deck.
* Converts deck returned by {@link #generateRandomDeck} method to {@link DeckCardLists} format.
*
* @return
*/
private DeckCardLists createDeck() {
DeckCardLists deckList = new DeckCardLists();
Deck deck = generateRandomDeck();
for (Card card : deck.getCards()) {
CardInfo cardInfo = CardRepository.instance.findCard(card.getExpansionSetCode(), card.getCardNumber());
if (cardInfo != null) {
deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
}
}
return deckList;
}
/**
* Creates game options with two human players.
*
* @param gameTypeView
* @param session
* @return
*/
private MatchOptions createGameOptions(GameTypeView gameTypeView, Session session) {
MatchOptions options = new MatchOptions("Test game", gameTypeView.getName());
options.getPlayerTypes().add("Human");
options.getPlayerTypes().add("Human");
options.setDeckType(session.getDeckTypes()[0]);
options.setLimited(false);
options.setAttackOption(MultiplayerAttackOption.MULTIPLE);
options.setRange(RangeOfInfluence.ALL);
options.setWinsNeeded(1);
return options;
}
/**
* Generates random deck in {@link Deck} format.
* Uses {B}{R} as deck colors.
*
* @return
*/
private Deck generateRandomDeck() {
String selectedColors = "BR";
List<ColoredManaSymbol> allowedColors = new ArrayList<ColoredManaSymbol>();
log.info("Building deck with colors: " + selectedColors);
for (int i = 0; i < selectedColors.length(); i++) {
char c = selectedColors.charAt(i);
allowedColors.add(ColoredManaSymbol.lookup(c));
}
List<Card> cardPool = Sets.generateRandomCardPool(45, allowedColors);
return ComputerPlayer.buildDeck(cardPool, allowedColors);
}
}