From 7695b92eb17fb138fb4ad28eb601043e8277ad37 Mon Sep 17 00:00:00 2001 From: magenoxx Date: Fri, 17 Dec 2010 20:17:18 +0300 Subject: [PATCH] [tests] Added bdd embedder, steps configure and runner. Added poc for starting games. --- Mage.Server/UW Control.dck | 29 ++++ Mage.Server/pom.xml | 10 ++ .../src/main/resources/log4j.properties | 8 + .../java/mage/server/bdd/MageEmbedder.java | 73 +++++++++ .../test/java/mage/server/bdd/MageSteps.java | 38 +++++ .../java/mage/server/bdd/MageStoryRunner.java | 21 +++ .../java/mage/server/bdd/StoryRunPOC.java | 152 ++++++++++++++++++ 7 files changed, 331 insertions(+) create mode 100644 Mage.Server/UW Control.dck create mode 100644 Mage.Server/src/main/resources/log4j.properties create mode 100644 Mage.Server/src/test/java/mage/server/bdd/MageEmbedder.java create mode 100644 Mage.Server/src/test/java/mage/server/bdd/MageSteps.java create mode 100644 Mage.Server/src/test/java/mage/server/bdd/MageStoryRunner.java create mode 100644 Mage.Server/src/test/java/mage/server/bdd/StoryRunPOC.java diff --git a/Mage.Server/UW Control.dck b/Mage.Server/UW Control.dck new file mode 100644 index 00000000000..3033c885668 --- /dev/null +++ b/Mage.Server/UW Control.dck @@ -0,0 +1,29 @@ +NAME:UW Control +2 [ROE:236] Island +1 [ROE:235] Island +1 [ROE:234] Island +2 [ROE:233] Island +2 [CON:15] Path to Exile +3 [ROE:21] Gideon Jura +1 [CON:11] Martial Coup +2 [ZEN:9] Day of Judgment +1 [ZEN:216] Kabira Crossroads +4 [WWK:31] Jace, the Mind Sculptor +3 [M10:64] Mind Spring +3 [WWK:123] Everflowing Chalice +1 [ROE:232] Plains +4 [ROE:53] Wall of Omens +1 [ROE:229] Plains +1 [ROE:230] Plains +1 [ROE:231] Plains +3 [ALA:20] Oblivion Ring +4 [ZEN:70] Spreading Seas +4 [WWK:145] Tectonic Edge +1 [ALA:9] Elspeth, Knight-Errant +2 [ROE:59] Deprive +1 [ZEN:220] Misty Rainforest +4 [WWK:133] Celestial Colonnade +1 [ZEN:211] Arid Mesa +4 [M10:226] Glacial Fortress +1 [WWK:142] Sejiri Steppe +2 [M10:65] Negate diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index 6c85e253441..d746dea46a3 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -29,6 +29,11 @@ Mage-Sets ${mage-version} + + junit + junit + 4.8.2 + com.sun.xml.bind jaxb-impl @@ -83,6 +88,11 @@ ${project.version} runtime + + org.jbehave + jbehave-core + 3.2-beta-1 + diff --git a/Mage.Server/src/main/resources/log4j.properties b/Mage.Server/src/main/resources/log4j.properties new file mode 100644 index 00000000000..cdef4d6b9e0 --- /dev/null +++ b/Mage.Server/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +#default levels +log4j.rootLogger=info, console + +#console log +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%-5p [%d{yyyy-MM-dd HH:mm [ss:SSS]}] %C{1}[%t]: %m%n +log4j.appender.console.Threshold=DEBUG \ No newline at end of file diff --git a/Mage.Server/src/test/java/mage/server/bdd/MageEmbedder.java b/Mage.Server/src/test/java/mage/server/bdd/MageEmbedder.java new file mode 100644 index 00000000000..4e27d6791d9 --- /dev/null +++ b/Mage.Server/src/test/java/mage/server/bdd/MageEmbedder.java @@ -0,0 +1,73 @@ +package mage.server.bdd; + +import org.jbehave.core.configuration.Configuration; +import org.jbehave.core.configuration.MostUsefulConfiguration; +import org.jbehave.core.embedder.Embedder; +import org.jbehave.core.io.CodeLocations; +import org.jbehave.core.io.LoadFromRelativeFile; +import org.jbehave.core.io.StoryResourceNotFound; +import org.jbehave.core.reporters.StoryReporterBuilder; +import org.jbehave.core.steps.CandidateSteps; +import org.jbehave.core.steps.InstanceStepsFactory; + +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains configuration for working with steps and stories in Mage. + * + * @author nantuko + */ +public class MageEmbedder extends Embedder { + + /** + * We meed to extend LoadFromRelativeFile because of bug in replacing slashes + * + * @author nantuko + */ + private class MageStoryFilePath extends LoadFromRelativeFile { + + private final StoryFilePath[] traversals; + private final URL location; + + public MageStoryFilePath(URL location, StoryFilePath... traversals) { + super(location, traversals); + this.location = location; + this.traversals = traversals; + } + + @Override + public String loadResourceAsText(String resourcePath) { + List traversalPaths = new ArrayList(); + String locationPath = new File(location.getFile()).getAbsolutePath(); + + String filePath = locationPath.replace("target\\test-classes", "src/test/java") + "/" + resourcePath; + File file = new File(filePath); + if (file.exists()) { + return loadContent(filePath); + } + + throw new StoryResourceNotFound(resourcePath, traversalPaths); + } + + } + + @Override + public Configuration configuration() { + Class embedderClass = this.getClass(); + URL codeLocation = CodeLocations.codeLocationFromClass(embedderClass); + Configuration configuration = new MostUsefulConfiguration() + .useStoryLoader(new MageStoryFilePath(codeLocation, LoadFromRelativeFile.mavenModuleTestStoryFilePath("src/test/java") )) + .useStoryReporterBuilder(new StoryReporterBuilder() + .withCodeLocation(codeLocation) + .withDefaultFormats()); + return configuration; + } + + @Override + public List candidateSteps() { + return new InstanceStepsFactory(configuration(), new MageSteps()).createCandidateSteps(); + } +} \ No newline at end of file diff --git a/Mage.Server/src/test/java/mage/server/bdd/MageSteps.java b/Mage.Server/src/test/java/mage/server/bdd/MageSteps.java new file mode 100644 index 00000000000..7c59f3c5321 --- /dev/null +++ b/Mage.Server/src/test/java/mage/server/bdd/MageSteps.java @@ -0,0 +1,38 @@ +package mage.server.bdd; + +import org.jbehave.core.annotations.Given; +import org.jbehave.core.annotations.Then; +import org.jbehave.core.annotations.When; + +/** + * Defines Mage BDD steps. + * + * @author nantuko + */ +public class MageSteps { + + @Given("I'm in the game") + public void inTheGame() { + System.out.println("In the game"); + } + + @Given("I have an \"$card\" card") + public void hasACard(String card) { + System.out.println("card: " + card); + } + + @Given("phase is $own \"$phase\"") + public void hasPhase(String own, String phase) { + System.out.println("phase is: " + own + " -> " + phase); + } + + @When("I splay \"$card\"") + public void playCard(String card) { + System.out.println("play a card: " + card); + } + + @Then("there is an \"$card\" on $zone") + public void playCard(String card, String zone) { + System.out.println("checking: " + card + ", zone=" + zone); + } +} diff --git a/Mage.Server/src/test/java/mage/server/bdd/MageStoryRunner.java b/Mage.Server/src/test/java/mage/server/bdd/MageStoryRunner.java new file mode 100644 index 00000000000..f8c142aa1de --- /dev/null +++ b/Mage.Server/src/test/java/mage/server/bdd/MageStoryRunner.java @@ -0,0 +1,21 @@ +package mage.server.bdd; + +import org.jbehave.core.io.StoryFinder; + +import java.util.List; + +import static java.util.Arrays.asList; + +/** + * Runs Mage stories (tests) + * + * @author nantuko + */ +public class MageStoryRunner { + public static void main(String[] argv) throws Throwable { + MageEmbedder embedder = new MageEmbedder(); + List storyPaths = (new StoryFinder()).findPaths("src/test/java", asList("stories/land.story"), null); + System.out.println("Found stories count: " + storyPaths.size()); + embedder.runStoriesAsPaths(storyPaths); + } +} diff --git a/Mage.Server/src/test/java/mage/server/bdd/StoryRunPOC.java b/Mage.Server/src/test/java/mage/server/bdd/StoryRunPOC.java new file mode 100644 index 00000000000..96f2f1fd373 --- /dev/null +++ b/Mage.Server/src/test/java/mage/server/bdd/StoryRunPOC.java @@ -0,0 +1,152 @@ +package mage.server.bdd; + +import mage.interfaces.MageException; +import mage.interfaces.Server; +import mage.interfaces.ServerState; +import mage.interfaces.callback.CallbackClient; +import mage.interfaces.callback.CallbackClientDaemon; +import mage.interfaces.callback.ClientCallback; +import mage.server.Main; +import mage.sets.Sets; +import mage.util.Logging; +import mage.view.*; +import org.junit.Test; + +import java.rmi.NotBoundException; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Proof of concept of running game from tests.\ + * Will be removed later when BDD is finished. + * + * @author nantuko + */ +public class StoryRunPOC { + + private static Logger logger = Logging.getLogger(StoryRunPOC.class.getName()); + + private static UUID sessionId; + private static Server server; + private static String userName; + private static ServerState serverState; + private static CallbackClientDaemon callbackDaemon; + private static UUID gameId; + private static UUID playerId; + private static CardView cardPlayed; + + @Test + public void testEmpty() { + + } + + public static void main(String[] argv) throws Exception { + String[] args = new String[] {"-testMode=true"}; + Main.main(args); + connect("player", "localhost", 17171); + UUID roomId = server.getMainRoomId(); + + List playerTypes = new ArrayList(); + playerTypes.add("Human"); + playerTypes.add("Computer - default"); + TableView table = server.createTable(sessionId, roomId, "Two Player Duel", "Limited", playerTypes, null, null); + System.out.println("Cards in the deck: " + Sets.loadDeck("UW Control.dck").getCards().size()); + server.joinTable(sessionId, roomId, table.getTableId(), "Human", Sets.loadDeck("UW Control.dck")); + server.joinTable(sessionId, roomId, table.getTableId(), "Computer", Sets.loadDeck("UW Control.dck")); + server.startGame(sessionId, roomId, table.getTableId()); + } + + public static void connect(String userName, String serverName, int port) { + try { + System.setSecurityManager(null); + Registry reg = LocateRegistry.getRegistry(serverName, port); + server = (Server) reg.lookup("mage-server"); + sessionId = server.registerClient(userName, UUID.randomUUID()); + CallbackClient client = new CallbackClient(){ + @Override + public void processCallback(ClientCallback callback) { + logger.info("IN >> " + callback.getMessageId() + " - " + callback.getMethod()); + try { + if (callback.getMethod().equals("startGame")) { + UUID[] data = (UUID[]) callback.getData(); + gameId = data[0]; + playerId = data[1]; + server.joinGame(gameId, sessionId); + } else if (callback.getMethod().equals("gameInit")) { + server.ack("gameInit", sessionId); + } else if (callback.getMethod().equals("gameAsk")) { + GameClientMessage message = (GameClientMessage) callback.getData(); + logger.info("ASK >> " + message.getMessage()); + if (message.getMessage().equals("Do you want to take a mulligan?")) { + server.sendPlayerBoolean(gameId, sessionId, false); + } + } else if (callback.getMethod().equals("gameTarget")) { + GameClientMessage message = (GameClientMessage) callback.getData(); + logger.info("TARGET >> " + message.getMessage() + " >> " + message.getTargets()); + if (message.getMessage().equals("Select a starting player")) { + logger.info(" Sending >> " + playerId); + server.sendPlayerUUID(gameId, sessionId, playerId); + } + } else if (callback.getMethod().equals("gameSelect")) { + GameClientMessage message = (GameClientMessage) callback.getData(); + logger.info("SELECT >> " + message.getMessage()); + if (!message.getMessage().startsWith("Precombat Main - play spells and sorceries.")) { + server.sendPlayerBoolean(gameId, sessionId, false); + } else { + if (cardPlayed == null) { + CardsView cards = message.getGameView().getHand(); + CardView landToPlay = null; + for (CardView card : cards.values()) { + //System.out.println(card.getName()); + if (card.getName().equals("Plains") || card.getName().equals("Island")) { + landToPlay = card; + } + } + if (landToPlay != null) { + logger.info("Playing " + landToPlay); + server.sendPlayerUUID(gameId, sessionId, landToPlay.getId()); + cardPlayed = landToPlay; + } else { + logger.warning("Couldn't find land to play"); + } + } else { + logger.info("Checking battlefield..."); + boolean foundPlayer = false; + boolean foundLand = false; + for (PlayerView player: message.getGameView().getPlayers()) { + if (player.getPlayerId().equals(playerId)) { + foundPlayer = true; + for (PermanentView permanent : player.getBattlefield().values()) { + if (permanent.getId().equals(cardPlayed.getId())) { + foundLand = true; + } + } + break; + } + } + logger.info(" found player: " + foundPlayer); + logger.info(" found land: " + foundLand); + System.exit(0); + } + } + } + } catch (Exception e) { + logger.info(e.getMessage()); + } + } + }; + callbackDaemon = new CallbackClientDaemon(sessionId, client, server); + serverState = server.getServerState(); + } catch (MageException ex) { + logger.log(Level.SEVERE, null, ex); + } catch (RemoteException ex) { + logger.log(Level.SEVERE, "Unable to connect to server - ", ex); + } catch (NotBoundException ex) { + logger.log(Level.SEVERE, "Unable to connect to server - ", ex); + } + } +}