コード例 #1
0
ファイル: LobbyPluginTest.py プロジェクト: sbirmi/bari
    def testHandleHost(self):
        """Handling of HOST message"""
        fakeWs = 1
        msg = ClientRxMsg(["HOST", "foo"], initiatorWs=fakeWs)
        self.plugin.processMsg(msg)

        self.assertGiTxQueueMsgs(self.txq, [InternalHost([], "foo", initiatorWs=fakeWs)])

        msg = ClientRxMsg(["HOST", "bar", {1: 2, 3: 4}], initiatorWs=fakeWs)
        self.plugin.processMsg(msg)

        self.assertGiTxQueueMsgs(self.txq, [InternalHost([{1: 2, 3: 4}], "bar",
                                                         initiatorWs=fakeWs)])
コード例 #2
0
ファイル: server.py プロジェクト: lambdaFooBar/bari
async def rxClient(clientWs, path):
    """
    Method to handle each client websocket connecting to
    the server.
    """
    path = path.strip("/")
    wsSetBariName(clientWs)

    # GxRxQueue + task must exist if the path is valid in this check
    if giByPath(path) is None:
        await clientWs.send(json.dumps([MTYPE_ERROR, "Bad path"]))
        return

    # Register ws <--> path
    wsPathAdd(clientWs, path)

    # Queue+task for messages to ws
    clientTxQueueAdd(clientWs)

    # Queue+task
    giRxMsg(path, InternalConnectWsToGi(clientWs))

    try:
        async for message in clientWs:
            try:
                jmsg = json.loads(message)
            except json.decoder.JSONDecodeError:
                await clientTxMsg([MTYPE_ERROR, "Bad JSON message"], clientWs)
                continue

            if not isinstance(jmsg, list):
                await clientTxMsg([MTYPE_ERROR, "Bad message: not a list"],
                                  clientWs)
                continue

            if not jmsg:
                await clientTxMsg([MTYPE_ERROR, "Bad message: empty list"],
                                  clientWs)
                continue

            giRxMsg(path, ClientRxMsg(jmsg, initiatorWs=clientWs))

    except websockets.exceptions.ConnectionClosedError:
        pass

    giRxMsg(path, InternalDisconnectWsToGi(clientWs))

    wsPathRemove(clientWs, path)

    clientTxQueueRemove(clientWs)
コード例 #3
0
ファイル: ChatRoomTest.py プロジェクト: sbirmi/bari
    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)
        ])
コード例 #4
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),
                ])
コード例 #5
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)
コード例 #6
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)
            ])
コード例 #7
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),
                ])
コード例 #8
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),
        ])