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)])
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)
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) ])
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), ])
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)
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) ])
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), ])
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), ])