def test09_next_owner_id_race_condition(self): owner = 11 player1 = 12 player2 = 13 # Create the game. response = yield self.service.handle([], {'action': ['create'], 'owner_id': [owner]}) game_id = response['game_id'] self.add_players_to_game(game_id, [owner, player1, player2]) # Complete the game. yield self.complete_game(game_id, owner, player1, player2) table = self.table_instance.game2table[game_id] self.test_done = False self.counter = 0 def listener(args): if not self.test_done: self.counter += 1 modified = args['modified'][0] table.poll({'modified': [modified]}).addCallback(listener) return args modified = table.get_modified() poll = table.poll({'modified': [modified]}).addCallback(listener) d1 = table.update_next_owner_id() d2 = table.update_next_owner_id() d3 = table.update_next_owner_id() d = defer.DeferredList([d1, d2, d3]) # Wait for all three update operations to finish... yield d # ...and then wait for the next_owner change to be dispatched by the poll. yield poll self.assertEquals(self.counter, 1) # Break the listen loop so that the test runner doesn't complain # about a dirty reactor. self.test_done = True table.touch({}) # For the same reason cancel the next_game_timer. table.stop_timer(table.next_game_timer)
def test06_next_game_timeout(self): owner = 98 player1 = 12 player2 = 78 # Create game response = yield self.service.handle([], {'action': ['create'], 'owner_id': [owner]}) game_id = response['game_id'] sql = "INSERT INTO tabs (player_id, game_id, created) VALUES (%d, %d, datetime('now'))" for player_id in [owner, player1, player2]: yield self.service.db.runQuery(sql % (player_id, game_id)) # Change the next game timeout from the default to 0.2 seconds for the test. table = self.table_instance.game2table[game_id] table.NEXT_GAME_TIMEOUT = 0.2 # Complete the game yield self.complete_game(game_id, owner, player1, player2) state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [player1]}) self.assertEqual(state, [{'game_id': game_id, 'next_game_id': None, 'next_owner_id': player1}, [player1]]) # Start a poll on this table to know when the next owner will change. poll = self.table_instance.poll({'game_id': [game_id], 'modified': [table.get_modified()]}) result = yield poll state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [player1]}) # Next owner took too long to create the game, # so player2 was chosen as the "new" next owner. self.assertEqual(state, [{'game_id': game_id, 'next_game_id': None, 'next_owner_id': player2}, [player2]]) # Cancel the timers, so that the test runner doesn't complain # about a "dirty" reactor. table.stop_timer(table.next_game_timer)
def test07_next_game_timeout_after_game_created(self): owner = 57 player1 = 123 player2 = 334 # Create first game response = yield self.service.handle([], {'action': ['create'], 'owner_id': [owner]}) game_id = response['game_id'] self.add_players_to_game(game_id, [owner, player1, player2]) # Change the next game timeout from the default to 0.2 seconds for the test. table = self.table_instance.game2table[game_id] table.NEXT_GAME_TIMEOUT = 0.2 # Complete the game yield self.complete_game(game_id, owner, player1, player2) state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [player1]}) self.assertEqual(state, [{'game_id': game_id, 'next_game_id': None, 'next_owner_id': player1}, [player1]]) # player1 is the next owner, let him create the next game. # We will let him wait long enough so that the timer kicks in and # gives another player a chance to be next owner. response = yield self.service.handle([], {'action': ['create'], 'owner_id': [player1], 'previous_game_id': [game_id]}) new_game_id = response['game_id'] self.add_players_to_game(new_game_id, [owner, player1, player2]) # Start a poll on this table to know when another player is chosen. poll = self.table_instance.poll({'game_id': [new_game_id], 'modified': [table.get_modified()]}) result = yield poll state = yield self.table_instance.state({'type': ['table'], 'game_id': [new_game_id], 'player_id': [owner]}) # Next owner took too long to create the game, # so player2 was chosen as the "new" next owner. # This can be seen when inquiring about table # from the new, pending game. self.assertEqual(state, [{'game_id': new_game_id, 'next_game_id': None, # player 2 didn't create the next game yet, so it is None 'next_owner_id': player2}, # player2 is now the next owner [player2]]) # The same result should be seen when inquiring about the table from the old (previous) game, state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [player2]}) self.assertEqual(state, [{'game_id': game_id, 'next_game_id': None, 'next_owner_id': player2}, [player2]]) # ---- # Since player1 already started creating the next game, he should never # again be chosen as the next owner for this round, we can see that by # checking that next_owner_id only alternates between player2 and the # original game's owner. # First change: yield self.table_instance.poll({'game_id': [new_game_id], 'modified': [table.get_modified()]}) state = yield self.table_instance.state({'type': ['table'], 'game_id': [new_game_id], 'player_id': [owner]}) self.assertEqual(state[0]['next_owner_id'], owner) # Second change: yield self.table_instance.poll({'game_id': [new_game_id], 'modified': [table.get_modified()]}) state = yield self.table_instance.state({'type': ['table'], 'game_id': [new_game_id], 'player_id': [owner]}) self.assertEqual(state[0]['next_owner_id'], player2) # Third change, we're back to the owner: yield self.table_instance.poll({'game_id': [new_game_id], 'modified': [table.get_modified()]}) state = yield self.table_instance.state({'type': ['table'], 'game_id': [new_game_id], 'player_id': [owner]}) self.assertEqual(state[0]['next_owner_id'], owner) # And fourth change - back to player2: yield self.table_instance.poll({'game_id': [new_game_id], 'modified': [table.get_modified()]}) state = yield self.table_instance.state({'type': ['table'], 'game_id': [new_game_id], 'player_id': [owner]}) self.assertEqual(state[0]['next_owner_id'], player2) # ---- # Player 2 creates a new game response = yield self.service.handle([], {'action': ['create'], 'owner_id': [player2], 'previous_game_id': [new_game_id]}) newest_game_id = response['game_id'] # Check the state now. # At this point, player1's and player2's games are both pending. # Depending on from which game you inquire about it, you should see # different results. # Looking from the first (and still current) game, the user should be # pointed to the newest pending game: state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [owner]}) self.assertEqual(state, [{'game_id': game_id, 'next_game_id': newest_game_id, 'next_owner_id': player2}, [player2]]) # Looking from player1's pending game, the table should report the # new owner (player2), but not the new game yet, because it's still pending: state = yield self.table_instance.state({'type': ['table'], 'game_id': [new_game_id], 'player_id': [owner]}) self.assertEqual(state, [{'game_id': new_game_id, 'next_game_id': None, 'next_owner_id': player2}, [player2]]) # Looking from player2's pending game, we should see the same results: state = yield self.table_instance.state({'type': ['table'], 'game_id': [newest_game_id], 'player_id': [owner]}) self.assertEqual(state, [{'game_id': newest_game_id, 'next_game_id': None, 'next_owner_id': player2}, [player2]]) # Let player1 finish creating the game now by setting the card and sentence. # player1's game should be promoted as the next game of the table and every # of the above requests should now point to it. # Set card yield self.service.handle([], {'action': ['set_card'], 'card': [1], 'game_id': [new_game_id], 'player_id': [player1]}) # Set sentence yield self.service.handle([], {'action': ['set_sentence'], 'sentence': ['SENTENCE'], 'game_id': [new_game_id], 'player_id': [player1]}) # Looking from previous game: state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [owner]}) self.assertEqual(state, [{'game_id': game_id, 'next_game_id': new_game_id, 'next_owner_id': player1}, [player1]]) # Looking from player1's game, which was promoted: state = yield self.table_instance.state({'type': ['table'], 'game_id': [new_game_id], 'player_id': [owner]}) self.assertEqual(state, [{'game_id': new_game_id, 'next_game_id': None, 'next_owner_id': None}, []]) # The game should still be part of the same old table. table2 = self.table_instance.game2table[new_game_id] self.assertEqual(table2, table) # Looking from player2's game, which is still in the pending state, # the player should be pointed to the promoted game. state = yield self.table_instance.state({'type': ['table'], 'game_id': [newest_game_id], 'player_id': [owner]}) self.assertEqual(state, [{'game_id': newest_game_id, 'next_game_id': new_game_id, 'next_owner_id': player1}, [player1]]) # Now let's move player2's game into 'invitation' state - this should # trigger it to be detached from the current table, and put into # its own, brand new table. # Set card yield self.service.handle([], {'action': ['set_card'], 'card': [10], 'game_id': [newest_game_id], 'player_id': [player2]}) # Set sentence yield self.service.handle([], {'action': ['set_sentence'], 'sentence': ['The Real Sentence'], 'game_id': [newest_game_id], 'player_id': [player2]}) table3 = self.table_instance.game2table[newest_game_id] self.assertNotEqual(table3, table)