Loic wrote on Tuesday the 8th: > I very much doubt there will be any benefit in making an actual bot > run in the tests. The connection pattern is specific but the rest of > the bot actions is not.
After I sent my previous message, I took a look at what I'd been working on before with fresh eyes. This solution *does* work, and given that I'd already put effort into it before sending my last message, it was actually easier to use this setup of deferred's/reactor.callLater()'s you see in nBotsAndOneLivePlayer() in the attached patch. I am therefore planning to merge this bug-tests branch at r6232 into trunk, the changset for which is shown in the attached patch. I plan to use this commit message: Test to exhibit bug#14139. This new test in test-bug-14139.py.in exhibits bug#14139 by adding bots and user and showing that a hand does not start. If the bug is closed, this test should pass as written. Note that some changes were needed in test-pokeravatar.py.in in some of the helper functions. This doesn't impact the functioning of those test. Much of the changes move some methods to base classes; the rest make minor changes to helper functions to handle the existence of the bots at the tables and slightly different uses of the helper functions. Finally, a few files that should have been in .gitignore are added. This will be meaningless currently to anyone but those using git-svn. The attached patch is copyrighted by me and licensed under AGPLv3-or-later.
diff --git a/.gitignore b/.gitignore index fd53985..1b2b85e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ *~ TAGS ########################################################################### +# poker-network: bkuhn-specific files. Remove this if you add files by +# this name, bkuhn will appreciate it. +poker-network/check.log +########################################################################### # poker-network: Specific files that are generated by build poker-network/ABOUT-NLS poker-network/INSTALL @@ -79,6 +83,12 @@ poker-network/po/remove-potcdate.sed poker-network/po/remove-potcdate.sin poker-network/po/stamp-po poker-network/poker-network.pc +poker-network/pokerprizes/Makefile +poker-network/pokerprizes/Makefile.in +poker-network/pokerprizes/poker.prizes.xml +poker-network/pokerprizes/run +poker-network/pokerprizes/schema.sql +poker-network/pokerprizes/test-prizes.py poker-network/pokerclient2d/.deps poker-network/pokerclient2d/.libs poker-network/pokerclient2d/Makefile @@ -129,6 +139,7 @@ poker-network/pokernetwork/pokernetworkconfig.pyc poker-network/pokernetwork/pokerserver poker-network/pokernetwork/pokerserver.8 poker-network/pokernetwork/version.pyc +poker-network/pokernetwork/pokersql poker-network/pokerstats/Makefile poker-network/pokerstats/Makefile.in poker-network/pokerstats/poker.stats.xml @@ -193,6 +204,14 @@ poker-network/tests/testbirthday.php poker-network/tests/testcurrency.php poker-network/tests/testpoker.php poker-network/tests/testwebservice.php +poker-network/tests/test-nullfilter.py +poker-network/tests/test-pokerrestclient.py +poker-network/tests/test-pokerserver-run-load.py +poker-network/tests/test-pokerservice-load.py +poker-network/tests/test-pokersql.py +poker-network/tests/test-proxy.py +poker-network/tests/test-bug-14139.py +poker-network/tests/test-sessionproxyfilter.py poker-network/tests/upgrade poker-network/tests/.coverage poker-network/tests/_trial_temp diff --git a/poker-network/ChangeLog b/poker-network/ChangeLog index 9bb61d9..fc64b1d 100644 --- a/poker-network/ChangeLog +++ b/poker-network/ChangeLog @@ -1,5 +1,66 @@ +2009-09-13 Bradley M. Kuhn <[email protected]> + + * tests/test-bug-14139.py.in + (PokerAvatarTablePickerDoesNotDealHandTestCase.nBotsAndOneLivePlayer): + Abstracted test02 code into this method. + (PokerAvatarTablePickerDoesNotDealHandTestCase.test02_tablePicker_someBots_playShouldSucceed_1bot): + Wrote test. + (PokerAvatarTablePickerDoesNotDealHandTestCase.test03_tablePicker_someBots_playShouldSucceed_2bot): + Wrote test. + (PokerAvatarTablePickerDoesNotDealHandTestCase.test04_tablePicker_someBots_playShouldSucceed_3bot): + Wrote test. + (PokerAvatarTablePickerDoesNotDealHandTestCase.test05_tablePicker_someBots_playShouldSucceed_4bot): + Wrote test. + (PokerAvatarTablePickerDoesNotDealHandTestCase.test06_tablePicker_someBots_playShouldSucceed_5bot): + Wrote test. + + * tests/test-pokeravatar.py.in + (PokerAvatarTestCaseBaseClass.readyToPlay) + (PokerAvatarTablePickerBaseClass.tablePickerSucceeds): Use + getSerial() to lookup avatar serial. + (settings_xml_table_picker_server): Added play money table to + settings. + (PokerAvatarTablePickerBaseClass.tablePickerSucceeds): Ignore play + money buy-ins. + + * tests/test-bug-14139.py.in + (PokerAvatarTablePickerDoesNotDealHandTestCase.test02_tablePicker_someBots_playShouldSucceed): + Wrote test. + (PokerAvatarTablePickerDoesNotDealHandTestCase.setUpBots): Wrote method. + (PokerAvatarTablePickerDoesNotDealHandTestCase.startHandAndReceiveCards): + Wrote test. + +2009-09-07 Bradley M. Kuhn <[email protected]> + + * tests/test-bug-14139.py.in + (PokerAvatarTablePickerDoesNotDealHandTestCase.startHandAndReceiveCards): + Tweaked method from PokerAvatarTestCase.startHandAndReceiveCards + (PokerAvatarTablePickerDoesNotDealHandTestCase.test01_tablePicker_allHuman_playSucceeds): + Wrote test. + (PokerAvatarTablePickerDoesNotDealHandTestCase.tearDown): Wrote + method. + (PokerAvatarTablePickerDoesNotDealHandTestCase.beginHandSetupOnePlayer): + Wrote method, mostly cut-and-paste from + PokerAvatarTestCaseBaseClass.beginHandSetup. + (PokerAvatarTablePickerDoesNotDealHandTestCase.test01_tablePicker_allHuman_playSucceeds): + Switched to new SetupOnePlayer, for better contrast with Bot + players present. + + * tests/test-pokeravatar.py.in + (PokerAvatarTestCaseBaseClass.beginHandSetup) + (PokerAvatarTestCaseBaseClass.dealTable) + (PokerAvatarTestCaseBaseClass.doBlindPost): Moved methods into + base class. + (PokerAvatarTestCaseBaseClass.beginHandSetup): Added + dealerAssigned argument. + + * tests/test-bug-14139.py.in: Created test file. + 2009-09-06 Bradley M. Kuhn <[email protected]> + * tests/test-pokeravatar.py.in (PokerAvatarTablePickerBaseClass): + Abstracted out some code from PokerAvatarTablePickerTestCase. + * Makefile.am (install-data-local, all-local): Removed 'client' from list in for loop, since r6200 deleted the files it would refer to. diff --git a/poker-network/configure.ac b/poker-network/configure.ac index 9fc07a7..9e09a6f 100644 --- a/poker-network/configure.ac +++ b/poker-network/configure.ac @@ -276,6 +276,7 @@ AC_CONFIG_FILES([ tests/test-pokerserver.py tests/test-pokerserver-run-load.py tests/test-pokerrestclient.py + tests/test-bug-14139.py tests/testcurrency.php tests/testpoker.php tests/testbirthday.php diff --git a/poker-network/tests/Makefile.am b/poker-network/tests/Makefile.am index c4674d0..7aa677c 100644 --- a/poker-network/tests/Makefile.am +++ b/poker-network/tests/Makefile.am @@ -93,12 +93,19 @@ TESTS = coverage-reset \ test-pokerserver.py \ test-pokerserver-run-load.py \ test-pokerrestclient.py \ + test-bug-14139.py \ testcurrency.php \ testpoker.php \ testbirthday.php \ testwebservice.php \ coverage-report +# Regarding XFAIL_TESTS: the only items we typically list here are tests +# designed to cover open bugs. We expect them to fail until the bug is +# closed. If you close a bug, be sure to remove the test-bug-NUMBER.py +# entry from XFAIL_TESTS below. + +XFAIL_TESTS = test-bug-14139.py .PHONY: coverage-reset coverage-report diff --git a/poker-network/tests/test-bug-14139.py.in b/poker-network/tests/test-bug-14139.py.in new file mode 100644 index 0000000..e68fc35 --- /dev/null +++ b/poker-network/tests/test-bug-14139.py.in @@ -0,0 +1,426 @@ +...@python@ +# -*- mode: python -*- +# +# Copyright (C) 2009 Bradley M. Kuhn <[email protected]> +# +# This software's license gives you freedom; you can copy, convey, +# propagate, redistribute and/or modify this program under the terms of +# the GNU Affero General Public License (AGPL) as published by the Free +# Software Foundation (FSF), either version 3 of the License, or (at your +# option) any later version of the AGPL published by the FSF. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +# General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program in a file in the toplevel directory called +# "AGPLv3". If not, see <http://www.gnu.org/licenses/>. +# +import sys, os, tempfile, shutil, signal +sys.path.insert(0, "@srcdir@/..") +sys.path.insert(0, "..") +sys.path.insert(0, ".") + +import locale +import libxml2 +from types import * +import socket +import time +from twisted.trial import unittest, runner, reporter +import twisted.internet.base +from twisted.internet import reactor, defer, error, base +from twisted.python import failure, runtime +from twisted.python.runtime import seconds + +from tests import testclock +from tests.testmessages import restore_all_messages, silence_all_messages, search_output, clear_all_messages, get_messages +#os.environ['VERBOSE_T'] = '0' +verbose = int(os.environ.get('VERBOSE_T', '-1')) +if verbose < 0: silence_all_messages() + +twisted.internet.base.DelayedCall.debug = True + +from pokernetwork import pokerservice +from pokernetwork.pokerclientpackets import * +from pokernetwork import pokernetworkconfig + +# Note that since import doesn't allow -'s in indentifiers, I have to do +# the following trick to import another test file. +test_pokeravatar = __import__('test-pokeravatar', globals(), locals(), + ['PokerAvatarTablePickerBaseClass'], -1) +PokerAvatarTablePickerBaseClass = test_pokeravatar.PokerAvatarTablePickerBaseClass + +settings_bot_xml = """ +<settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="poker-bot.xsd" delays="false" wait="1" reconnect="yes" watch="no" level="1" cash_in="no" ping="10" verbose="0" no_display_packets="yes" rebuy="yes" name_prefix="BOT" poker_network_version="2.0.0"> + <delays position="0" begin_round="0" end_round="0" end_round_last="0" showdown="5" lag="15"/> + <name>test</name> + <passwd>test</passwd> + <servers>%(serverInfo)s</servers> + <muck>yes</muck> + <currency id="0"></currency> + <auto_post>yes</auto_post> +n <path>.. ../@srcdir@ @POKER_ENGINE_PKGSYSCONFDIR@ </path> + + <verbose>6</verbose> + <table name="Play Money NL HE 10-max 1/2" count="%(botCount)d"/> +</settings> +""" +# ----------------------------------------------------------------------------- +class PokerAvatarTablePickerDoesNotDealHandTestCase(PokerAvatarTablePickerBaseClass): + # ------------------------------------------------------------------------- + # I had serious weirdness trying to call + # PokerAvatarTablePickerBaseClass.tearDown(self), so I had to copy the + # tearDown code from the base class. I think this problem had + def tearDown(self): + if hasattr(self, 'tmpdir'): + shutil.rmtree(self.tmpdir) + if hasattr(self, 'botPid'): + os.kill(self.botPid, signal.SIGHUP) + os.kill(self.botPid, signal.SIGINT) + os.kill(self.botPid, signal.SIGTERM) + os.kill(self.botPid, signal.SIGKILL) + # Rest stupidly copied from super class, see above + d = self.service.stopService() + d.addCallback(lambda x: self.p.stopListening()) + d.addCallback(self.destroyDb) + d.addCallback(self.cleanSessions) + return d + # ------------------------------------------------------------------------- + def setUpBots(self, botCount): + # Next, create the bot application so that we have bots joining + # the any tables specificed in the settings_bot_xml above + self.tmpdir = tempfile.mkdtemp() + outFile = os.path.join(self.tmpdir, "poker.bot.xml") + outFH = open(outFile, "w") + botConfigData = settings_bot_xml % { 'serverInfo': "127.0.0.1:%d" % self.port, + 'botCount' : botCount } + outFH.write(botConfigData) + outFH.close() + pid = os.fork() + if not pid: + # The child simply execs the bot code. + saveArgv = sys.argv + sys.argv.append(outFile) + newEnviorn = os.environ + newEnviorn['PYTHONPATH'] = ".:@srcdir@/../../" + os.execlp("@PYTHON@", "@srcdir@/../../pokernetwork/pokerbot", + "@srcdir@/../../pokernetwork/pokerbot", outFile) + else: + # In the parent, we continue with the test + self.botPid = pid + # ------------------------------------------------------------------------- + # I copied the startHandAndReceiveCards from PokerAvatarTestCase + # rather than moving it into PokerAvatarTestCaseBaseClass because + # there were some changes to be made due to the fact that when + # TablePicker is used, a different player gets the button. I am not + # sure why this is, really, and it may be part of what is going on in + # the bug. + def startHandAndReceiveCards(self, (client, packet), gameId, bigBlindAmount = 200, + smallBlindAmount = 100): + table = self.service.getTable(gameId) + + lang2strings = { 'default' : [ "Dealer: user1 pays %(smallBlind)d blind\n", + "Dealer: user0 pays %(bigBlind)d blind\n", + "Dealer: pre-flop, %(numPlayers)d players\n" ], + 'en_US' : [ "Dealer: user1 pays %(smallBlind)d blind\n", + "Dealer: user0 pays %(bigBlind)d blind\n", + "Dealer: pre-flop, %(numPlayers)d players\n" ], + 'fr_FR' : [ "Dealer: user1 paye %(smallBlind)d de blind\n", + "Dealer: user0 paye %(bigBlind)d de blind\n", + "Dealer: pre-flop, %(numPlayers)d joueurs\n" ] } + for lang in lang2strings.keys(): + for ii in range(0, len(lang2strings[lang])): + lang2strings[lang][ii] = lang2strings[lang][ii] % {'bigBlind': bigBlindAmount / 100, 'smallBlind' : smallBlindAmount / 100, 'numPlayers' : 2 } + avatar = [] + avatar.append(self.service.avatars[0]) + + found = 0 + ignored = 0 + for packet in avatar[0].resetPacketsQueue(): + if packet.type == PACKET_POKER_BLIND: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.dead, 0) + elif packet.type == PACKET_POKER_CHIPS_PLAYER2BET: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.cookie, "") + if (packet.serial == avatar[0].getSerial()): + self.assertEquals(packet.chips, [smallBlindAmount, 2]) + else: + assert("unknown serial in player2bet packet: %d" + % packet.serial) + elif packet.type == PACKET_POKER_CHIPS: + found += 1 + self.assertEquals(packet.serial, mySerial) + self.assertEquals(packet.game_id, gameId) + elif packet.type == PACKET_POKER_CHAT: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.serial, 0) + if (packet.message not in lang2strings[self.avatarLocales[0]]): + self.fail("Unexpected and/or Wrong Language (expected %s) message: %s for avatar %d" + % (self.avatarLocales[0], packet.message, 0)) + elif packet.type == PACKET_POKER_STATE: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.serial, 0) + self.assertEquals(packet.string, "pre-flop") + elif packet.type == PACKET_POKER_BEGIN_ROUND: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.serial, 0) + self.assertEquals(packet.cookie, "") + + elif packet.type == PACKET_POKER_PLAYER_CARDS: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(len(packet.cards), 2) + elif packet.type == PACKET_POKER_BET_LIMIT: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.serial, 0) + self.assertEquals(packet.cookie, "") + self.assertEquals(packet.step, smallBlindAmount) + self.assertEquals(packet.min, bigBlindAmount) + self.assertEquals(packet.max, 180000) + self.assertEquals(packet.allin, packet.max) + self.assertEquals(packet.pot, smallBlindAmount + bigBlindAmount) + self.assertEquals(packet.call, 0) + else: + ignored += 1 + self.assertEquals(found, 14, """Expected 14, but got %d. If we +get nothing here, it means the hand play was not started. It is this +failure we should see to exhibit bug#14139. If we do not get this failure +for test02, then something else is wrong with test02""" % found) + return (client, packet) + # ------------------------------------------------------------------------- + # The below was seriously hacked from + # PokerAvatarTestCaseBaseClass.beginHandSetup. It might read a little + # weird because I did not adjust it carefully to consider only the single player. + def beginHandSetupOnePlayer(self, (client, packet), gameId, dealerAssigned = 1): + table = self.service.getTable(gameId) + avatars = self.service.avatar_collection.get(client.getSerial()) + self.failUnless(len(avatars) == 1, "Only one avatar should have this serial") + avatar = avatars[0] + avatar.queuePackets() + # Handle the packets that initially arrive. I learned what to + # expect from "What to expect while a hand is being played?" in + # pokerpackets.py + packetList = [] + packetList.extend(avatar.resetPacketsQueue()) + playersExpect = [ avatar.getSerial() ] + playersExpect.sort() + if len(self.service.avatars) > 1: + avatar1 = self.service.avatars[1] + avatar1.queuePackets() + packetList.extend(avatar1.resetPacketsQueue()) + found = 0 + for packet in packetList: + if packet.type == PACKET_POKER_IN_GAME: + found += 1 + self.assertEquals(packet.serial, 0) + self.assertEquals(packet.game_id, gameId) + self.failUnless(avatar.getSerial() in packet.players, + "Should find myself in the player list") + self.failUnless(len(packet.players) > 1, + "Should have bots or second player here") + packet.players.sort() + elif packet.type == PACKET_POKER_DEALER: + found += 1 + self.assertEquals(packet.dealer, dealerAssigned) + self.assertEquals(packet.previous_dealer, -1) + self.assertEquals(packet.game_id, gameId) + elif packet.type == PACKET_POKER_START: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.level, 0) + self.assertEquals(packet.hand_serial, 1) + self.assertEquals(packet.serial, 0) + self.assertEquals(packet.hands_count, 0) + self.assertEquals(packet.time, 0) + elif packet.type == PACKET_POKER_POSITION: + found += 1 + self.assertEquals(packet.game_id, gameId) + elif packet.type == PACKET_POKER_CHIPS_POT_RESET: + found += 1 + self.assertEquals(packet.cookie, "") + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.length, 11) + self.assertEquals(packet.serial, 0) + elif packet.type == PACKET_POKER_BLIND_REQUEST: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.dead, 0) + elif packet.type == PACKET_POKER_SELF_IN_POSITION: + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.position, -1) + self.assertEquals(packet.length, 8) + elif packet.type == PACKET_POKER_BOARD_CARDS: + self.assertEquals(packet.game_id, gameId) + self.assertEquals(True, packet.serial == avatar.getSerial() ) + self.assertEquals(packet.cards, []) + # When I was writing this loop, I also saw a number of: + # POKER_PLAYER_CHIPS and also the POKER_PLAYER_ARRIVE for + # serial 5, but I thought it was safe to ignore them here. + + self.failUnless(found >= 7, "Got %d, expected at least 7." % found) + avatar.queuePackets() + if len(self.service.avatars) > 1: + avatar1.queuePackets() + return (client, packet) + # ------------------------------------------------------------------------- + def test01_tablePicker_allHuman_playSucceeds(self): + """test01_tablePicker_playSuceeds + This test should succeed even before bug 14139 is closed. It's a + bit of a control group -- to make sure that when the players are + all human, that both using table picker suceed in having a hand + started. This test is basically a "mix" of + PokerAvatarTestCase.test15_handPlay() and + PokerAvatarTablePickerTestCase.test03_tablePicker_onlyOnePossible()""" + self.createClients(2) + + playersDeferreds = [] + for ii in [ 0, 1 ]: + iiDeferred = self.preparePlayerForTablePickerSend(ii) + playersDeferreds.append(iiDeferred) + iiDeferred.addCallback(self.setMoneyForPlayer, ii, 1, "over_min_under_best", 1) + iiDeferred.addCallback(self.tablePickerSucceeds, ii, ii, 0, + "holdem", "100-200-no-limit", 1, "NL HE 10-max 100/200", + autoBlindAnte = (ii == 0)) + iiDeferred.addCallback(self.readyToPlay, ii, 1) + + # Next, add items to start playing to last user added. + iiDeferred.addCallback(self.dealTable, 1) + iiDeferred.addCallback(self.beginHandSetupOnePlayer, 1, dealerAssigned = 0) + iiDeferred.addCallback(self.doBlindPost, 1, 1) + iiDeferred.addCallback(self.startHandAndReceiveCards, 1, + smallBlindAmount = 10000, bigBlindAmount = 20000 ) + return defer.DeferredList(playersDeferreds) + # ------------------------------------------------------------------------- + def nBotsAndOneLivePlayer(self, botCount): + """The code here uses a serious of reactor.callLater()'s and two + deferreds to be sure that the user-controlled player does not get + created until the bots have fully joined. We must do this sort of + delay because we don't know how long the subprocess of bots will + take to have enough bots + """ + + self.setUpBots(botCount) + + finishedDeferred = defer.Deferred() + + def setupPlayerIfBotsAtTable(): + table = self.service.getTable(6) + numberJoined = len(table.avatar_collection.serial2avatars.keys()) + + if (numberJoined < botCount): + return None + else: + self.createClients(1) + playerDeferred = self.preparePlayerForTablePickerSend(0) + playerDeferred.addCallback(self.setMoneyForPlayer, 0, 0, "over_min_under_best", 6) + playerDeferred.addCallback(self.tablePickerSucceeds, 0, 0, 0, + "holdem", "1-2-no-limit", 6, "Play Money NL HE 10-max 1/2", + autoBlindAnte = False) + playerDeferred.addCallback(self.readyToPlay, 0, 6) + playerDeferred.addCallback(self.dealTable, 6) + playerDeferred.addCallback(self.beginHandSetupOnePlayer, 6, dealerAssigned = 0) + playerDeferred.addCallback(self.doBlindPost, 0, 6) + playerDeferred.addCallback(self.startHandAndReceiveCards, 6, + smallBlindAmount = 100, bigBlindAmount = 200 ) + playerDeferred.addCallback(lambda : finishedDeferred.callback(True)) + return playerDeferred + + def checkWaitforFinished(): + playerDeferred = setupPlayerIfBotsAtTable() + if playerDeferred != None: + return playerDeferred + else: + reactor.callLater(5, checkWaitforFinished) + + reactor.callLater(5, checkWaitforFinished) + return finishedDeferred + # ------------------------------------------------------------------------- + def test02_tablePicker_someBots_playShouldSucceed_1bot(self): + """test02_tablePicker_someBots_playShouldSucceed_1bot + This is the actual test for bug #14139. Similar to the previous + test, but instead we create a bot server. The code in this test + uses a serious of reactor.callLater()'s and two deferreds to be + sure that the user-controlled player does not get created until + the bots have fully joined. We must do this sort of delay because + we don't know how long the subprocess of bots will take to have enough bots + """ + return self.nBotsAndOneLivePlayer(1) + # ------------------------------------------------------------------------- + def test03_tablePicker_someBots_playShouldSucceed_2bot(self): + """test03_tablePicker_someBots_playShouldSucceed_2bot + This is the actual test for bug #14139. Similar to the previous + test, but instead we create a bot server. The code in this test + uses a serious of reactor.callLater()'s and two deferreds to be + sure that the user-controlled player does not get created until + the bots have fully joined. We must do this sort of delay because + we don't know how long the subprocess of bots will take to have enough bots + """ + return self.nBotsAndOneLivePlayer(2) + # ------------------------------------------------------------------------- + def test04_tablePicker_someBots_playShouldSucceed_3bot(self): + """test04_tablePicker_someBots_playShouldSucceed_3bot + This is the actual test for bug #14139. Similar to the previous + test, but instead we create a bot server. The code in this test + uses a serious of reactor.callLater()'s and two deferreds to be + sure that the user-controlled player does not get created until + the bots have fully joined. We must do this sort of delay because + we don't know how long the subprocess of bots will take to have enough bots + """ + return self.nBotsAndOneLivePlayer(3) + # ------------------------------------------------------------------------- + def test05_tablePicker_someBots_playShouldSucceed_4bot(self): + """test05_tablePicker_someBots_playShouldSucceed_4bot + This is the actual test for bug #14139. Similar to the previous + test, but instead we create a bot server. The code in this test + uses a serious of reactor.callLater()'s and two deferreds to be + sure that the user-controlled player does not get created until + the bots have fully joined. We must do this sort of delay because + we don't know how long the subprocess of bots will take to have enough bots + """ + return self.nBotsAndOneLivePlayer(4) + # ------------------------------------------------------------------------- + def test06_tablePicker_someBots_playShouldSucceed_5bot(self): + """test06_tablePicker_someBots_playShouldSucceed_5bot + This is the actual test for bug #14139. Similar to the previous + test, but instead we create a bot server. The code in this test + uses a serious of reactor.callLater()'s and two deferreds to be + sure that the user-controlled player does not get created until + the bots have fully joined. We must do this sort of delay because + we don't know how long the subprocess of bots will take to have enough bots + """ + return self.nBotsAndOneLivePlayer(5) +############################################################################## +def Run(): + loader = runner.TestLoader() +# loader.methodPrefix = "test02" + suite = loader.suiteFactory() + suite.addTest(loader.loadClass(PokerAvatarTablePickerDoesNotDealHandTestCase)) + return runner.TrialRunner( + reporter.VerboseTextReporter, +# tracebackFormat='verbose', + tracebackFormat='default', + ).run(suite) + +# ------------------------------------------------------ +if __name__ == '__main__': + if Run().wasSuccessful(): + sys.exit(0) + else: + sys.exit(1) +# Interpreted by emacs +# Local Variables: +# compile-command: "( cd .. ; ./config.status tests/test-bug-14139.py tests/test-pokeravatar.py ) ; ( cd ../tests ; make VERBOSE_T=-1 COVERAGE_FILES='../pokernetwork/pokeravatar.py' TESTS='coverage-reset test-bug-14139.py coverage-report' check )" +# End: + +# I have this set to cover pokerpackets because this isn't really a +# coverage test and therefore I would rather not have errors when it fails +# to cover some particular file. diff --git a/poker-network/tests/test-pokeravatar.py.in b/poker-network/tests/test-pokeravatar.py.in index 69fba7e..b791c44 100644 --- a/poker-network/tests/test-pokeravatar.py.in +++ b/poker-network/tests/test-pokeravatar.py.in @@ -356,7 +356,9 @@ class PokerAvatarTestCaseBaseClass(unittest.TestCase): return (client, packet) # ------------------------------------------------------------------------ def readyToPlay(self, (client, packet), id, gameId ): - avatar = self.service.avatars[id] + avatars = self.service.avatar_collection.get(client.getSerial()) + self.failUnless(len(avatars) == 1, "Only one avatar should have this serial") + avatar = avatars[0] avatar.queuePackets() avatar.handlePacketLogic(PacketPokerReadyToPlay(serial = client.getSerial(), game_id = gameId)) @@ -382,6 +384,97 @@ class PokerAvatarTestCaseBaseClass(unittest.TestCase): print packet self.assertEquals(found, True) return (client, packet) + # ------------------------------------------------------------------------ + def dealTable(self, (client, packet), gameId): + table = self.service.getTable(gameId) + table.beginTurn() + table.update() + return (client, packet) + # ------------------------------------------------------------------------ + def beginHandSetup(self, (client, packet), gameId, dealerAssigned = 1, + blindAmount = 100, blindExpected = 'small'): + table = self.service.getTable(gameId) + avatar0 = self.service.avatars[0] + avatar1 = self.service.avatars[1] + avatar0.queuePackets() + avatar1.queuePackets() + # Handle the packets that initially arrive. I learned what to + # expect from "What to expect while a hand is being played?" in + # pokerpackets.py + packetList = [] + packetList.extend(avatar0.resetPacketsQueue()) + packetList.extend(avatar1.resetPacketsQueue()) + playersExpect = [ avatar0.getSerial(), avatar1.getSerial() ] + playersExpect.sort() + found = 0 + for packet in packetList: + if packet.type == PACKET_POKER_IN_GAME: + found += 1 + self.assertEquals(packet.serial, 0) + self.assertEquals(packet.game_id, gameId) + packet.players.sort() + self.assertEquals(packet.players, playersExpect) + elif packet.type == PACKET_POKER_DEALER: + found += 1 + self.assertEquals(packet.dealer, dealerAssigned) + self.assertEquals(packet.previous_dealer, -1) + self.assertEquals(packet.game_id, gameId) + elif packet.type == PACKET_POKER_START: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.level, 0) + self.assertEquals(packet.hand_serial, 1) + self.assertEquals(packet.serial, 0) + self.assertEquals(packet.hands_count, 0) + self.assertEquals(packet.time, 0) + elif packet.type == PACKET_POKER_POSITION: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(True, packet.serial == avatar0.getSerial() + or packet.serial == avatar1.getSerial()) + elif packet.type == PACKET_POKER_CHIPS_POT_RESET: + found += 1 + self.assertEquals(packet.cookie, "") + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.length, 11) + self.assertEquals(packet.serial, 0) + elif packet.type == PACKET_POKER_BLIND_REQUEST: + found += 1 + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.dead, 0) + self.assertEquals(packet.serial, avatar1.getSerial()) + self.assertEquals(packet.amount, blindAmount) + self.assertEquals(packet.state, blindExpected) + elif packet.type == PACKET_POKER_SELF_IN_POSITION: + self.assertEquals(packet.serial, avatar1.getSerial()) + self.assertEquals(packet.game_id, gameId) + self.assertEquals(packet.position, -1) + self.assertEquals(packet.length, 8) + elif packet.type == PACKET_POKER_BOARD_CARDS: + self.assertEquals(packet.game_id, gameId) + self.assertEquals(True, packet.serial == avatar0.getSerial() + or packet.serial == avatar1.getSerial()) + + self.assertEquals(packet.cards, []) + # When I was writing this loop, I also saw a number of: + # POKER_PLAYER_CHIPS and also the POKER_PLAYER_ARRIVE for + # serial 5, but I thought it was safe to ignore them here. + self.assertEquals(found, 14) + avatar0.queuePackets() + avatar1.queuePackets() + return (client, packet) + # ------------------------------------------------------------------------ + def doBlindPost(self, (client, packet), id, gameId): + # By now, we should have seen as noted above, a request for the + # blinds for avatar1 for 100 small blind. Here we send it. + avatars = self.service.avatar_collection.get(client.getSerial()) + self.failUnless(len(avatars) == 1, "Only one avatar should have this serial") + avatar = avatars[0] + avatar.queuePackets() + avatar.handlePacketLogic(PacketPokerBlind(serial= avatar.getSerial(), + game_id = gameId, dead = 0, + amount = 100)) + return (client, packet) ############################################################################## class PokerAvatarTestCase(PokerAvatarTestCaseBaseClass): # ------------------------------------------------------------------------- @@ -788,94 +881,6 @@ class PokerAvatarTestCase(PokerAvatarTestCaseBaseClass): d.addCallback(self.statsQuery, 0) return d # ------------------------------------------------------------------------ - def dealTable(self, (client, packet), gameId): - table = self.service.getTable(gameId) - table.beginTurn() - table.update() - return (client, packet) - # ------------------------------------------------------------------------ - def beginHandSetup(self, (client, packet), gameId): - table = self.service.getTable(gameId) - avatar0 = self.service.avatars[0] - avatar1 = self.service.avatars[1] - avatar0.queuePackets() - avatar1.queuePackets() - # Handle the packets that initially arrive. I learned what to - # expect from "What to expect while a hand is being played?" in - # pokerpackets.py - packetList = [] - packetList.extend(avatar0.resetPacketsQueue()) - packetList.extend(avatar1.resetPacketsQueue()) - playersExpect = [ avatar0.getSerial(), avatar1.getSerial() ] - playersExpect.sort() - found = 0 - for packet in packetList: - if packet.type == PACKET_POKER_IN_GAME: - found += 1 - self.assertEquals(packet.serial, 0) - self.assertEquals(packet.game_id, gameId) - packet.players.sort() - self.assertEquals(packet.players, playersExpect) - elif packet.type == PACKET_POKER_DEALER: - found += 1 - self.assertEquals(packet.dealer, 1) - self.assertEquals(packet.previous_dealer, -1) - self.assertEquals(packet.game_id, gameId) - elif packet.type == PACKET_POKER_START: - found += 1 - self.assertEquals(packet.game_id, gameId) - self.assertEquals(packet.level, 0) - self.assertEquals(packet.hand_serial, 1) - self.assertEquals(packet.serial, 0) - self.assertEquals(packet.hands_count, 0) - self.assertEquals(packet.time, 0) - elif packet.type == PACKET_POKER_POSITION: - found += 1 - self.assertEquals(packet.game_id, gameId) - self.assertEquals(True, packet.serial == avatar0.getSerial() - or packet.serial == avatar1.getSerial()) - elif packet.type == PACKET_POKER_CHIPS_POT_RESET: - found += 1 - self.assertEquals(packet.cookie, "") - self.assertEquals(packet.game_id, gameId) - self.assertEquals(packet.length, 11) - self.assertEquals(packet.serial, 0) - elif packet.type == PACKET_POKER_BLIND_REQUEST: - found += 1 - self.assertEquals(packet.game_id, gameId) - self.assertEquals(packet.dead, 0) - self.assertEquals(packet.serial, avatar1.getSerial()) - self.assertEquals(packet.amount, 100) - self.assertEquals(packet.state, 'small') - elif packet.type == PACKET_POKER_SELF_IN_POSITION: - self.assertEquals(packet.serial, avatar1.getSerial()) - self.assertEquals(packet.game_id, gameId) - self.assertEquals(packet.position, -1) - self.assertEquals(packet.length, 8) - elif packet.type == PACKET_POKER_BOARD_CARDS: - self.assertEquals(packet.game_id, gameId) - self.assertEquals(True, packet.serial == avatar0.getSerial() - or packet.serial == avatar1.getSerial()) - - self.assertEquals(packet.cards, []) - # When I was writing this loop, I also saw a number of: - # POKER_PLAYER_CHIPS and also the POKER_PLAYER_ARRIVE for - # serial 5, but I thought it was safe to ignore them here. - self.assertEquals(found, 14) - avatar0.queuePackets() - avatar1.queuePackets() - return (client, packet) - # ------------------------------------------------------------------------ - def doBlindPost(self, (client, packet), id, gameId): - # By now, we should have seen as noted above, a request for the - # blinds for avatar1 for 100 small blind. Here we send it. - avatar = self.service.avatars[id] - avatar.queuePackets() - avatar.handlePacketLogic(PacketPokerBlind(serial= avatar.getSerial(), - game_id = gameId, dead = 0, - amount = 100)) - return (client, packet) - # ------------------------------------------------------------------------ def startHandAndReceiveCards(self, (client, packet), gameId): table = self.service.getTable(gameId) @@ -4238,7 +4243,7 @@ settings_xml_table_picker_server = """<?xml version="1.0" encoding="ISO-8859-1"? <table name="Limit HE 10-max 2/4" variant="holdem" betting_structure="2-4-limit" seats="10" player_timeout="60" currency_serial="2" /> <table name="Limit HE 6-max 2/4" variant="holdem" betting_structure="2-4-limit" seats="6" player_timeout="60" currency_serial="2" /> <table name="Stud 8-max 2/4" variant="7stud" betting_structure="2-4-limit" seats="8" player_timeout="60" currency_serial="2" /> - + <table name="Play Money NL HE 10-max 1/2" variant="holdem" betting_structure="1-2-no-limit" seats="10" player_timeout="60" currency_serial="0" /> <listen tcp="19480" /> <cashier acquire_timeout="5" pokerlock_queue_timeout="30" user_create="yes"/> @@ -4250,7 +4255,7 @@ settings_xml_table_picker_server = """<?xml version="1.0" encoding="ISO-8859-1"? </server> """ # ----------------------------------------------------------------------------- -class PokerAvatarTablePickerTestCase(PokerAvatarTestCaseBaseClass): +class PokerAvatarTablePickerBaseClass(PokerAvatarTestCaseBaseClass): # Timeout needs to be higher for this test case because some of the # later tests add so many clients that 240 isn't enough. timeout = 540 @@ -4318,7 +4323,9 @@ class PokerAvatarTablePickerTestCase(PokerAvatarTestCaseBaseClass): preBuyInBalance = self.service.getMoney(client.getSerial(), table.currency_serial) - avatar = self.service.avatars[id] + avatars = self.service.avatar_collection.get(client.getSerial()) + self.failUnless(len(avatars) == 1, "Only one avatar should have this serial") + avatar = avatars[0] avatar.queuePackets() avatar.handlePacketLogic( PacketPokerTablePicker(serial = client.getSerial(), @@ -4433,8 +4440,9 @@ class PokerAvatarTablePickerTestCase(PokerAvatarTestCaseBaseClass): "best buy in amount is undefined or 0") self.failIf(minBuyInAmount == None or minBuyInAmount <= 0, "min buy in amount is undefined or 0") - self.assertEquals(preBuyInBalance - amountBoughtIn, - self.service.getMoney(client.getSerial(), table.currency_serial)) + if table.currency_serial > 0: + self.assertEquals(preBuyInBalance - amountBoughtIn, + self.service.getMoney(client.getSerial(), table.currency_serial)) # Next, we should never have been allowed to buy in at a table with # a minimum less than we have. self.failUnless(preBuyInBalance > minBuyInAmount) @@ -4487,6 +4495,7 @@ class PokerAvatarTablePickerTestCase(PokerAvatarTestCaseBaseClass): d.addCallback(self.login, playerNumber) return d +class PokerAvatarTablePickerTestCase(PokerAvatarTablePickerBaseClass): # ------------------------------------------------------------------------ def test00_tablePicker_failure_by_min(self): self.createClients(1) @@ -4626,6 +4635,7 @@ class PokerAvatarTablePickerTestCase(PokerAvatarTestCaseBaseClass): playersDeferreds.append(pickerDeferred) return defer.DeferredList(playersDeferreds) # ------------------------------------------------------------------------ + def test09_tablePicker_noTableDueToLackofFunds(self): self.createClients(4) @@ -4704,6 +4714,7 @@ class PokerAvatarTablePickerTestCase(PokerAvatarTestCaseBaseClass): ############################################################################## def Run(): loader = runner.TestLoader() +# loader.methodPrefix = "test15" # loader.methodPrefix = "test8" suite = loader.suiteFactory() suite.addTest(loader.loadClass(PokerAvatarTestCase))
-- -- bkuhn
_______________________________________________ Pokersource-users mailing list [email protected] https://mail.gna.org/listinfo/pokersource-users
