Пример #1
0
    def testEnoughTurnsPlayed(self):
        txq = asyncio.Queue()
        wordset = SupportedWordSets["test"]

        allConns = Connections(txq)
        team1 = mockPlyrTeam(txq, allConns, 1, {"sb": [101]}, {"sb": 2})
        team2 = mockPlyrTeam(txq, allConns, 2, {"jg": [102]}, {"jg": 2})

        teams = {1: team1, 2: team2}
        hostParameters = HostParameters(numTeams=2,
                                        turnDurationSec=30,
                                        wordSets=["test"],
                                        numTurns=2)

        for team in teams.values():
            for ws in team.conns._wss:
                allConns.addConn(ws)

        turnMgr = TurnManager("taboo:1", txq, wordset, teams, hostParameters, allConns, None)

        self.assertFalse(turnMgr.startNewTurn())
        self.assertGiTxQueueMsgs(txq, [
            ClientTxMsg(['PLAYER-STATUS', 'jg', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101}),
            ClientTxMsg(['PLAYER-STATUS', 'sb', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101}),
            ClientTxMsg(['PLAYER-STATUS', 'jg', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {102}),
            ClientTxMsg(['PLAYER-STATUS', 'sb', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {102}),
            ClientTxMsg(["SCORE", {1: 0, 2: 0}],
                        {101, 102}),
        ], anyOrder=True)
Пример #2
0
    def __processReady(self, qmsg):
        """
        ["READY"]
        """
        ws = qmsg.initiatorWs

        if len(qmsg.jmsg) != 1:
            self.txQueue.put_nowait(ClientTxMsg(["READY-BAD", "Invalid message length"],
                                                {ws}, initiatorWs=ws))
            return True

        #if self.state != GameState.WAITING_TO_START:
        #    self.txQueue.put_nowait(ClientTxMsg(["READY-BAD", "Game already started/ended"],
        #                            {ws}, initiatorWs=ws))
        #    return True

        player = self.playerByWs.get(ws, None)
        if not player:
            self.txQueue.put_nowait(ClientTxMsg(["READY-BAD", "Join first"],
                                    {ws}, initiatorWs=ws))
            return True

        if player.ready:
            self.txQueue.put_nowait(ClientTxMsg(["READY-BAD", "Already ready"],
                                    {ws}, initiatorWs=ws))
            return True

        player.ready = True
        if all(t.ready() for t in self.teams.values()):
            self.turnMgr.startNewTurn()
            self.state = GameState.RUNNING
            trace(Level.info, "Game started")

        return True
Пример #3
0
    def __processJoin(self, qmsg):
        """
        ["JOIN", playerName, team:int={0..T}]
        """
        ws = qmsg.initiatorWs

        assert ws in self.playerByWs, "Join request from an unrecognized connection"

        if self.playerByWs[ws]:
            self.txQueue.put_nowait(ClientTxMsg(["JOIN-BAD",
                                                 "Unexpected JOIN message from client that "
                                                 "has already joined"], {ws}, initiatorWs=ws))
            return True

        if len(qmsg.jmsg) != 3:
            self.txQueue.put_nowait(ClientTxMsg(["JOIN-BAD", "Invalid message length"],
                                                {ws}, initiatorWs=ws))
            return True

        _, playerName, teamNumber = qmsg.jmsg

        if not isinstance(playerName, str) or not validPlayerNameRe.match(playerName):
            self.txQueue.put_nowait(ClientTxMsg(["JOIN-BAD", "Invalid player name", playerName],
                                                {ws}, initiatorWs=ws))
            return True

        if (not isinstance(teamNumber, int) or
            teamNumber < 0 or teamNumber > self.hostParameters.numTeams):
            self.txQueue.put_nowait(ClientTxMsg(["JOIN-BAD", "Invalid team number", teamNumber],
                                                {ws}, initiatorWs=ws))
            return True

        return self.joinPlayer(ws, playerName, teamNumber)
Пример #4
0
    def __processKickoff(self, qmsg):
        """
        ["KICKOFF"]
        """
        ws = qmsg.initiatorWs

        if len(qmsg.jmsg) != 1:
            self.txQueue.put_nowait(
                ClientTxMsg(["KICKOFF-BAD", "Invalid message length"], {ws},
                            initiatorWs=ws))
            return True

        if self.state != GameState.RUNNING:
            trace(Level.play, "_processDiscard current state", self.state.name)
            self.txQueue.put_nowait(
                ClientTxMsg(["KICKOFF-BAD", "Game not running"], {ws},
                            initiatorWs=ws))
            return True

        player = self.playerByWs[ws]
        if player != self.turnMgr.activePlayer:
            trace(
                Level.play, "_processDiscard msg rcvd from",
                player.name if player else None, "activePlayer",
                self.turnMgr.activePlayer.name
                if self.turnMgr.activePlayer else None)
            self.txQueue.put_nowait(
                ClientTxMsg(["KICKOFF-BAD", "It is not your turn"], {ws},
                            initiatorWs=ws))
            return True

        return self.turnMgr.processKickoff(qmsg)
Пример #5
0
    def testHandleGiStatusWithConnections(self):
        """Handling of InternalGiStatus"""
        self.plugin.conns.addConn(self.connWs1)
        self.plugin.conns.addConn(self.connWs2)

        # Process InternalGiStatus with two clients connected
        msg = InternalGiStatus([], "foo:1")
        self.plugin.processMsg(msg)

        self.assertGiTxQueueMsgs(self.txq, [ClientTxMsg(["GAME-STATUS", "foo:1"],
                                                        {self.connWs1, self.connWs2},
                                                        initiatorWs=None)])

        # Process InternalGiStatus with two clients connected: updating an existing game
        msg = InternalGiStatus([{"count": 10}], "foo:1")
        self.plugin.processMsg(msg)

        self.assertGiTxQueueMsgs(self.txq, [ClientTxMsg(["GAME-STATUS", "foo:1", {"count": 10}],
                                                        {self.connWs1, self.connWs2},
                                                        initiatorWs=None)])

        # Processing same InternalGiStatus with two clients connected
        # should not create messages
        msg = InternalGiStatus([{"count": 10}], "foo:1")
        self.plugin.processMsg(msg)
        self.assertGiTxQueueMsgs(self.txq, [])
Пример #6
0
    def testAddConnectionsAfterMsgSrc(self):
        # message source with no messages
        msgSrcEmpty = MsgSrc(self.conns)  # pylint: disable=unused-variable

        msgSrc = MsgSrc(self.conns)
        msgSrc.setMsgs([
            Jmai([1], initiatorWs=clientWs3),
            Jmai([2], initiatorWs=clientWs3)
        ])

        self.assertGiTxQueueMsgs(self.txq, [])

        # Add websockets afterwards

        conns1 = Connections(self.txq)
        conns2 = Connections(self.txq)
        conns2.addConn(clientWs2)

        self.conns.addConnections(conns1)
        self.assertGiTxQueueMsgs(self.txq, [])

        self.conns.addConnections(conns2)
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs2}, initiatorWs=clientWs3)
        ])

        conns1.addConn(clientWs1)
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs1}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs1}, initiatorWs=clientWs3)
        ])
Пример #7
0
    def processDeclare(self, qmsg):
        """
        ["DECLARE"]
        Should only be processed if:
        1. game state is player turn
        2. ws has joined
        3. player[ws].name == turn.current()
        """
        ws = qmsg.initiatorWs

        if not isinstance(self.gameState, StatePlayerTurn):
            self.txQueue.put_nowait(
                ClientTxMsg(["DECLARE-BAD", "Can't make moves now"], {ws},
                            initiatorWs=ws))
            return True

        if self.playerByWs[ws] is None:
            self.txQueue.put_nowait(
                ClientTxMsg(["DECLARE-BAD", "You must join the game first"],
                            {ws},
                            initiatorWs=ws))
            return True

        if self.playerByWs[ws].name != self.currRound.turn.current():
            self.txQueue.put_nowait(
                ClientTxMsg(["DECLARE-BAD", "It is not your turn"], {ws},
                            initiatorWs=ws))
            return True

        if len(qmsg.jmsg) != 1:
            self.txQueue.put_nowait(
                ClientTxMsg(["DECLARE-BAD", "Invalid message length"], {ws},
                            initiatorWs=ws))
            return True

        event = self.currRound.rule.processDeclare(self.currRound,
                                                   self.playerByWs[ws])

        if not event:
            self.txQueue.put_nowait(
                ClientTxMsg(["DECLARE-BAD", "Invalid declare"], {ws},
                            initiatorWs=ws))
        else:
            jmsg = [
                "UPDATE", self.currRound.roundParams.roundNum, {
                    "DECLARE": event.toJmsg()
                }
            ]
            self.broadcast(jmsg)
            self.processEvent(event)

        return True
Пример #8
0
    def __validateCompletedOrDiscard(self, qmsg):
        """ Validates [COMPLETED|DISCARD, turn<int>, wordIdx<int>]
        Replies a DISCARD-BAD or COMPLETED-BAD if the message is
        received at wrong turn state

        Returns True iff message is valid
        """
        msgType = qmsg.jmsg[0]
        assert msgType in ("DISCARD", "COMPLETED")
        badReplyType = "{}-BAD".format(msgType)

        ws = qmsg.initiatorWs

        if self._state != TurnMgrState.RUNNING:
            trace(Level.play, "process{} turn state".format(msgType),
                  self._state.name)
            self._txQueue.put_nowait(
                ClientTxMsg(
                    [badReplyType, "Can't {} right now".format(msgType)], {ws},
                    initiatorWs=ws))
            return False

        if qmsg.jmsg[1] != self._curTurnId:
            self._txQueue.put_nowait(
                ClientTxMsg([badReplyType, "Invalid turn"], {ws},
                            initiatorWs=ws))
            return False

        assert self._curTurnId in self._wordsByTurnId, (
            "Since the turn is in running state, {} must exist in {}".format(
                self._curTurnId, self._wordsByTurnId.keys()))

        assert self._wordsByTurnId[self._curTurnId], (
            "Since the turn is in running state, there must be at least 1 word in {}"
            .format(self._wordsByTurnId[self._curTurnId]))

        lastWord = self._wordsByTurnId[self._curTurnId][-1]

        if qmsg.jmsg[2] != lastWord.wordId:
            self._txQueue.put_nowait(
                ClientTxMsg([badReplyType, "Invalid word"], {ws},
                            initiatorWs=ws))
            return False

        if lastWord.state != WordState.IN_PLAY:
            self._txQueue.put_nowait(
                ClientTxMsg([badReplyType, "The word is no longer in play"],
                            {ws},
                            initiatorWs=ws))
            return False

        return True
Пример #9
0
 def __finalizeJoin(self, ws, player):
     player.addConn(ws)
     self.playerByWs[ws] = player
     self.txQueue.put_nowait(
         ClientTxMsg(["JOIN-OKAY", player.name, player.team.teamNumber],
                     {ws},
                     initiatorWs=ws))
Пример #10
0
    def processHost(self, qmsg):
        """
        original_message = [
            "HOST", "taboo",
            {"numTeams": <int>,         # 1..4
             "turnDurationSec": <int>,  # 30..180
             "wordSets": ["name1", "name2", ...]}]

        qmsg.jmsg = original_message[2:]
        """
        try:
            hostParameters = HostParameters.fromJmsg(qmsg.jmsg)
        except InvalidDataException as exc:
            self.txQueue.put_nowait(
                ClientTxMsg([MTYPE_HOST_BAD] + exc.toJmsg(),
                            {qmsg.initiatorWs},
                            initiatorWs=qmsg.initiatorWs))
            return True

        self.gameIdx += 1

        newRoom = TabooRoom("taboo:{}".format(self.gameIdx),
                            "Taboo Room #{}".format(self.gameIdx),
                            hostParameters)
        self.rooms[self.gameIdx] = newRoom
        self.txQueue.put_nowait(
            InternalRegisterGi(newRoom, initiatorWs=qmsg.initiatorWs))

        return True
Пример #11
0
    def __validateCompletedOrDiscard(self, qmsg):
        """ Validates [COMPLETED|DISCARD, turn<int>, wordIdx<int>]
        Replies a DISCARD-BAD or COMPLETED-BAD if the message is incorrect,
        or if the message is received at wrong game state

        Returns True iff message format is valid
        """
        msgType = qmsg.jmsg[0]
        assert msgType in ("DISCARD", "COMPLETED")
        badReplyType = "{}-BAD".format(msgType)

        ws = qmsg.initiatorWs

        if len(qmsg.jmsg) != 3:
            self.txQueue.put_nowait(
                ClientTxMsg([badReplyType, "Invalid message length"], {ws},
                            initiatorWs=ws))
            return False

        if (not isinstance(qmsg.jmsg[1], int)) or (not isinstance(
                qmsg.jmsg[2], int)):
            self.txQueue.put_nowait(
                ClientTxMsg([badReplyType, "Invalid message type"], {ws},
                            initiatorWs=ws))
            return False

        if self.state != GameState.RUNNING:
            trace(Level.play, "_process{} current state".format(msgType),
                  self.state.name)
            self.txQueue.put_nowait(
                ClientTxMsg([badReplyType, "Game not running"], {ws},
                            initiatorWs=ws))
            return False

        player = self.playerByWs[ws]
        if player != self.turnMgr.activePlayer:
            trace(
                Level.play, "_process{} msg rcvd from".format(msgType),
                player.name if player else None, "activePlayer",
                self.turnMgr.activePlayer.name
                if self.turnMgr.activePlayer else None)
            self.txQueue.put_nowait(
                ClientTxMsg([badReplyType, "It is not your turn"], {ws},
                            initiatorWs=ws))
            return False

        return True
Пример #12
0
    def testBasic(self):
        txq = asyncio.Queue()
        wordset = SupportedWordSets["test"]
        with stub(wordset, "nextWord", self.mockNextWord):
            allConns = Connections(txq)
            team1 = mockPlyrTeam(txq, allConns, 1, {"sb1": [101], "sb2": [102]}, {})
            team2 = mockPlyrTeam(txq, allConns, 2, {"jg1": [201], "jg2": [202]}, {})

            teams = {1: team1, 2: team2}
            hostParameters = HostParameters(numTeams=2,
                                            turnDurationSec=30,
                                            wordSets=["test"],
                                            numTurns=2)

            for team in teams.values():
                for ws in team.conns._wss:
                    allConns.addConn(ws)
            self.drainGiTxQueue(txq)

            turnMgr = TurnManager("taboo:1", txq, wordset, teams, hostParameters, allConns, None)
            def mockFindNextPlayer():
                return team2.members["jg1"]
            stub1 = stub(turnMgr, "_findNextPlayer", mockFindNextPlayer)
            stub1.__enter__() # pylint: disable=no-member

            self.assertGiTxQueueMsgs(txq, [
                ClientTxMsg(["SCORE", {1: 0, 2: 0}],
                            {101, 102, 201, 202}),
            ], anyOrder=True)

            self.assertTrue(turnMgr.startNewTurn())
            self.assertGiTxQueueMsgs(txq, [
                ClientTxMsg(["WAIT-FOR-KICKOFF", 1, "jg1"], {101, 102, 201, 202}, None),
            ])

            self.assertTrue(turnMgr.startNextWord())
            secretMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                        'utcTimeout': None,  # We didn't send KICKOFF explicitly
                                        'secret': 'c', 'disallowed': ['c1', 'c2']}]
            publicMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                        'utcTimeout': None}]
            self.assertGiTxQueueMsgs(txq, [
                ClientTxMsg(publicMsg, {101, 102, 201, 202}),
                ClientTxMsg(secretMsg, {101, 102}),
                ClientTxMsg(secretMsg, {201}),
            ], anyOrder=True)
Пример #13
0
    def processRefresh(self, qmsg):
        if qmsg.jmsg[1] in SupportedWordSets:
            try:
                SupportedWordSets[qmsg.jmsg[1]].loadData()
            except Exception as exc:  # pylint: disable=broad-except
                trace(Level.error, "Failed to refresh", qmsg.jmsg[1], str(exc))
                self.txQueue.put_nowait(
                    ClientTxMsg(["REFRESH-BAD"], {qmsg.initiatorWs},
                                initiatorWs=qmsg.initiatorWs))

        return False  # Pretend message wasn't understood
Пример #14
0
    def testHandleNewConnection(self):
        """Handling of InternalGiStatus when a new client (connWs2)
        connects when (connWs1) is already connected"""
        self.plugin.giStatusByPath["foo:1"] = [True]

        self.plugin.conns.addConn(self.connWs1)

        # Process InternalGiStatus with two clients connected
        msg = InternalConnectWsToGi(self.connWs2)
        self.plugin.processMsg(msg)
        self.assertGiTxQueueMsgs(self.txq, [ClientTxMsg(["GAME-STATUS", "foo:1", True],
                                                        {self.connWs2}, initiatorWs=None)])
Пример #15
0
    def testNewGame(self):
        env = self.setUpTabooRoom()

        self.assertGiTxQueueMsgs(env.txq, [
            InternalGiStatus([
                {"hostParameters": {"numTeams": 2,
                                    "turnDurationSec": 30,
                                    "wordSets": ["test"],
                                    "numTurns": 1},
                 "gameState": "WAITING_TO_START",
                 "clientCount": {1: {}, 2: {}},
                 "winners": []}
            ], "taboo:1"),
        ], anyOrder=True)

        ws1 = 1
        env.room.processConnect(ws1)

        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["TEAM-STATUS", 1, []], {ws1}),
            ClientTxMsg(["TEAM-STATUS", 2, []], {ws1}),
            ClientTxMsg(['HOST-PARAMETERS', {'numTeams': 2,
                                             'turnDurationSec': 30,
                                             'wordSets': ['test'],
                                             'numTurns': 1}], {ws1}),
            ClientTxMsg(["SCORE", {1: 0, 2: 0}],
                        {ws1}),
            InternalGiStatus([
                {"hostParameters": {"numTeams": 2,
                                    "turnDurationSec": 30,
                                    "wordSets": ["test"],
                                    "numTurns": 1},
                 "gameState": "WAITING_TO_START",
                 "clientCount": {1: {}, 2: {}},
                 "winners":[]
                }
            ], "taboo:1"),
        ], anyOrder=True)
Пример #16
0
    def processHost(self, qmsg):
        if qmsg.jmsg:
            self.txQueue.put_nowait(
                ClientTxMsg([MTYPE_HOST_BAD, "Unexpected parameters"],
                            {qmsg.initiatorWs},
                            initiatorWs=qmsg.initiatorWs))
            return True

        self.gameIdx += 1
        newRoom = ChatRoom("chat:{}".format(self.gameIdx),
                           "Chat Room #{}".format(self.gameIdx))
        self.rooms[self.gameIdx] = newRoom

        self.txQueue.put_nowait(
            InternalRegisterGi(newRoom, initiatorWs=qmsg.initiatorWs))
        return True
Пример #17
0
    def testHandleMsg(self):
        """Received messages are broadcast to all clients"""
        self.testInstantiation()

        self.plugin.conns.addConn(self.connWs1)
        self.plugin.conns.addConn(self.connWs2)

        fakeWs = 55
        msg = ClientRxMsg(["foo", 2, True, {"count": 3}], initiatorWs=fakeWs)
        self.plugin.processMsg(msg)
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg(["foo", 2, True, {
                "count": 3
            }], {self.connWs1, self.connWs2},
                        initiatorWs=fakeWs)
        ])
Пример #18
0
    def send(self, jmaiList, wss=None):
        """Send the messages to a subset (or all) connections
        Arguments
        ---------
        jmsgs : list of messages
        wss : (optional) set of websockets
            Websockets to send the messages. If not specified,
            send the message to all websockets.
        """
        wss = wss or self._wss
        if not wss:
            return

        for jmai in jmaiList:
            self._txQueue.put_nowait(
                ClientTxMsg(jmai.jmsg, wss, initiatorWs=jmai.initiatorWs))
Пример #19
0
    async def worker(self):
        """The worker task for a plugin. All messages should be processed.
        Any unhandled message returns a bad message to the sender"""
        trace(Level.game, "{}.worker() ready".format(self.path))
        while True:
            qmsg = await self.rxQueue.get()
            self.rxQueue.task_done()
            trace(Level.msg, self.path, "received", str(qmsg))

            processed = self.processMsg(qmsg)
            if not processed:
                if not isinstance(qmsg, ClientRxMsg):
                    trace(Level.error, "Unexpected message not handled:",
                          str(qmsg))
                    continue
                self.txQueue.put_nowait(
                    ClientTxMsg("Bad message", {qmsg.initiatorWs},
                                initiatorWs=qmsg.initiatorWs))
Пример #20
0
    def processHost(self, qmsg):
        try:
            hostParameters = RoundParameters.fromJmsg(qmsg.jmsg)
        except InvalidDataException as exc:
            self.txQueue.put_nowait(
                ClientTxMsg([MTYPE_HOST_BAD] + exc.toJmsg(),
                            {qmsg.initiatorWs},
                            initiatorWs=qmsg.initiatorWs))
            return True

        self.gameIdx += 1
        newRoom = Dirty7Room("dirty7:{}".format(self.gameIdx),
                             "Dirty7 Room #{}".format(self.gameIdx),
                             self.storage, hostParameters)
        self.rooms[self.gameIdx] = newRoom

        self.txQueue.put_nowait(
            InternalRegisterGi(newRoom, initiatorWs=qmsg.initiatorWs))
        return True
Пример #21
0
    def processKickoff(self, qmsg):
        """Always returns True (implies message ingested)"""
        ws = qmsg.initiatorWs

        if self._state != TurnMgrState.KICKOFF_WAIT:
            self._txQueue.put_nowait(
                ClientTxMsg(["KICKOFF-BAD", "Can't kickoff a turn"], {ws},
                            initiatorWs=ws))
            return True

        # Start with a new word for the activePlayer

        ctx = {"turnId": self._curTurnId}
        self._txQueue.put_nowait(
            TimerRequest(self.turnDurationSec, self.timerExpiredCb, ctx))
        self._utcTimeout = expiryEpoch(self.turnDurationSec)

        assert self.startNextWord(
        ) is True, "Must always be able to start a new word"
        return True
Пример #22
0
    def testAddDelConnections(self):
        conns1 = Connections(self.txq)
        conns1.addConn(clientWs1)
        conns2 = Connections(self.txq)
        conns2.addConn(clientWs2)

        self.conns.addConnections(conns1)
        self.conns.addConnections(conns2)

        msgSrc = MsgSrc(self.conns)
        msgSrc.setMsgs([
            Jmai([1], initiatorWs=clientWs3),
            Jmai([2], initiatorWs=clientWs3)
        ])

        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs1}, initiatorWs=clientWs3),
            ClientTxMsg([1], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs1}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs2}, initiatorWs=clientWs3)
        ],
                                 anyOrder=True)

        self.conns.delConnections(conns1)

        clientWs4 = 104
        conns3 = Connections(self.txq)
        conns3.addConn(clientWs3)
        conns3.addConn(clientWs4)

        self.conns.addConnections(conns3)

        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs3, clientWs4}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs3, clientWs4}, initiatorWs=clientWs3)
        ],
                                 anyOrder=True)
Пример #23
0
    def processPlay(self, qmsg):
        """
        ["PLAY", {"dropCards": list of cards,
                  "numDrawCards": int,
                  "pickCards": list of cards}]
        Should only be processed if:
        1. game state is player turn
        2. ws has joined
        3. player[ws].name == turn.current()
        """
        ws = qmsg.initiatorWs

        if not isinstance(self.gameState, StatePlayerTurn):
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD", "Can't make moves now"], {ws},
                            initiatorWs=ws))
            return True

        if self.playerByWs[ws] is None:
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD", "You must join the game first"], {ws},
                            initiatorWs=ws))
            return True

        if self.playerByWs[ws].name != self.currRound.turn.current():
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD", "It is not your turn"], {ws},
                            initiatorWs=ws))
            return True

        if len(qmsg.jmsg) != 2:
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD", "Invalid message length"], {ws},
                            initiatorWs=ws))
            return True

        playDesc = qmsg.jmsg[1]
        if not isinstance(playDesc, dict):
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD", "Invalid move description"], {ws},
                            initiatorWs=ws))
            return True
        playDesc = dict(playDesc)

        # dropCards
        dropCards = playDesc.pop("dropCards", [])
        if not isinstance(dropCards, list):
            self.txQueue.put_nowait(
                ClientTxMsg(
                    ["PLAY-BAD", "Invalid cards being dropped", dropCards],
                    {ws},
                    initiatorWs=ws))
            return True

        try:
            dropCards = [Card.fromJmsg(cd) for cd in dropCards]
        except InvalidDataException as exc:
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD"] + exc.toJmsg(), {ws}, initiatorWs=ws))
            return True

        # numDrawCards
        numDrawCards = playDesc.pop("numDrawCards", 0)
        if not isinstance(numDrawCards, int):
            self.txQueue.put_nowait(
                ClientTxMsg([
                    "PLAY-BAD", "Drawing invalid number of cards", numDrawCards
                ], {ws},
                            initiatorWs=ws))
            return True

        # pickCards
        pickCards = playDesc.pop("pickCards", [])
        if not isinstance(pickCards, list):
            self.txQueue.put_nowait(
                ClientTxMsg(
                    ["PLAY-BAD", "Invalid cards being drawn", pickCards], {ws},
                    initiatorWs=ws))
            return True

        try:
            pickCards = [Card.fromJmsg(cd) for cd in pickCards]
        except InvalidDataException as exc:
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD"] + exc.toJmsg(), {ws}, initiatorWs=ws))
            return True

        # If item remain in play-description, complain
        if playDesc:
            self.txQueue.put_nowait(
                ClientTxMsg(
                    ["PLAY-BAD", "Unrecognized play description", playDesc],
                    {ws},
                    initiatorWs=ws))
            return True

        # If the deck doesn't have numDrawCards
        if self.currRound.tableCards.deckCardCount() < numDrawCards:
            self.txQueue.put_nowait(
                ClientTxMsg([
                    "PLAY-BAD", "Drawing invalid number of cards", numDrawCards
                ], {ws},
                            initiatorWs=ws))
            return None

        # pickCards should be in revealedCards
        if not self.currRound.tableCards.revealedCardsContains(pickCards):
            self.txQueue.put_nowait(
                ClientTxMsg([
                    "PLAY-BAD", "Picking cards not available",
                    [cd.toJmsg() for cd in pickCards]
                ], {ws},
                            initiatorWs=ws))
            return True

        event = self.currRound.rule.processPlay(self.currRound,
                                                self.playerByWs[ws], dropCards,
                                                numDrawCards, pickCards)

        if not event:
            self.txQueue.put_nowait(
                ClientTxMsg(["PLAY-BAD", "Invalid play"], {ws},
                            initiatorWs=ws))
        else:
            jmsg = [
                "UPDATE", self.currRound.roundParams.roundNum, {
                    "PLAY": [
                        self.playerByWs[ws].name,
                        [cd.toJmsg() for cd in dropCards], numDrawCards,
                        [cd.toJmsg() for cd in pickCards]
                    ] + event.toJmsg()
                }
            ]
            self.broadcast(jmsg)
            self.processEvent(event)

        return True
Пример #24
0
    def test1MsgSrc1Websocket(self):
        """
        Try various triggers of adding/removing MsgSrcs and Websockets
        """
        self.assertGiTxQueueMsgs(self.txq, [])

        # Adding connections doesn't create a message
        self.conns.addConn(clientWs1)
        self.assertGiTxQueueMsgs(self.txq, [])

        # Adding msgSrc with no messages
        msgSrc1 = MsgSrc(self.conns)
        self.assertGiTxQueueMsgs(self.txq, [])

        # Set messages in msgSrc
        msgSrc1.setMsgs([
            Jmai([1], initiatorWs=clientWs3),
            Jmai([2], initiatorWs=clientWs3)
        ])
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs1}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs1}, initiatorWs=clientWs3)
        ])

        # Adding msgSrc with previous messages
        msgSrc2 = MsgSrc(self.conns)
        msgSrc2.setMsgs(
            [Jmai([True], initiatorWs=None),
             Jmai([False], initiatorWs=None)])
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([True], {clientWs1}),
            ClientTxMsg([False], {clientWs1})
        ])

        # Adding a second connection
        self.conns.addConn(clientWs2)
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs2}, initiatorWs=clientWs3),
            ClientTxMsg([True], {clientWs2}, initiatorWs=None),
            ClientTxMsg([False], {clientWs2}, initiatorWs=None)
        ],
                                 anyOrder=True)

        # Adding msgSrc with state preset
        msgSrc2.setMsgs([Jmai(["yes"], initiatorWs=None)])
        self.assertGiTxQueueMsgs(
            self.txq, [ClientTxMsg(["yes"], {clientWs1, clientWs2})])

        # Delete msgSrc
        self.conns.delMsgSrc(msgSrc2)

        # Add another client
        self.conns.addConn(clientWs3)
        self.assertSetEqual(self.conns.msgSrcs, {msgSrc1})
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg([1], {clientWs3}, initiatorWs=clientWs3),
            ClientTxMsg([2], {clientWs3}, initiatorWs=clientWs3)
        ],
                                 anyOrder=True)

        # Remove a client
        self.conns.delConn(clientWs2)
        self.assertGiTxQueueMsgs(self.txq, [])

        # Add msgSrc2 again
        self.conns.addMsgSrc(msgSrc2)
        self.assertGiTxQueueMsgs(
            self.txq,
            [ClientTxMsg(["yes"], {clientWs1, clientWs3}, initiatorWs=None)],
            anyOrder=True)
Пример #25
0
    def testReady(self):
        env = self.setUpTabooRoom()
        self.drainGiTxQueue(env.txq)

        env.room.state = TabooRoom.GameState.WAITING_TO_START

        env.room.processMsg(ClientRxMsg(["READY", "stuff"], 101))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["READY-BAD", "Invalid message length"], {101}, 101),
        ])

        env.room.processMsg(ClientRxMsg(["READY"], 101))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["READY-BAD", "Join first"], {101}, 101),
        ])

        self.setUpTeamPlayer(env, 1, "sb1", [101])
        self.setUpTeamPlayer(env, 1, "sb2", [102])
        self.setUpTeamPlayer(env, 2, "jg1", [201])
        self.setUpTeamPlayer(env, 2, "jg2", [202])
        self.drainGiTxQueue(env.txq)

        def mockFindNextPlayer(remainingPlayers=[
                env.room.playerByWs[201],
                env.room.playerByWs[101],
                env.room.playerByWs[202],
            ]):
            if remainingPlayers:
                return remainingPlayers.pop(0)
            return None
        with stub(env.room.turnMgr, "_findNextPlayer", mockFindNextPlayer):
            env.room.processMsg(ClientRxMsg(["READY"], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(['PLAYER-STATUS', 'sb1', {'numConns': 1,
                                                      'ready': True,
                                                      'turnsPlayed': 0}],
                            {101, 102, 201, 202}),
            ])
            self.assertEqual(env.room.state, TabooRoom.GameState.WAITING_TO_START)
            env.room.processMsg(ClientRxMsg(["READY"], 102))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(['PLAYER-STATUS', 'sb2', {'numConns': 1,
                                                      'ready': True,
                                                      'turnsPlayed': 0}],
                            {101, 102, 201, 202}),
            ])
            self.assertEqual(env.room.state, TabooRoom.GameState.WAITING_TO_START)
            env.room.processMsg(ClientRxMsg(["READY"], 201))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(['PLAYER-STATUS', 'jg1', {'numConns': 1,
                                                      'ready': True,
                                                      'turnsPlayed': 0}],
                            {101, 102, 201, 202}),
            ])
            self.assertEqual(env.room.state, TabooRoom.GameState.WAITING_TO_START)

            #If a player sends READY multiple times, it is replied with a READY-BAD
            env.room.processMsg(ClientRxMsg(["READY"], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(['READY-BAD', 'Already ready'], {101}, 101)
            ])

            #READY from last of the (initial) players trigger start of the game
            env.room.processMsg(ClientRxMsg(["READY"], 202))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(['PLAYER-STATUS', 'jg2', {'numConns': 1,
                                                      'ready': True,
                                                      'turnsPlayed': 0}],
                            {101, 102, 201, 202}),
                ClientTxMsg(["WAIT-FOR-KICKOFF", 1, "jg1"], {101, 102, 201, 202}, None),
            ])
            self.assertEqual(env.room.state, TabooRoom.GameState.RUNNING)

            #A late-joinee is connected in READY state when it joins
            self.setUpTeamPlayer(env, 1, "sb3", [103])
            self.drainGiTxQueue(env.txq)
            env.room.processMsg(ClientRxMsg(["READY"], 103))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(['READY-BAD', 'Already ready'], {103}, 103)
            ])
Пример #26
0
    def testJoin(self):
        env = self.setUpTabooRoom()
        ws1 = 101
        env.room.processConnect(ws1)
        self.drainGiTxQueue(env.txq)

        env.room.processMsg(ClientRxMsg(["JOIN"], ws1))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["JOIN-BAD", "Invalid message length"], {ws1}, ws1),
        ])

        env.room.processMsg(ClientRxMsg(["JOIN", "sb1", -1], ws1))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["JOIN-BAD", "Invalid team number", -1], {ws1}, ws1),
        ])

        env.room.processMsg(ClientRxMsg(["JOIN", "sb1", 3], ws1))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["JOIN-BAD", "Invalid team number", 3], {ws1}, ws1),
        ])

        env.room.processMsg(ClientRxMsg(["JOIN", "#$H", 1], ws1))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["JOIN-BAD", "Invalid player name", "#$H"], {ws1}, ws1),
        ])

        #Good join - specified team number
        env.room.processMsg(ClientRxMsg(["JOIN", "sb1", 1], ws1))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(['PLAYER-STATUS', 'sb1', {'numConns': 0, 'ready': False, 'turnsPlayed': 0}],
                        {101}),
            ClientTxMsg(['PLAYER-STATUS', 'sb1', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101}),
            ClientTxMsg(["TEAM-STATUS", 1, ["sb1"]], {101}),
            ClientTxMsg(["JOIN-OKAY", "sb1", 1], {ws1}, ws1),
        ], anyOrder=True)

        #Join more players
        self.setUpTeamPlayer(env, 1, "sb2", [102])
        self.setUpTeamPlayer(env, 2, "jg1", [201])
        self.setUpTeamPlayer(env, 2, "jg2", [202])
        #Join one more player in team 2
        self.setUpTeamPlayer(env, 2, "jg3", [203])
        self.drainGiTxQueue(env.txq)

        #A random-team join (team = 0) should lead to "water-fill"
        ws2 = 1001
        env.room.processConnect(ws2)
        self.drainGiTxQueue(env.txq)
        env.room.processMsg(ClientRxMsg(["JOIN", "xx", 0], ws2))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["TEAM-STATUS", 1, ["sb1", "sb2", "xx"]],
                        {101, 102, 201, 202, 203, 1001}),
            ClientTxMsg(['PLAYER-STATUS', 'xx', {'numConns': 0, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001}),
            ClientTxMsg(['PLAYER-STATUS', 'xx', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001}),
            ClientTxMsg(["JOIN-OKAY", "xx", 1], {ws2}, ws2),
        ], anyOrder=True)

        #Now run a bunch of new JOINs on team 2
        self.setUpTeamPlayer(env, 2, "jg4", [204])
        self.setUpTeamPlayer(env, 2, "jg5", [205])

        # The next two random JOINs should be assgnd team 1
        ws2 = ws2 + 1
        env.room.processConnect(ws2)
        self.drainGiTxQueue(env.txq)
        env.room.processMsg(ClientRxMsg(["JOIN", "yy", 0], ws2))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["TEAM-STATUS", 1, ["sb1", "sb2", "xx", "yy"]],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002}),
            ClientTxMsg(['PLAYER-STATUS', 'yy', {'numConns': 0, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002}),
            ClientTxMsg(['PLAYER-STATUS', 'yy', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002}),
            ClientTxMsg(["JOIN-OKAY", "yy", 1], {ws2}, ws2),
        ], anyOrder=True)

        ws2 = ws2 + 1
        env.room.processConnect(ws2)
        self.drainGiTxQueue(env.txq)
        env.room.processMsg(ClientRxMsg(["JOIN", "zz", 0], ws2))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(["TEAM-STATUS", 1, ["sb1", "sb2", "xx", "yy", "zz"]],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002, 1003}),
            ClientTxMsg(['PLAYER-STATUS', 'zz', {'numConns': 0, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002, 1003}),
            ClientTxMsg(['PLAYER-STATUS', 'zz', {'numConns': 1, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002, 1003}),
            ClientTxMsg(["JOIN-OKAY", "zz", 1], {ws2}, ws2),
        ], anyOrder=True)

        #A JOIN from an unrecognized ws ofc leads to assert
        with self.assertRaises(AssertionError):
            env.room.processMsg(ClientRxMsg(["JOIN", "zz", 0], ws2+1))

        #A re-JOIN from a plyr forces it to its original team
        env.room.processConnect(2001)
        self.drainGiTxQueue(env.txq)
        env.room.processMsg(ClientRxMsg(["JOIN", "jg1", 1], 2001))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(['PLAYER-STATUS', 'jg1', {'numConns': 2, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002, 1003, 2001}),
            ClientTxMsg(["JOIN-OKAY", "jg1", 2], {2001}, 2001),
        ])

        #A re-JOIN from a plyr forces it to its original team
        env.room.processConnect(2002)
        self.drainGiTxQueue(env.txq)
        env.room.processMsg(ClientRxMsg(["JOIN", "jg1", 0], 2002))
        self.assertGiTxQueueMsgs(env.txq, [
            ClientTxMsg(['PLAYER-STATUS', 'jg1', {'numConns': 3, 'ready': False, 'turnsPlayed': 0}],
                        {101, 102, 201, 202, 203, 1001, 204, 205, 1002, 1003, 2001, 2002}),
            ClientTxMsg(["JOIN-OKAY", "jg1", 2], {2002}, 2002),
        ])
Пример #27
0
    def testBasic(self):
        turn = self.setUpWord()

        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg(["TEAM-STATUS", 1, []],
                        {101, 102, 103}),
            ClientTxMsg(["TEAM-STATUS", 1, ['sb']],
                        {101, 102, 103}),
            ClientTxMsg(["TEAM-STATUS", 2, []],
                        {101, 102, 103}),
            ClientTxMsg(["TURN", 1, 1, {"team": 1, "player": "sb", "state": "IN_PLAY",
                                        "utcTimeout": 30}],
                        {101, 102, 103}),
            ClientTxMsg(["TURN", 1, 1, {"team": 1, "player": "sb", "state": "IN_PLAY",
                                        "utcTimeout": 30,
                                        "secret": "a",
                                        "disallowed": ["a1", "a2"]}],
                        {101}),
            ClientTxMsg(["TURN", 1, 1, {"team": 1, "player": "sb", "state": "IN_PLAY",
                                        "utcTimeout": 30,
                                        "secret": "a",
                                        "disallowed": ["a1", "a2"]}],
                        {102}),
            ClientTxMsg(["PLAYER-STATUS", "sb", {"numConns": 1,
                                                 "ready": False,
                                                 "turnsPlayed": 0}],
                        {101, 102, 103}),
        ], anyOrder=True)
        self.assertIsNotNone(turn._privateMsgSrc)

        turn._state = WordState.COMPLETED
        turn._score = [1]
        turn.updateMsgs()
        self.assertIsNone(turn._privateMsgSrc) # privateMsgSrc should be deleted
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg(["TURN", 1, 1, {"team": 1, "player": "sb", "state": "COMPLETED",
                                        "secret": "a",
                                        "disallowed": ["a1", "a2"],
                                        "score": [1]}],
                        {101, 102, 103}),
        ], anyOrder=True)

        turn._state = WordState.DISCARDED
        turn._score = [2]
        turn.updateMsgs()
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg(["TURN", 1, 1, {"team": 1, "player": "sb", "state": "DISCARDED",
                                        "secret": "a",
                                        "disallowed": ["a1", "a2"],
                                        "score": [2]}],
                        {101, 102, 103}),
        ], anyOrder=True)

        turn._state = WordState.TIMED_OUT
        turn._score = [2]
        turn.updateMsgs()
        self.assertGiTxQueueMsgs(self.txq, [
            ClientTxMsg(["TURN", 1, 1, {"team": 1, "player": "sb", "state": "TIMED_OUT",
                                        "secret": "a",
                                        "disallowed": ["a1", "a2"],
                                        "score": [2]}],
                        {101, 102, 103}),
        ], anyOrder=True)
Пример #28
0
    def testCompleted(self):
        env = self.setUpTabooRoom()
        self.drainGiTxQueue(env.txq)

        with stubs([(SupportedWordSets["test"], "nextWord", self.mockNextWord),
                    (Taboo.TurnManager, "expiryEpoch", stubExpiryEpochGen())]):
            env.room.processMsg(ClientRxMsg(["COMPLETED"], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(["COMPLETED-BAD", "Invalid message length"], {101}, 101),
            ])

            env.room.processMsg(ClientRxMsg(["COMPLETED", "foo", 1], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(["COMPLETED-BAD", "Invalid message type"], {101}, 101),
            ])

            env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 1], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(["COMPLETED-BAD", "Game not running"], {101}, 101),
            ])

            self.setUpTeamPlayer(env, 1, "sb1", [101])
            self.setUpTeamPlayer(env, 1, "sb2", [102])
            self.setUpTeamPlayer(env, 2, "jg1", [201])
            self.setUpTeamPlayer(env, 2, "jg2", [202])

            def mockFindNextPlayer(remainingPlayers=[
                    env.room.playerByWs[201],
                    env.room.playerByWs[101],
                    env.room.playerByWs[202],
                ]):
                if remainingPlayers:
                    return remainingPlayers.pop(0)
                return None
            with stub(env.room.turnMgr, "_findNextPlayer", mockFindNextPlayer):
                env.room._allPlayersReady()
                self.drainGiTxQueue(env.txq)

                env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 1], 101))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["COMPLETED-BAD", "It is not your turn"], {101}, 101),
                ])

                env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 1], 201))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["COMPLETED-BAD", "Can't COMPLETED right now"], {201}, 201), #sic
                ])

                # KICKOFF turn
                env.room.processMsg(ClientRxMsg(["KICKOFF"], 201))
                self.drainGiTxQueue(env.txq)

                env.room.processMsg(ClientRxMsg(["COMPLETED", 0, 1], 201))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["COMPLETED-BAD", "Invalid turn"], {201}, 201),
                ])

                env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 0], 201))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["COMPLETED-BAD", "Invalid word"], {201}, 201),
                ])

                env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 1], 201))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["TURN", 1, 1, {"team": 2, "player": "jg1", "state": "COMPLETED",
                                                "secret": "c",
                                                "disallowed": ["c1", "c2"],
                                                "score": [2]}],
                                {101, 102, 201, 202}),
                    ClientTxMsg(["SCORE", {1: 0, 2: 1}],
                                {101, 102, 201, 202}),
                    ClientTxMsg(["TURN", 1, 2, {"team": 2, "player": "jg1", "state": "IN_PLAY",
                                                "utcTimeout": 30}],
                                {101, 102, 201, 202}),
                    ClientTxMsg(["TURN", 1, 2, {"team": 2, "player": "jg1", "state": "IN_PLAY",
                                                "utcTimeout": 30,
                                                "secret": "a",
                                                "disallowed": ["a1", "a2"]}],
                                {201}),
                    ClientTxMsg(["TURN", 1, 2, {"team": 2, "player": "jg1", "state": "IN_PLAY",
                                                "utcTimeout": 30,
                                                "secret": "a",
                                                "disallowed": ["a1", "a2"]}],
                                {101, 102}),
                ], anyOrder=True)
                self.assertEqual(env.room.teams[2].members['jg1'].turnsPlayed, 0)

                env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 2], 201))
                self.drainGiTxQueue(env.txq)

                env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 3], 201))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["TURN", 1, 3, {"team": 2, "player": "jg1", "state": "COMPLETED",
                                                "secret": "b",
                                                "disallowed": ["b1", "b2"],
                                                "score": [2]}],
                                {101, 102, 201, 202}),
                    ClientTxMsg(["SCORE", {1: 0, 2: 3}],
                                {101, 102, 201, 202}),
                    ClientTxMsg(["GAME-OVER", [2]],
                                {101, 102, 201, 202}),
                    InternalGiStatus([
                        {"hostParameters": {"numTeams": 2,
                                            "turnDurationSec": 30,
                                            "wordSets": ["test"],
                                            "numTurns": 1},
                         "gameState": "GAME_OVER",
                         "clientCount": {1: {'sb1': 1, 'sb2': 1}, 2: {'jg1': 1, 'jg2': 1}},
                         "winners": [2]
                        }
                    ], "taboo:1"),
                ], anyOrder=True)
                self.assertEqual(env.room.teams[2].members['jg1'].turnsPlayed, 1)

                env.room.processMsg(ClientRxMsg(["COMPLETED", 1, 3], 201))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["COMPLETED-BAD", "Game not running"],
                                {201}, 201),
                ])
Пример #29
0
    def testTurnTimeOut(self):
        env = self.setUpTabooRoom()

        env.room.state = TabooRoom.GameState.RUNNING
        self.setUpTeamPlayer(env, 1, "sb1", [101])
        self.setUpTeamPlayer(env, 1, "sb2", [102])
        self.setUpTeamPlayer(env, 2, "jg1", [201])
        self.setUpTeamPlayer(env, 2, "jg2", [202])
        self.drainGiTxQueue(env.txq)

        def mockFindNextPlayer(remainingPlayers=[
                env.room.playerByWs[201],
                env.room.playerByWs[101],
                env.room.playerByWs[202],
            ]):
            if remainingPlayers:
                return remainingPlayers.pop(0)
            return None
        with stubs([(SupportedWordSets["test"], "nextWord", self.mockNextWord),
                    (Taboo.TurnManager, "expiryEpoch", stubExpiryEpochGen()),
                    (env.room.turnMgr, "_findNextPlayer", mockFindNextPlayer)]):
            env.room.turnMgr.startNewTurn()
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(["WAIT-FOR-KICKOFF", 1, "jg1"], {101, 102, 201, 202}, None),
            ], anyOrder=True)

            # Start the timer by issuing a KICKOFF
            env.room.processMsg(ClientRxMsg(["KICKOFF"], 201))
            secretMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                        'utcTimeout': 30,
                                        'secret': 'c', 'disallowed': ['c1', 'c2']}]
            publicMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                        'utcTimeout': 30}]
            self.assertGiTxQueueMsgs(env.txq, [
                TimerRequest(30, env.room.turnMgr.timerExpiredCb, {
                                "turnId": 1,
                             }),
                ClientTxMsg(secretMsg, {201}),
                ClientTxMsg(secretMsg, {101, 102}),
                ClientTxMsg(publicMsg, {101, 102, 201, 202}),
            ], anyOrder=True)
            self.assertEqual(env.room.teams[2].members['jg1'].turnsPlayed, 0)

            # Invalid turnId
            env.room.turnMgr.timerExpiredCb({"turnId": 5})

            # Valid timer expiry, starts the next turn
            env.room.turnMgr.timerExpiredCb({"turnId": 1})
            publicMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'TIMED_OUT',
                         'secret': 'c', 'disallowed': ['c1', 'c2'],
                         'score': [1]}]
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(publicMsg, {101, 102, 201, 202}),
                ClientTxMsg(["WAIT-FOR-KICKOFF", 2, "sb1"], {101, 102, 201, 202}, None),
                ClientTxMsg(["SCORE", {1: 1, 2: 0}],
                            {101, 102, 201, 202}),
            ], anyOrder=True)
            self.assertEqual(env.room.teams[2].members['jg1'].turnsPlayed, 1)

            # KICKOFF new turn, discard 1st word, let timer expire on the last word
            env.room.processMsg(ClientRxMsg(["KICKOFF"], 101))
            secretMsg = ['TURN', 2, 1, {'team': 1, 'player': 'sb1', 'state': 'IN_PLAY',
                                        'utcTimeout': 31,
                                        'secret': 'a', 'disallowed': ['a1', 'a2']}]
            publicMsg = ['TURN', 2, 1, {'team': 1, 'player': 'sb1', 'state': 'IN_PLAY',
                                        'utcTimeout': 31}]
            self.assertGiTxQueueMsgs(env.txq, [
                TimerRequest(30, env.room.turnMgr.timerExpiredCb, {
                                "turnId": 2,
                             }),
                ClientTxMsg(secretMsg, {101}),
                ClientTxMsg(secretMsg, {201, 202}),
                ClientTxMsg(publicMsg, {101, 102, 201, 202}),
            ], anyOrder=True)

            env.room.processMsg(ClientRxMsg(["DISCARD", 2, 1], 101))
            self.drainGiTxQueue(env.txq)

            with stub(env.room.turnMgr._wordSet, "areWordsAvailable",
                      lambda path: False):
                env.room.turnMgr.timerExpiredCb({"turnId": 2})
                publicMsg = ['TURN', 2, 2, {'team': 1, 'player': 'sb1', 'state': 'TIMED_OUT',
                             'secret': 'b', 'disallowed': ['b1', 'b2'],
                             'score': [2]}]
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(publicMsg, {101, 102, 201, 202}),
                    ClientTxMsg(["SCORE", {1: 1, 2: 2}],
                                {101, 102, 201, 202}),
                    ClientTxMsg(["GAME-OVER", [2]], {101, 102, 201, 202}),
                    InternalGiStatus([
                        {"hostParameters": {"numTeams": 2,
                                            "turnDurationSec": 30,
                                            "wordSets": ["test"],
                                            "numTurns": 1},
                         "gameState": "GAME_OVER",
                         "clientCount": {1: {'sb1': 1, 'sb2': 1}, 2: {'jg1': 1, 'jg2': 1}},
                         "winners": [2]
                        }
                    ], "taboo:1"),
                ], anyOrder=True)
                self.assertEqual(env.room.teams[1].members['sb1'].turnsPlayed, 1)

                # Test timer fire after the game is over
                env.room.turnMgr.timerExpiredCb({"turnId": 2})
                self.assertGiTxQueueMsgs(env.txq, [])
                self.assertEqual(env.room.teams[1].members['sb1'].turnsPlayed, 1)
Пример #30
0
    def testKickoff(self):
        env = self.setUpTabooRoom()
        self.drainGiTxQueue(env.txq)

        with stubs([(SupportedWordSets["test"], "nextWord", self.mockNextWord),
                    (Taboo.TurnManager, "expiryEpoch", stubExpiryEpochGen())]):
            env.room.processMsg(ClientRxMsg(["KICKOFF", 2], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(["KICKOFF-BAD", "Invalid message length"], {101}, 101),
            ])

            env.room.processMsg(ClientRxMsg(["KICKOFF"], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(["KICKOFF-BAD", "Game not running"], {101}, 101),
            ])

            env.room.state = TabooRoom.GameState.RUNNING
            self.setUpTeamPlayer(env, 1, "sb1", [101])
            self.setUpTeamPlayer(env, 1, "sb2", [102])
            self.setUpTeamPlayer(env, 2, "jg1", [201])
            self.setUpTeamPlayer(env, 2, "jg2", [202])
            self.drainGiTxQueue(env.txq)

            env.room.processMsg(ClientRxMsg(["KICKOFF"], 101))
            self.assertGiTxQueueMsgs(env.txq, [
                ClientTxMsg(["KICKOFF-BAD", "It is not your turn"], {101}, 101),
            ])

            def mockFindNextPlayer(remainingPlayers=[
                    env.room.playerByWs[201],
                    env.room.playerByWs[101],
                    env.room.playerByWs[202],
                ]):
                if remainingPlayers:
                    return remainingPlayers.pop(0)
                return None
            with stub(env.room.turnMgr, "_findNextPlayer", mockFindNextPlayer):
                env.room.turnMgr.startNewTurn()
                env.room.processMsg(ClientRxMsg(["KICKOFF"], 101))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["WAIT-FOR-KICKOFF", 1, "jg1"], {101, 102, 201, 202}, None),
                    ClientTxMsg(["KICKOFF-BAD", "It is not your turn"], {101}, 101),
                ])

                env.room.processMsg(ClientRxMsg(["KICKOFF"], 201))
                secretMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                            'utcTimeout': 30,
                                            'secret': 'c', 'disallowed': ['c1', 'c2']}]
                publicMsg = ['TURN', 1, 1, {'team': 2, 'player': 'jg1', 'state': 'IN_PLAY',
                                            'utcTimeout': 30}]
                self.assertGiTxQueueMsgs(env.txq, [
                    TimerRequest(30, env.room.turnMgr.timerExpiredCb, {
                                    "turnId": 1,
                                 }),
                    ClientTxMsg(secretMsg, {201}),
                    ClientTxMsg(secretMsg, {101, 102}),
                    ClientTxMsg(publicMsg, {101, 102, 201, 202}),
                ], anyOrder=True)

                env.room.processMsg(ClientRxMsg(["KICKOFF"], 201))
                self.assertGiTxQueueMsgs(env.txq, [
                    ClientTxMsg(["KICKOFF-BAD", "Can't kickoff a turn"], {201}, 201),
                ])