def test01_load(self): database = 'test.sqlite' if os.path.exists(database): os.unlink(database) service = CardstoriesService({'db': database}) self.assertFalse(os.path.exists(database)) service.startService() self.assertTrue(os.path.exists(database)) yield service.stopService() game_id = 100 player_id = 20 db = sqlite3.connect(database) c = db.cursor() c.execute("INSERT INTO games (id) VALUES (%d)" % game_id) c.execute("INSERT INTO player2game (game_id, player_id) VALUES (%d, %d)" % (game_id, player_id)) db.commit() db.close() service = CardstoriesService({'db': database}) service.startService() self.assertEquals(game_id, service.games[game_id].id) self.assertEquals([player_id], service.games[game_id].get_players()) self.assertEquals(len(service.games[game_id].pollers), 1) yield service.stopService()
class CardstoriesServiceTestBase(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database}) self.service.startService() self.db = sqlite3.connect(self.database) def tearDown(self): self.db.close() os.unlink(self.database) return self.service.stopService()
def test01_load_notify(self): card = 5 str_sentence = 'SENTENCE' owner_id = 15 self.loaded = False result = yield self.service.create({'owner_id': [owner_id]}) service2 = CardstoriesService({'db': self.database}) def accept(event): self.assertEquals(event['details']['type'], 'load') self.loaded = True service2.listen().addCallback(accept) service2.startService() service2.stopService() self.assertTrue(self.loaded, 'load event called')
def test00_startService(self): database = 'test.sqlite' service = CardstoriesService({'db': database}) self.assertFalse(os.path.exists(database)) def start(event): self.assertEqual(event['type'], 'start') service.notified_start = True return event service.listen().addCallback(start) service.startService() self.assertTrue(service.notified_start) self.assertTrue(os.path.exists(database)) def stop(event): self.assertEqual(event['type'], 'stop') service.notified_stop = True return event service.listen().addCallback(stop) d = service.stopService() self.assertTrue(service.notified_stop) return d
class MailTestAllow(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database, 'plugins-libdir': '../fixture2', 'plugins-confdir': '../fixture2', 'plugins-dir': '../fixture2'}) self.service.startService() def tearDown(self): return self.service.stopService() def test00_init(self): plugin = mail.Plugin(self.service, [ ]) for allowed in mail.Plugin.ALLOWED: has_key = plugin.templates.has_key(allowed) if allowed in ('invite', 'vote'): self.assertTrue(has_key) else: self.assertFalse(has_key)
class MailTestAllow(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({ 'db': self.database, 'plugins-libdir': '../fixture2', 'plugins-confdir': '../fixture2', 'plugins-dir': '../fixture2' }) self.service.startService() def tearDown(self): return self.service.stopService() def test00_init(self): plugin = mail.Plugin(self.service, []) for allowed in mail.Plugin.ALLOWED: has_key = plugin.templates.has_key(allowed) if allowed in ('invite', 'vote'): self.assertTrue(has_key) else: self.assertFalse(has_key)
class ChatTest(unittest.TestCase): # initialise our test with a service that we can use during testing and a testing database def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) # Empty 'chat/' subdir self.test_logdir = 'test_logdir.tmp' if os.path.exists(self.test_logdir): shutil.rmtree(self.test_logdir) self.service = CardstoriesService({ 'db': self.database, 'plugins-confdir': 'CONFDIR', 'plugins-libdir': 'LIBDIR', 'plugins-logdir': self.test_logdir, 'static': 'STATIC' }) self.service.startService() def tearDown(self): # kill the service we started before the test return self.service.stopService() @defer.inlineCallbacks def complete_game(self): self.winner_card = winner_card = 5 sentence = 'SENTENCE' owner_id = 15 result = yield self.service.create({ 'card': [winner_card], 'sentence': [sentence], 'owner_id': [owner_id] }) game_id = result['game_id'] yield self.service.set_card({ 'action': ['set_card'], 'card': [winner_card], 'player_id': [owner_id], 'game_id': [game_id] }) yield self.service.set_sentence({ 'action': ['set_sentence'], 'sentence': [sentence], 'player_id': [owner_id], 'game_id': [game_id] }) self.player1 = 16 for player_id in (self.player1, 17): yield self.service.participate({ 'action': ['participate'], 'player_id': [player_id], 'game_id': [game_id] }) player = yield self.service.player2game({ 'action': ['player2game'], 'player_id': [player_id], 'game_id': [game_id] }) card = player['cards'][0] yield self.service.pick({ 'action': ['pick'], 'player_id': [player_id], 'game_id': [game_id], 'card': [card] }) yield self.service.voting({ 'action': ['voting'], 'game_id': [game_id], 'owner_id': [owner_id] }) winner_id = self.player1 yield self.service.vote({ 'action': ['vote'], 'game_id': [game_id], 'player_id': [winner_id], 'card': [winner_card] }) loser_id = 17 yield self.service.vote({ 'action': ['vote'], 'game_id': [game_id], 'player_id': [loser_id], 'card': [120] }) self.assertTrue(self.service.games.has_key(game_id)) yield self.service.complete({ 'action': ['complete'], 'game_id': [game_id], 'owner_id': [owner_id] }) self.assertFalse(self.service.games.has_key(game_id)) defer.returnValue(True) def test00_create_logdir(self): chat_instance = Plugin(self.service, []) logdir = os.path.join(self.test_logdir, 'chat') self.assertTrue(os.path.exists(logdir)) @defer.inlineCallbacks def test00_preprocess_noop(self): # create a new instance of the plugin and make sure it's the right type chat_instance = Plugin(self.service, []) self.assertEquals(chat_instance.name(), 'chat') # run a game to get into a realistic situation yield self.complete_game() # run the preprocess method and make sure it does not affect anything during a normal 'game' event result_in = 'RESULT' result_out = yield chat_instance.preprocess(result_in, Request(action=['game'])) self.assertEquals(result_in, result_out) @defer.inlineCallbacks def test01_add_message(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 sentence = "This is my sentence!" now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) # verify we have no messages yet self.assertEquals(len(chat_instance.messages), 0) # run the request result = yield chat_instance.preprocess(True, request) # verify we now have one message self.assertEquals(len(chat_instance.messages), 1) # verify the event has been removed from the pipeline self.assertFalse(request.args.has_key('action')) # verify the message we added is in the list self.assertEquals(chat_instance.messages[0]["player_id"], player_id) self.assertEquals(chat_instance.messages[0]["sentence"], sentence) # check that the message has been recorded in log file with open( os.path.join(self.test_logdir, 'chat', '%s.log' % strftime('%Y-%m-%d'))) as f: lines = f.readlines() self.assertEquals(len(lines), 1) self.assertIn(sentence, lines[0]) self.assertIn('player_%d' % player_id, lines[0]) @defer.inlineCallbacks def test02_check_added_message_after_now(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 sentence = "This is my sentence!" now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later state, players_id_list = yield chat_instance.state( {"modified": [now + 1]}) self.assertTrue(state.has_key('messages')) self.assertEquals(len(state['messages']), 0) self.assertEquals(players_id_list, []) @defer.inlineCallbacks def test03_check_added_message_before_now(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 sentence = "This is my sentence!" now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later state, players_id_list = yield chat_instance.state( {"modified": [now - 1]}) self.assertEquals(len(state['messages']), 1) self.assertEquals(state['messages'][0]['player_id'], player_id) self.assertEquals(state['messages'][0]['sentence'], sentence) self.assertEquals(players_id_list, [player_id]) @defer.inlineCallbacks def test04_check_multiple_messages(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_ids = [200, 220, 999] sentences = [ "This is my sentence!", "Yeah another test hello.", "Ping ping poing pong." ] when = [] for i in range(3): when.append(int(runtime.seconds() * 1000)) request = Request(action=['message'], player_id=[player_ids[i]], sentence=[sentences[i]]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later # we check right back to one second ago to make sure all recently added messages are caught state, players_id_list = yield chat_instance.state( {"modified": [when[-1] - 1000]}) self.assertEquals(len(state['messages']), 3) for i in range(3): self.assertEquals(state['messages'][i]['player_id'], player_ids[i]) self.assertEquals(state['messages'][i]['sentence'], sentences[i]) self.assertEquals(players_id_list, player_ids) @defer.inlineCallbacks def test05_check_half_of_multiple_messages(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_ids = [200, 220, 999] sentences = [ "This is my sentence!", "Yeah another test hello.", "Ping ping poing pong." ] when = [] for i in range(3): sleep(0.1) when.append(int(runtime.seconds() * 1000)) request = Request(action=['message'], player_id=[player_ids[i]], sentence=[sentences[i]]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later # we check right back to one second ago to make sure all recently added messages are caught state, players_id_list = yield chat_instance.state( {"modified": [when[-1] - 150]}) # this time because of the 100ms delay between messages, and only checking to 150ms ago # we should only get the last two messages self.assertEquals(len(state['messages']), 2) for i in range(2): self.assertEquals(state['messages'][i]['player_id'], player_ids[i + 1]) self.assertEquals(state['messages'][i]['sentence'], sentences[i + 1]) self.assertEquals(players_id_list, player_ids[-2:]) @defer.inlineCallbacks def test06_touch_state(self): player_id = 200 sentence = "This is my sentence!" # new instance of chat plugin to run the test against chat_instance = Plugin(self.service, []) # put the chat instance into the service's pollable_plugins self.service.pollable_plugins.append(chat_instance) # flag to signify whether the callback has run self.called = False # service to poll instance waiting for chat d = self.service.poll({ 'action': ['poll'], 'player_id': [player_id], 'type': ['chat'], 'modified': [chat_instance.get_modified()] }) # callback which runs once the chat plugin calls touch() def check(event): self.called = True d.addCallback(check) # make sure our flag is false before we run self.assertFalse(self.called) # run the test request request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) result = yield chat_instance.preprocess(True, request) yield d # make sure the flag is now set after we've run the test self.assertTrue(self.called) @defer.inlineCallbacks def test07_notification_messages(self): # new instance of chat plugin to run the test against chat_instance = Plugin(self.service, []) self.count = 0 def build_message(self, message): """ message == {'type': 'notification', 'game_id': GAME_ID, 'player_id': 'OWNER_ID', 'sentence': 'SENTENCE'} """ self.count += 1 self.assertEquals(self.count, 1) self.assertEquals(message['type'], 'notification') self.assertEquals(message['player_id'], '15') self.assertEquals(message['sentence'], 'SENTENCE') # build_message should only be called once, upon game creation. chat_instance.build_message = build_message # run a game to get into a realistic situation yield self.complete_game() @defer.inlineCallbacks def test08_nonascii_characters_message(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 # The sentence is a 'str' object. Create it by encoding a unicode string. unicode_sentence = u"你好 Matjaž Gregorič" sentence_bytes = unicode_sentence.encode('utf-8') request = Request(action=['message'], player_id=[player_id], sentence=[sentence_bytes]) # run the request result = yield chat_instance.preprocess(True, request) # check that the message has been recorded in log file with open( os.path.join(self.test_logdir, 'chat', '%s.log' % strftime('%Y-%m-%d'))) as f: lines = f.readlines() self.assertIn(unicode_sentence, lines[0].decode('utf-8')) @defer.inlineCallbacks def test09_nonascii_characters_notification(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request class FakeGame: id = 102 owner_id = 303 unicode_sentence = u"我不明白 šal čez želodec" changes = { 'type': 'change', 'details': { 'type': 'load', 'sentence': unicode_sentence }, 'game': FakeGame() } result = yield chat_instance.self_notify(changes) with open( os.path.join(self.test_logdir, 'chat', '%s.log' % strftime('%Y-%m-%d'))) as f: lines = f.readlines() self.assertIn(unicode_sentence, lines[0].decode('utf-8')) @defer.inlineCallbacks def test10_escape_html(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 201 naughty_sentence = '<script>alert("haha!")</script>' now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[naughty_sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure our naughty message is returned properly escaped state, players_id_list = yield chat_instance.state( {"modified": [now - 1]}) self.assertEquals(state['messages'][0]['player_id'], player_id) self.assertEquals(state['messages'][0]['sentence'], '<script>alert("haha!")</script>') @defer.inlineCallbacks def test11_link_url(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 201 url_sentence = 'For searching the web I use google.com, it\'s great!' now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[url_sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure our message is returned with a link for the url state, players_id_list = yield chat_instance.state( {"modified": [now - 1]}) self.assertEquals(state['messages'][0]['player_id'], player_id) self.assertEquals( state['messages'][0]['sentence'], 'For searching the web I use <a target="_blank" href="http://google.com">google.com</a>, it\'s great!' )
class TableTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database, 'plugins-confdir': 'CONFDIR', 'plugins-libdir': 'LIBDIR', 'static': 'STATIC'}) self.service.auth = Mock() self.service.startService() # Fake an activity plugin to which the table plugin should listen self.mock_activity_instance = Mock() self.mock_activity_instance.name.return_value = 'activity' # Show all players as online self.mock_activity_instance.is_player_online.return_value = True self.table_instance = table.Plugin(self.service, [self.mock_activity_instance]) self.mock_activity_instance.listen.assert_called_once_with() self.mock_activity_instance.reset_mock() def tearDown(self): # kill the service we started before the test return self.service.stopService() @defer.inlineCallbacks def add_players_to_game(self, game_id, player_ids): sql = "INSERT INTO tabs (player_id, game_id, created) VALUES (%d, %d, datetime('now'))" for player_id in player_ids: yield self.service.db.runQuery(sql % (player_id, game_id)) @defer.inlineCallbacks def complete_game(self, game_id, owner, player1, player2): # Set card yield self.service.handle([], {'action': ['set_card'], 'card': [1], 'game_id': [game_id], 'player_id': [owner]}) # Set sentence yield self.service.handle([], {'action': ['set_sentence'], 'sentence': ['SENTENCE'], 'game_id': [game_id], 'player_id': [owner]}) # Join yield self.service.handle([], {'action': ['participate'], 'game_id': [game_id], 'player_id': [player1]}) yield self.service.handle([], {'action': ['participate'], 'game_id': [game_id], 'player_id': [player2]}) # Pick game, players_ids = yield self.table_instance.get_game_by_id(game_id, player1) yield self.service.handle([], {'action': ['pick'], 'game_id': [game_id], 'player_id': [player1], 'card': [game['self'][2][0]]}) game, players_ids = yield self.table_instance.get_game_by_id(game_id, player2) yield self.service.handle([], {'action': ['pick'], 'game_id': [game_id], 'player_id': [player2], 'card': [game['self'][2][0]]}) # Vote yield self.service.handle([], {'action': ['voting'], 'game_id': [game_id], 'owner_id': [game['owner_id']]}) @defer.inlineCallbacks def player_vote(player_id): game, players_ids = yield self.table_instance.get_game_by_id(game_id, player_id) my_card = game['self'][0] board = [x for x in game['board'] if x != my_card] yield self.service.handle([], {'action': ['vote'], 'game_id': [game_id], 'player_id': [player_id], 'card': [board[0]]}) yield player_vote(player1) yield player_vote(player2) # Complete yield self.service.handle([], {'action': ['complete'], 'game_id': [game_id], 'owner_id': [game['owner_id']]}) @defer.inlineCallbacks def test01_no_table(self): player_id = 12 game_id = 59 # Request for tables should direct the player to create his own game state = yield self.table_instance.state({'type': ['table'], 'game_id': ['undefined'], 'player_id': [player_id]}) self.assertEqual(state, [{'game_id': None, 'next_game_id': None, 'next_owner_id': player_id}, [player_id]]) # Next games of existing games should also ask to create a new game, since we have no table info state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [player_id]}) self.assertEqual(state, [{'game_id': game_id, 'next_game_id': None, 'next_owner_id': player_id}, [player_id]]) @defer.inlineCallbacks def test02_create_game_next(self): player1 = 12 player2 = 78 player3 = 98 # Poll to know when a table gets available poll = self.table_instance.poll({'game_id': ['undefined'], 'modified': [0]}) result = yield poll modified = result['modified'][0] # Start a new poll immediately. poll = self.table_instance.poll({'game_id': ['undefined'], 'modified': [modified]}) # Make sure it doesn't return at once. self.assertFalse(poll.called) self.assertEqual(modified, self.table_instance.get_modified({'game_id': ['undefined']})) # Create first game response = yield self.service.handle([], {'action': ['create'], 'owner_id': [player1]}) game_id = response['game_id'] # Poll must return to inform players waiting for an available table result = yield poll modified = result['modified'][0] # Associate all players with the game in the tabs db table. sql = "INSERT INTO tabs (player_id, game_id, created) VALUES (%d, %d, datetime('now'))" for player_id in [player1, player2, player3]: yield self.service.db.runQuery(sql % (player_id, game_id)) state = yield self.table_instance.state({'type': ['table'], 'game_id': ['undefined'], 'player_id': [player2]}) self.assertEqual(state, [{'game_id': None, 'next_game_id': game_id, 'next_owner_id': player1}, [player1]]) # Initial state of the table itself 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': None}, []]) # Start a poll on this table to know when the next game will be available there poll = self.table_instance.poll({'game_id': [game_id], 'modified': [0]}) result = yield poll modified = result['modified'][0] poll = self.table_instance.poll({'game_id': [game_id], 'modified': [modified]}) self.assertFalse(poll.called) self.assertEqual(modified, self.table_instance.get_modified({'game_id': [game_id]})) # Complete first game yield self.complete_game(game_id, player1, player2, player3) 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': player2}, [player2]]) # Poll must return to announce the next owner result = yield poll modified = result['modified'][0] poll = self.table_instance.poll({'game_id': [game_id], 'modified': [modified]}) self.assertFalse(poll.called) # Next owner disconnects before creating the game - should chose another player def is_player_online(*args, **kw): if args[0] == player2: return False return True self.mock_activity_instance.is_player_online.side_effect = is_player_online yield self.table_instance.on_activity_notification({'type': 'player_disconnecting', 'player_id': 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': player3}, [player3]]) # Poll must return to announce the next owner result = yield poll modified = result['modified'][0] # All players quit - deletes the table # Clear the side_effect which otherwise takes precedence over return_value. self.mock_activity_instance.is_player_online.side_effect = None self.mock_activity_instance.is_player_online.return_value = False yield self.table_instance.on_activity_notification({'type': 'player_disconnecting', 'player_id': player1}) yield self.table_instance.on_activity_notification({'type': 'player_disconnecting', 'player_id': player3}) 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]]) @defer.inlineCallbacks def test04_postprocess(self): game_id = 55 tab1_game_id = 17 tab2_game_id = 18 player_id = 77 mock_request = Mock() mock_request.args = {'action': ['state'], 'player_id': [player_id], 'game_id': [game_id], 'type': ['tabs']} response = [{'type': 'tabs', 'games': [{'id': tab1_game_id, 'state': 'complete'}, {'id': tab2_game_id, 'state': 'complete'}]}] def mock_state(args): game_id = args['game_id'][0] if game_id == tab1_game_id: next_game_id = 42 next_owner_id = player_id elif game_id == tab2_game_id: next_game_id = None next_owner_id = 21 result = [{'game_id': game_id, 'next_game_id': next_game_id, 'next_owner_id': next_owner_id}, [player_id]] return result self.table_instance.state = mock_state result = yield self.table_instance.postprocess(response, mock_request) # During postprocessing, next_owner_id and next_game_id should be added to # the response. self.assertEqual(result[0]['games'][0]['next_owner_id'], player_id) self.assertEqual(result[0]['games'][0]['next_game_id'], 42) self.assertEqual(result[0]['games'][1]['next_owner_id'], 21) self.assertEqual(result[0]['games'][1]['next_game_id'], None) # Make sure things don't fail if response is not of the expected shape. yield self.table_instance.postprocess({'type': 'chat'}, mock_request) yield self.table_instance.postprocess([[1, 2, {'this': 'test'}]], mock_request) @defer.inlineCallbacks 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) @defer.inlineCallbacks 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) @defer.inlineCallbacks 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)
class ActivityTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database, 'plugins-confdir': 'CONFDIR', 'plugins-libdir': 'LIBDIR', 'static': 'STATIC' }) self.service.startService() # Don't actually make delayed calls, but allow tests to call them self.default_reactor = activity.reactor.callLater self.activity_reactor = FakeReactor() activity.reactor = self.activity_reactor self.activity_instance = activity.Plugin(self.service, []) def tearDown(self): activity.reactor = self.default_reactor # kill the service we started before the test return self.service.stopService() @defer.inlineCallbacks def check_online_players(self, online_players): """ Check that the players currently online are the ones (and only the ones) in the list online_players_ids """ state = yield self.activity_instance.state([]) self.assertEqual(state[0]['online_players'], online_players) for player_id in online_players.keys(): is_online = self.activity_instance.is_player_online(player_id) self.assertTrue(is_online, "Player id %d is not online" % player_id) @defer.inlineCallbacks def test01_online_offline(self): player_id = 12 # No player initially yield self.check_online_players({}) # Player going online on_event_mock = Mock() self.activity_instance.listen().addCallback(on_event_mock) self.activity_instance.on_service_notification({'type': 'poll_start', 'player_id': player_id}) on_event_mock.assert_called_once_with({'type': 'player_connecting', 'player_id': player_id}) on_event_mock.reset_mock() self.activity_instance.listen().addCallback(on_event_mock) yield self.check_online_players({player_id: {'active_polls': 1} }) # Player dropping poll self.activity_instance.on_service_notification({'type': 'poll_end', 'player_id': player_id}) self.assertEqual(on_event_mock.call_count, 0) yield self.check_online_players({player_id: {'active_polls': 0} }) # Player starting another poll quickly enough self.activity_instance.on_service_notification({'type': 'poll_start', 'player_id': player_id}) self.assertEqual(on_event_mock.call_count, 0) yield self.check_online_players({player_id: {'active_polls': 1} }) # Player dropping poll again, this time for good (going offline) self.activity_instance.on_service_notification({'type': 'poll_end', 'player_id': player_id}) self.assertEqual(on_event_mock.call_count, 0) self.activity_reactor.call_now() # Second call should not have any effect (several delayed call can happen concurrently) self.activity_reactor.call_now() on_event_mock.assert_called_once_with({'type': 'player_disconnecting', 'player_id': player_id}) yield self.check_online_players({})
class CardstoriesEventLogTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database}) self.service.startService() self.db = sqlite3.connect(self.database) self.game = CardstoriesGame(self.service) def tearDown(self): self.game.destroy() self.db.close() os.unlink(self.database) return self.service.stopService() # Since the logging is all async, the tests would be a nightmare without # enforcing events to be logged serially as they happen. # In order to do this, we wait by poking at the DB in a loop until the # expected number of records exists in the DB. def wait_for_logs(self, game_id, expected_nr): c = self.db.cursor() while True: time.sleep(0.005) c.execute('SELECT COUNT(*) FROM event_logs WHERE game_id = ?', [game_id]) if c.fetchone()[0] == expected_nr: break @defer.inlineCallbacks def test01_log_game_events(self): owner_id = 42 player1_id = 84 player2_id = 86 sentence = 'The Sentence.' # 1 - Should log creation. game_id = yield self.game.create(owner_id) self.wait_for_logs(game_id, 1) # 2 - Should log card set. owner = yield self.game.player2game(owner_id) winner_card = owner['cards'][0] yield self.game.set_card(owner_id, winner_card) self.wait_for_logs(game_id, 2) # 3 -Should log sentence set. yield self.game.set_sentence(owner_id, sentence) self.wait_for_logs(game_id, 3) # 4 - Should log invitation (player1 only). yield self.game.invite([player1_id]) self.wait_for_logs(game_id, 4) # 5 & 6 - Should log joining (both players). yield self.game.participate(player1_id) self.wait_for_logs(game_id, 5) yield self.game.participate(player2_id) self.wait_for_logs(game_id, 6) # 7 & 8 - Should log players picking cards. player1 = yield self.game.player2game(player1_id) picked_card1 = player1['cards'][0] yield self.game.pick(player1_id, picked_card1) self.wait_for_logs(game_id, 7) player2 = yield self.game.player2game(player2_id) picked_card2 = player1['cards'][0] yield self.game.pick(player2_id, picked_card2) self.wait_for_logs(game_id, 8) # 9 - Should log game moved into voting. yield self.game.voting(owner_id) self.wait_for_logs(game_id, 9) # 10 & 11 - Should log players voting for cards. yield self.game.vote(player1_id, winner_card) self.wait_for_logs(game_id, 10) yield self.game.vote(player2_id, picked_card1) self.wait_for_logs(game_id, 11) # 12 - Should log game completed. yield self.game.complete(owner_id) self.wait_for_logs(game_id, 12) # Now lets check the logs table. c = self.db.cursor() # Wait until the logs are written (they're written asynchronously) c.execute('SELECT event_type, player_id, data FROM event_logs WHERE game_id = ? ORDER BY timestamp', [game_id]) # Twelve events should be logged. rows = c.fetchall() self.assertEqual((event_log.GAME_CREATED, owner_id, None), rows[0]) self.assertEqual((event_log.OWNER_CHOSE_CARD, owner_id, str(winner_card)), rows[1]) self.assertEqual((event_log.OWNER_WROTE_STORY, owner_id, sentence), rows[2]) self.assertEqual((event_log.PLAYER_INVITED, owner_id, str(player1_id)), rows[3]) self.assertEqual((event_log.PLAYER_JOINED, player1_id, None), rows[4]) self.assertEqual((event_log.PLAYER_JOINED, player2_id, None), rows[5]) self.assertEqual((event_log.PLAYER_PICKED_CARD, player1_id, str(picked_card1)), rows[6]) self.assertEqual((event_log.PLAYER_PICKED_CARD, player2_id, str(picked_card2)), rows[7]) self.assertEqual((event_log.GAME_MOVED_TO_VOTING, owner_id, None), rows[8]) self.assertEqual((event_log.PLAYER_VOTED, player1_id, str(winner_card)), rows[9]) self.assertEqual((event_log.PLAYER_VOTED, player2_id, str(picked_card1)), rows[10]) self.assertEqual((event_log.GAME_COMPLETED, owner_id, None), rows[11]) c.close() @defer.inlineCallbacks def test02_log_canceled_game_events(self): owner_id = 4 player_id = 8 sentence = 'Some Sentence.' # 1 - Should log creation. game_id = yield self.game.create(owner_id) self.wait_for_logs( game_id, 1) # 2 - Should log card set. owner = yield self.game.player2game(owner_id) winner_card = owner['cards'][0] yield self.game.set_card(owner_id, winner_card) self.wait_for_logs( game_id, 2) # 3 -Should log sentence set. yield self.game.set_sentence(owner_id, sentence) self.wait_for_logs( game_id, 3) # 4 - Should log joining. yield self.game.participate(player_id) self.wait_for_logs( game_id, 4) # 5 - Should log player leaving. yield self.game.leave([player_id]) self.wait_for_logs( game_id, 5) # 6 - Should log game cancelation. yield self.game.cancel() self.wait_for_logs(game_id, 6) # Now lets check the logs table. c = self.db.cursor() c.execute('SELECT event_type, player_id, data FROM event_logs WHERE game_id = ? ORDER BY timestamp', [game_id]) # Twelve events should be logged. rows = c.fetchall() self.assertEqual((event_log.GAME_CREATED, owner_id, None), rows[0]) self.assertEqual((event_log.OWNER_CHOSE_CARD, owner_id, str(winner_card)), rows[1]) self.assertEqual((event_log.OWNER_WROTE_STORY, owner_id, sentence), rows[2]) self.assertEqual((event_log.PLAYER_JOINED, player_id, None), rows[3]) self.assertEqual((event_log.PLAYER_LEFT, player_id, None), rows[4]) self.assertEqual((event_log.GAME_CANCELED, owner_id, None), rows[5]) c.close() def test03_log_query_functions(self): c = self.db.cursor() game1 = 99 game2 = 199 player1 = 11 player2 = 12 invitee = 878 # Define some datetimes. now = datetime.now() an_hour_ago = now - timedelta(hours=1) six_hours_ago = now - timedelta(hours=6) yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) # Fill in some log data. data = [ # Game 1 [game1, two_days_ago, event_log.GAME_CREATED, player1, ''], [game1, two_days_ago, event_log.OWNER_CHOSE_CARD, player1, 22], [game1, two_days_ago, event_log.OWNER_WROTE_STORY, player1, 'This story'], [game1, six_hours_ago, event_log.PLAYER_JOINED, player2, 33], [game1, now, event_log.PLAYER_VOTED, player2, 33], # Game 2 [game2, yesterday, event_log.GAME_CREATED, player1, ''], [game2, yesterday, event_log.OWNER_CHOSE_CARD, player1, 34], [game2, six_hours_ago, event_log.OWNER_WROTE_STORY, player1, 'The Story'], [game2, an_hour_ago, event_log.PLAYER_INVITED, player1, invitee], [game2, an_hour_ago, event_log.PLAYER_JOINED, invitee, ''], [game2, now, event_log.PLAYER_PICKED_CARD, invitee, 23] ] for d in data: c.execute('INSERT INTO event_logs (game_id, timestamp, event_type, player_id, data) VALUES (?, ?, ?, ?, ?)', d) # Player's last activity. result = event_log.get_players_last_activity(c, player1) self.assertEquals(result['timestamp'], str(an_hour_ago)) self.assertEquals(result['game_id'], game2) self.assertEquals(result['event_type'], event_log.PLAYER_INVITED) self.assertEquals(result['data'], invitee) result = event_log.get_players_last_activity(c, player2) self.assertEquals(result['timestamp'], str(now)) self.assertEquals(result['game_id'], game1) self.assertEquals(result['event_type'], event_log.PLAYER_VOTED) self.assertEquals(result['data'], 33) result = event_log.get_players_last_activity(c, invitee) self.assertEquals(result['timestamp'], str(now)) self.assertEquals(result['game_id'], game2) self.assertEquals(result['event_type'], event_log.PLAYER_PICKED_CARD) self.assertEquals(result['data'], 23) # Game activities. result = event_log.get_game_activities(c, game1, since=yesterday) self.assertEquals(len(result), 2) self.assertEquals(result[0]['event_type'], event_log.PLAYER_JOINED) self.assertEquals(result[0]['timestamp'], str(six_hours_ago)) self.assertEquals(result[1]['event_type'], event_log.PLAYER_VOTED) self.assertEquals(result[1]['player_id'], player2) result = event_log.get_game_activities(c, game1, since=an_hour_ago) self.assertEquals(len(result), 1) self.assertEquals(result[0]['event_type'], event_log.PLAYER_VOTED) self.assertEquals(result[0]['player_id'], player2) result = event_log.get_game_activities(c, game2, since=two_days_ago) self.assertEquals(len(result), 6) self.assertEquals(result[5]['event_type'], event_log.PLAYER_PICKED_CARD) self.assertEquals(result[5]['timestamp'], str(now)) self.assertEquals(result[5]['player_id'], invitee)
class AggregateTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database}) self.service.startService() self.db = sqlite3.connect(self.database) def tearDown(self): self.db.close() os.unlink(self.database) return self.service.stopService() def test01_get_player_game_ids(self): c = self.db.cursor() player_id = 1231 game_ids = [34, 64, 322, 340] # fill in some game_ids for player. for game_id in game_ids: c.execute( 'insert into player2game (player_id, game_id) values (?, ?)', [player_id, game_id]) # fill in some bogus ones. c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id + 3, game_ids[0]]) c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id + 2, game_ids[0]]) c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id + 2, game_ids[0] + 12]) result = aggregate.get_player_game_ids(c, player_id) self.assertEquals(sorted(result), sorted(game_ids)) def test02_get_game_activities(self): c = self.db.cursor() game1 = 99 game2 = 199 sentence1 = 'This Story' sentence2 = 'That Story' player1 = 11 player2 = 12 invitee = 878 # Define some datetimes. now = datetime.now() an_hour_ago = now - timedelta(hours=1) six_hours_ago = now - timedelta(hours=6) yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) # Create two games. sql = 'INSERT INTO games (id, owner_id, state, sentence, created) VALUES (?, ?, ?, ?, ?)' c.execute(sql, [game1, player1, 'voting', sentence1, two_days_ago]) c.execute(sql, [game2, player1, 'invitation', sentence2, yesterday]) # Fill in some log data. data = [ # Game 1 [game1, two_days_ago, event_log.GAME_CREATED, player1, ''], [ game1, two_days_ago + timedelta(seconds=1), event_log.OWNER_CHOSE_CARD, player1, 22 ], [ game1, two_days_ago + timedelta(seconds=2), event_log.OWNER_WROTE_STORY, player1, sentence1 ], [game1, six_hours_ago, event_log.PLAYER_JOINED, player2, 33], [game1, now, event_log.PLAYER_VOTED, player2, 33], # Game 2 [game2, yesterday, event_log.GAME_CREATED, player1, ''], [ game2, yesterday + timedelta(seconds=1), event_log.OWNER_CHOSE_CARD, player1, 34 ], [ game2, six_hours_ago, event_log.OWNER_WROTE_STORY, player1, sentence2 ], [game2, an_hour_ago, event_log.PLAYER_INVITED, player1, invitee], [ game2, an_hour_ago + timedelta(seconds=1), event_log.PLAYER_JOINED, invitee, '' ], [game2, now, event_log.PLAYER_PICKED_CARD, invitee, 23] ] for d in data: c.execute( 'INSERT INTO event_logs (game_id, timestamp, event_type, player_id, data) VALUES (?, ?, ?, ?, ?)', d) # Seed the playerid2name data. aggregate.seed_playerid2name([ (player1, '*****@*****.**', 'John Johnson', False), (player2, '*****@*****.**', 'Bob Bobbson', False), (invitee, '*****@*****.**', 'Mr. Invitee', False) ]) result = aggregate.get_game_activities(c, [game1], player1, happened_since=three_days_ago) self.assertEquals(len(result), 1) self.assertEquals(result[0]['game_id'], game1) self.assertEquals(result[0]['state'], 'voting') self.assertEquals(result[0]['owner_name'], 'You') events = result[0]['events'] self.assertEquals(len(events), 5) self.assertEquals(events[0], 'You created the game') self.assertEquals(events[1], 'You chose the card') self.assertEquals(events[2], 'You wrote the story') self.assertEquals(events[3], 'Bob Bobbson joined the game') self.assertEquals(events[4], 'Bob Bobbson voted') since = six_hours_ago - timedelta(seconds=1) result = aggregate.get_game_activities(c, [game1, game2], invitee, happened_since=since) self.assertEquals(len(result), 2) self.assertEquals(result[0]['game_id'], game1) self.assertEquals(result[0]['state'], 'voting') self.assertEquals(result[0]['owner_name'], 'John Johnson') events1 = result[0]['events'] self.assertEquals(len(events1), 2) self.assertEquals(events1[0], 'Bob Bobbson joined the game') self.assertEquals(events1[1], 'Bob Bobbson voted') events2 = result[1]['events'] self.assertEquals(len(events2), 4) self.assertEquals(events2[0], 'John Johnson wrote the story') self.assertEquals(events2[1], 'John Johnson invited You to join the game') self.assertEquals(events2[2], 'You joined the game') self.assertEquals(events2[3], 'You picked a fake card') def test03_get_available_games(self): c = self.db.cursor() owner_id = 42 # Define some datetimes. now = datetime.now() an_hour_ago = now - timedelta(hours=1) yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) sec = timedelta(seconds=1) # Create some games. sql = 'INSERT INTO games (id, owner_id, state, sentence, created) VALUES (?, ?, ?, ?, ?)' games = [ [1, 'invitation', 'Story 1', three_days_ago], [2, 'invitation', 'Story 2', two_days_ago], [3, 'create', '', yesterday], [4, 'voting', 'Story 4', yesterday], [5, 'canceled', 'Story 5', an_hour_ago], [6, 'complete', 'Story 6', an_hour_ago], [7, 'invitation', 'Story 7', now], ] for game in games: c.execute(sql, [game[0], owner_id, game[1], game[2], game[3]]) # Seed the playerid2name data. aggregate.seed_playerid2name([(owner_id, '*****@*****.**', 'John Johnson', False)]) # Fetching all available games since two days ago should yeild two results. result = aggregate.get_available_games(c, two_days_ago - sec) self.assertEquals(len(result), 2) self.assertEquals(result[0]['game_id'], 2) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 2') self.assertEquals(result[1]['game_id'], 7) self.assertEquals(result[1]['owner_name'], 'John Johnson') self.assertEquals(result[1]['sentence'], 'Story 7') # Fetching all available games since three days ago should yeild three results, # but we are excluding three of them with the third optional parameter, # so there should be only one game in the result. result = aggregate.get_available_games(c, three_days_ago - sec, [2, 7, 888]) self.assertEquals(len(result), 1) self.assertEquals(result[0]['game_id'], 1) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 1') def test04_get_completed_games(self): c = self.db.cursor() owner_id = 42 # Define some datetimes. now = datetime.now() an_hour_ago = now - timedelta(hours=1) yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) # Seed the playerid2name data. aggregate.seed_playerid2name([(owner_id, '*****@*****.**', 'John Johnson', False)]) # Create some games. sql = 'INSERT INTO games (id, owner_id, state, sentence, created) VALUES (?, ?, ?, ?, ?)' games = [ [1, 'invitation', 'Story 1', three_days_ago], [2, 'create', '', two_days_ago], [3, 'complete', 'Story 3', yesterday], [4, 'voting', 'Story 4', yesterday], [5, 'canceled', 'Story 5', an_hour_ago], [6, 'complete', 'Story 6', an_hour_ago], [7, 'invitation', 'Story 7', now], ] for game in games: c.execute(sql, [game[0], owner_id, game[1], game[2], game[3]]) # Fetching completed games since two days ago should yeild two results. result = aggregate.get_completed_games(c, two_days_ago) self.assertEquals(len(result), 2) self.assertEquals(result[0]['game_id'], 3) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 3') self.assertEquals(result[1]['game_id'], 6) self.assertEquals(result[1]['owner_name'], 'John Johnson') self.assertEquals(result[1]['sentence'], 'Story 6') # Fetching completed games since three days ago should again yeild two results, # but we are excluding one of them with the third optional parameter, # so there should be only one game in the result. result = aggregate.get_available_games(c, three_days_ago, [1, 4, 888]) self.assertEquals(len(result), 1) self.assertEquals(result[0]['game_id'], 7) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 7') def test05_get_all_players(self): # Fake out the django table in our test db. c = self.db.cursor() c.execute("CREATE TABLE auth_user ( " " id INTEGER PRIMARY KEY, " " username VARCHAR(255), " " first_name VARCHAR(255) " "); ") c.execute( "CREATE TABLE cardstories_userprofile ( " " user_id INTEGER, " " activity_notifications_disabled BOOL NOT NULL DEFAULT False " "); ") players = [(1, '*****@*****.**', 'John Johnson', False), (2, '*****@*****.**', 'Bill Billson', True), (88, '*****@*****.**', None, False)] for player in players: c.execute( 'INSERT INTO auth_user (id, username, first_name) VALUES (?, ?, ?)', (player[0], player[1], player[2])) c.execute( 'INSERT INTO cardstories_userprofile (user_id, activity_notifications_disabled) VALUES (?, ?)', (player[0], player[3])) result = aggregate.get_all_players(c) self.assertEquals(len(result), 3) self.assertEquals(result[0], players[0]) self.assertEquals(result[1], players[1]) # For players without first name present in the database, it shouold return # the part of the email before the '@' character in place of the name. self.assertEquals(result[2], (88, '*****@*****.**', 'bigjoe99', False)) c.close() def test06_get_player_name(self): players = [(1, '*****@*****.**', 'John Johnson', False), (2, '*****@*****.**', 'Bob Bobbson', False), (42, '*****@*****.**', 'bigjoe99', False)] aggregate.seed_playerid2name(players) self.assertEquals(aggregate.get_player_name(1, 42), 'John Johnson') self.assertEquals(aggregate.get_player_name(2, 1), 'Bob Bobbson') self.assertEquals(aggregate.get_player_name(42, 2), 'bigjoe99') # Should return 'You' when current_player_id equals the requested player. self.assertEquals(aggregate.get_player_name(1, 1), 'You') self.assertEquals(aggregate.get_player_name(2, 2), 'You') self.assertEquals(aggregate.get_player_name(42, 42), 'You')
class LoopTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database}) self.service.startService() self.db = sqlite3.connect(self.database) # Fake out the django table in our test db. c = self.db.cursor() c.execute("CREATE TABLE auth_user ( " " id INTEGER PRIMARY KEY, " " username VARCHAR(255), " " first_name VARCHAR(255) " "); ") c.execute( "CREATE TABLE cardstories_userprofile ( " " user_id INTEGER UNIQUE, " " activity_notifications_disabled BOOL NOT NULL DEFAULT False " "); ") c.close() # Mock out send.smtp_open() and # smtp.close() calls. class FakeSmtp(object): def close(self): pass def fake_smtp_open(): return FakeSmtp() send.smtp_open = fake_smtp_open def tearDown(self): self.db.close() os.unlink(self.database) return self.service.stopService() def test01_loop(self): player1 = 1 player2 = 2 player3 = 88 player4 = 122 game1 = 111 game2 = 122 game3 = 133 # Mock out should_send_email to always return True, # we'll test that function separately. original_should_send_email = loop.should_send_email def always_true(last_active, game_activities_24h): return True loop.should_send_email = always_true now = datetime.now() yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) sec = timedelta(seconds=1) c = self.db.cursor() # Prepopulate the tables with fixture data. # ------------------------------------------------------------ # 1. auth_user auth_user_fixtures = [ (player1, '*****@*****.**', 'John Johnson', False), (player2, '*****@*****.**', 'Bill Billson', False), (player3, '*****@*****.**', None, False), (player4, '*****@*****.**', None, True) ] for player in auth_user_fixtures: c.execute( 'INSERT INTO auth_user (id, username, first_name) VALUES (?, ?, ?)', player[:3]) c.execute( 'INSERT INTO cardstories_userprofile (user_id, activity_notifications_disabled) VALUES (?, ?)', (player[0], player[3])) # 2. games games_fixtures = [ (game1, player1, 'Sentence 1', 'invitation', three_days_ago), (game2, player1, 'Sentence 2', 'complete', three_days_ago), (game3, player2, 'Sentence 3', 'invitation', now) ] for game in games_fixtures: c.execute( 'INSERT INTO games (id, owner_id, sentence, state, created) VALUES (?, ?, ?, ?, ?)', game) # 3. player2game player2game_fixtures = [(player1, game1), (player1, game2), (player2, game1), (player2, game2), (player2, game3), (player3, game2)] for player_id, game_id in player2game_fixtures: c.execute( 'insert into player2game (player_id, game_id) values (?, ?)', [player_id, game_id]) # 4. event_logs event_logs_fixtures = [ # Game 1 [game1, two_days_ago, event_log.GAME_CREATED, player1, ''], [game1, two_days_ago, event_log.OWNER_CHOSE_CARD, player1, 22], [ game1, two_days_ago, event_log.OWNER_WROTE_STORY, player1, 'Sentence 1' ], [game1, yesterday, event_log.PLAYER_JOINED, player2, ''], [game1, yesterday, event_log.PLAYER_VOTED, player2, 33], # Game 2 [game2, two_days_ago, event_log.GAME_CREATED, player1, ''], [game2, two_days_ago, event_log.OWNER_CHOSE_CARD, player1, 34], [ game2, two_days_ago, event_log.OWNER_WROTE_STORY, player1, 'Sentence 2' ], [game2, two_days_ago, event_log.PLAYER_INVITED, player1, player3], [game2, two_days_ago, event_log.PLAYER_JOINED, player3, ''], [game2, two_days_ago, event_log.PLAYER_PICKED_CARD, player3, 23], [game2, two_days_ago, event_log.PLAYER_JOINED, player2, ''], [game2, two_days_ago, event_log.PLAYER_PICKED_CARD, player2, 24], [game2, two_days_ago, event_log.PLAYER_JOINED, player4, ''], [game2, two_days_ago, event_log.GAME_MOVED_TO_VOTING, player1, ''], [game2, two_days_ago, event_log.PLAYER_VOTED, player2, 44], [game2, two_days_ago, event_log.PLAYER_VOTED, player3, 45], [game2, two_days_ago, event_log.GAME_COMPLETED, player1, ''], # Game 3 [game3, now, event_log.GAME_CREATED, player2, ''], [game3, now, event_log.OWNER_CHOSE_CARD, player2, 34], [game3, now, event_log.OWNER_WROTE_STORY, player2, 'Sentence 3'] ] for event in event_logs_fixtures: c.execute( 'INSERT INTO event_logs (game_id, timestamp, event_type, player_id, data) VALUES (?, ?, ?, ?, ?)', event) # ------------------------------------------------------------ self.db.commit() c.close() # Mock out send.send_mail to collect arguments it's been called with. calls = [] def mock_send_mail(email, name, context): calls.append([email, name, context]) send.send_mail = mock_send_mail count = loop.loop(self.database, self.database) # Should send out two emails (for player1 and player 3). # The email shouldn't be sent to player2 because he was last active 'now', # and nothing has happened since now (a blank email such as that shouldn't be sent). # The email shouldn't be sent to player4 because he has unsubscribed from the emails. self.assertEquals(count, 2) # Let's see what send_mail has been called with. self.assertEquals(len(calls), 2) # For player1: self.assertEquals(calls[0][1], '*****@*****.**') # No completed games: self.assertEquals(len(calls[0][2]['completed_games']), 0) # One available game (game3 by player2): self.assertEquals(len(calls[0][2]['available_games']), 1) game = calls[0][2]['available_games'][0] self.assertEquals(game['game_id'], game3) self.assertEquals(game['owner_name'], 'Bill Billson') self.assertEquals(game['sentence'], 'Sentence 3') # Player1 was last active two_days ago. # Since then (yesterday), two events happened on one of his games (game1). self.assertEquals(len(calls[0][2]['game_activities']), 1) activity = calls[0][2]['game_activities'][0] self.assertEquals(activity['game_id'], game1) self.assertEquals(activity['state'], 'invitation') self.assertEquals(activity['owner_name'], 'You') self.assertEquals(activity['sentence'], 'Sentence 1') self.assertEquals(len(activity['events']), 2) self.assertEquals(activity['events'][0], 'Bill Billson joined the game') self.assertEquals(activity['events'][1], 'Bill Billson voted') # For player3: self.assertEquals(calls[1][1], '*****@*****.**') # No completed games: self.assertEquals(len(calls[1][2]['completed_games']), 0) # One available game (game3 by player2): self.assertEquals(len(calls[1][2]['available_games']), 1) self.assertEquals(game['game_id'], game3) self.assertEquals(game['owner_name'], 'Bill Billson') self.assertEquals(game['sentence'], 'Sentence 3') # No game activities - player3 has less been active two days ago, but he has only # participated in game2 which hasn't seen any activity since then: self.assertEquals(len(calls[1][2]['game_activities']), 0) loop.should_send_email = original_should_send_email def test02_should_send_email(self): def to_iso_string(datetime): return datetime.strftime('%Y-%m-%d %H:%M:%S') now = datetime.now() # Should always send if player's last activity was less than 24 hours ago. self.assertTrue(loop.should_send_email(to_iso_string(now), [])) self.assertTrue( loop.should_send_email(to_iso_string(now - timedelta(hours=12)), [])) self.assertTrue( loop.should_send_email(to_iso_string(now - timedelta(hours=22)), [])) # Should always send if player's last activity was 7 days ago. self.assertTrue( loop.should_send_email(to_iso_string(now - timedelta(days=7)), [])) self.assertTrue( loop.should_send_email( to_iso_string(now - timedelta(days=7, hours=5)), [])) self.assertTrue( loop.should_send_email( to_iso_string(now - timedelta(days=7, hours=23)), [])) # Should always send if player's last activity was 30, 60, 90, ... days ago. self.assertTrue( loop.should_send_email(to_iso_string(now - timedelta(days=30)), [])) self.assertTrue( loop.should_send_email( to_iso_string(now - timedelta(days=60, hours=5)), [])) self.assertTrue( loop.should_send_email( to_iso_string(now - timedelta(days=90, hours=23)), [])) # Should NOT send otherwise, if there's no recent activities on player's games. self.assertFalse( loop.should_send_email(to_iso_string(now - timedelta(days=2)), [])) self.assertFalse( loop.should_send_email( to_iso_string(now - timedelta(days=26, hours=5)), [])) self.assertFalse( loop.should_send_email( to_iso_string(now - timedelta(days=6, hours=23)), [])) # Should still send, if there were recent activities on player's games. fake_activity = [{'game_id': 42, 'state': 'vote', 'events': []}] self.assertTrue( loop.should_send_email(to_iso_string(now - timedelta(days=2)), [fake_activity])) self.assertTrue( loop.should_send_email( to_iso_string(now - timedelta(days=26, hours=5)), [fake_activity])) self.assertTrue( loop.should_send_email( to_iso_string(now - timedelta(days=6, hours=23)), [fake_activity]))
class LoopTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database}) self.service.startService() self.db = sqlite3.connect(self.database) # Fake out the django table in our test db. c = self.db.cursor() c.execute( "CREATE TABLE auth_user ( " " id INTEGER PRIMARY KEY, " " username VARCHAR(255), " " first_name VARCHAR(255) " "); ") c.execute( "CREATE TABLE cardstories_userprofile ( " " user_id INTEGER UNIQUE, " " activity_notifications_disabled BOOL NOT NULL DEFAULT False " "); ") c.close() # Mock out send.smtp_open() and # smtp.close() calls. class FakeSmtp(object): def close(self): pass def fake_smtp_open(): return FakeSmtp() send.smtp_open = fake_smtp_open def tearDown(self): self.db.close() os.unlink(self.database) return self.service.stopService() def test01_loop(self): player1 = 1 player2 = 2 player3 = 88 player4 = 122 game1 = 111 game2 = 122 game3 = 133 # Mock out should_send_email to always return True, # we'll test that function separately. original_should_send_email = loop.should_send_email def always_true(last_active, game_activities_24h): return True loop.should_send_email = always_true now = datetime.now() yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) sec = timedelta(seconds=1) c = self.db.cursor() # Prepopulate the tables with fixture data. # ------------------------------------------------------------ # 1. auth_user auth_user_fixtures = [ (player1, '*****@*****.**', 'John Johnson', False), (player2, '*****@*****.**', 'Bill Billson', False), (player3, '*****@*****.**', None, False), (player4, '*****@*****.**', None, True) ] for player in auth_user_fixtures: c.execute('INSERT INTO auth_user (id, username, first_name) VALUES (?, ?, ?)', player[:3]) c.execute('INSERT INTO cardstories_userprofile (user_id, activity_notifications_disabled) VALUES (?, ?)', (player[0], player[3])) # 2. games games_fixtures = [ (game1, player1, 'Sentence 1', 'invitation', three_days_ago), (game2, player1, 'Sentence 2', 'complete', three_days_ago), (game3, player2, 'Sentence 3', 'invitation', now) ] for game in games_fixtures: c.execute('INSERT INTO games (id, owner_id, sentence, state, created) VALUES (?, ?, ?, ?, ?)', game) # 3. player2game player2game_fixtures =[ (player1, game1), (player1, game2), (player2, game1), (player2, game2), (player2, game3), (player3, game2) ] for player_id, game_id in player2game_fixtures: c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id, game_id]) # 4. event_logs event_logs_fixtures = [ # Game 1 [game1, two_days_ago, event_log.GAME_CREATED, player1, ''], [game1, two_days_ago, event_log.OWNER_CHOSE_CARD, player1, 22], [game1, two_days_ago, event_log.OWNER_WROTE_STORY, player1, 'Sentence 1'], [game1, yesterday, event_log.PLAYER_JOINED, player2, ''], [game1, yesterday, event_log.PLAYER_VOTED, player2, 33], # Game 2 [game2, two_days_ago, event_log.GAME_CREATED, player1, ''], [game2, two_days_ago, event_log.OWNER_CHOSE_CARD, player1, 34], [game2, two_days_ago, event_log.OWNER_WROTE_STORY, player1, 'Sentence 2'], [game2, two_days_ago, event_log.PLAYER_INVITED, player1, player3], [game2, two_days_ago, event_log.PLAYER_JOINED, player3, ''], [game2, two_days_ago, event_log.PLAYER_PICKED_CARD, player3, 23], [game2, two_days_ago, event_log.PLAYER_JOINED, player2, ''], [game2, two_days_ago, event_log.PLAYER_PICKED_CARD, player2, 24], [game2, two_days_ago, event_log.PLAYER_JOINED, player4, ''], [game2, two_days_ago, event_log.GAME_MOVED_TO_VOTING, player1, ''], [game2, two_days_ago, event_log.PLAYER_VOTED, player2, 44], [game2, two_days_ago, event_log.PLAYER_VOTED, player3, 45], [game2, two_days_ago, event_log.GAME_COMPLETED, player1, ''], # Game 3 [game3, now, event_log.GAME_CREATED, player2, ''], [game3, now, event_log.OWNER_CHOSE_CARD, player2, 34], [game3, now, event_log.OWNER_WROTE_STORY, player2, 'Sentence 3'] ] for event in event_logs_fixtures: c.execute('INSERT INTO event_logs (game_id, timestamp, event_type, player_id, data) VALUES (?, ?, ?, ?, ?)', event) # ------------------------------------------------------------ self.db.commit() c.close() # Mock out send.send_mail to collect arguments it's been called with. calls = [] def mock_send_mail(email, name, context): calls.append([email, name, context]) send.send_mail = mock_send_mail count = loop.loop(self.database, self.database) # Should send out two emails (for player1 and player 3). # The email shouldn't be sent to player2 because he was last active 'now', # and nothing has happened since now (a blank email such as that shouldn't be sent). # The email shouldn't be sent to player4 because he has unsubscribed from the emails. self.assertEquals(count, 2) # Let's see what send_mail has been called with. self.assertEquals(len(calls), 2) # For player1: self.assertEquals(calls[0][1], '*****@*****.**') # No completed games: self.assertEquals(len(calls[0][2]['completed_games']), 0) # One available game (game3 by player2): self.assertEquals(len(calls[0][2]['available_games']), 1) game = calls[0][2]['available_games'][0] self.assertEquals(game['game_id'], game3) self.assertEquals(game['owner_name'], 'Bill Billson') self.assertEquals(game['sentence'], 'Sentence 3') # Player1 was last active two_days ago. # Since then (yesterday), two events happened on one of his games (game1). self.assertEquals(len(calls[0][2]['game_activities']), 1) activity = calls[0][2]['game_activities'][0] self.assertEquals(activity['game_id'], game1) self.assertEquals(activity['state'], 'invitation') self.assertEquals(activity['owner_name'], 'You') self.assertEquals(activity['sentence'], 'Sentence 1') self.assertEquals(len(activity['events']), 2) self.assertEquals(activity['events'][0], 'Bill Billson joined the game') self.assertEquals(activity['events'][1], 'Bill Billson voted') # For player3: self.assertEquals(calls[1][1], '*****@*****.**') # No completed games: self.assertEquals(len(calls[1][2]['completed_games']), 0) # One available game (game3 by player2): self.assertEquals(len(calls[1][2]['available_games']), 1) self.assertEquals(game['game_id'], game3) self.assertEquals(game['owner_name'], 'Bill Billson') self.assertEquals(game['sentence'], 'Sentence 3') # No game activities - player3 has less been active two days ago, but he has only # participated in game2 which hasn't seen any activity since then: self.assertEquals(len(calls[1][2]['game_activities']), 0) loop.should_send_email = original_should_send_email def test02_should_send_email(self): def to_iso_string(datetime): return datetime.strftime('%Y-%m-%d %H:%M:%S') now = datetime.now() # Should always send if player's last activity was less than 24 hours ago. self.assertTrue(loop.should_send_email(to_iso_string(now), [])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(hours=12)), [])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(hours=22)), [])) # Should always send if player's last activity was 7 days ago. self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=7)), [])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=7, hours=5)), [])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=7, hours=23)), [])) # Should always send if player's last activity was 30, 60, 90, ... days ago. self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=30)), [])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=60, hours=5)), [])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=90, hours=23)), [])) # Should NOT send otherwise, if there's no recent activities on player's games. self.assertFalse(loop.should_send_email(to_iso_string(now - timedelta(days=2)), [])) self.assertFalse(loop.should_send_email(to_iso_string(now - timedelta(days=26, hours=5)), [])) self.assertFalse(loop.should_send_email(to_iso_string(now - timedelta(days=6, hours=23)), [])) # Should still send, if there were recent activities on player's games. fake_activity = [{'game_id': 42, 'state': 'vote', 'events': []}] self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=2)), [fake_activity])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=26, hours=5)), [fake_activity])) self.assertTrue(loop.should_send_email(to_iso_string(now - timedelta(days=6, hours=23)), [fake_activity]))
class MailTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({ 'db': self.database, 'plugins-libdir': '../fixture', 'plugins-confdir': '../fixture', 'plugins-dir': '../fixture' }) self.service.startService() def tearDown(self): return self.service.stopService() @defer.inlineCallbacks def complete_game(self): self.owner_id = 1 self.player1 = 2 self.player2 = 3 self.owner_email = '*****@*****.**' self.player1_email = '*****@*****.**' self.player2_email = '*****@*****.**' self.winner_card = winner_card = 5 sentence = 'SENTENCE' game = yield self.service.create({'owner_id': [self.owner_id]}) self.game_id = game['game_id'] yield self.service.set_card({ 'action': ['set_card'], 'card': [winner_card], 'game_id': [self.game_id], 'player_id': [self.owner_id] }) yield self.service.set_sentence({ 'action': ['set_sentence'], 'sentence': [sentence], 'game_id': [self.game_id], 'player_id': [self.owner_id] }) yield self.service.invite({ 'action': ['invite'], 'game_id': [self.game_id], 'invited_email': [self.player1_email], 'owner_id': [self.owner_id] }) for player_id in (self.player1, self.player2): yield self.service.participate({ 'action': ['participate'], 'player_id': [player_id], 'game_id': [self.game_id] }) player = yield self.service.player2game({ 'action': ['player2game'], 'player_id': [player_id], 'game_id': [self.game_id] }) card = player['cards'][0] yield self.service.pick({ 'action': ['pick'], 'player_id': [player_id], 'game_id': [self.game_id], 'card': [card] }) yield self.service.voting({ 'action': ['voting'], 'game_id': [self.game_id], 'owner_id': [self.owner_id] }) winner_id = self.player1 yield self.service.vote({ 'action': ['vote'], 'game_id': [self.game_id], 'player_id': [winner_id], 'card': [winner_card] }) loser_id = self.player2 yield self.service.vote({ 'action': ['vote'], 'game_id': [self.game_id], 'player_id': [loser_id], 'card': [120] }) self.assertTrue(self.service.games.has_key(self.game_id)) yield self.service.complete({ 'action': ['complete'], 'game_id': [self.game_id], 'owner_id': [self.owner_id] }) self.assertFalse(self.service.games.has_key(self.game_id)) defer.returnValue(True) def test00_init(self): plugin = mail.Plugin(self.service, []) self.assertEquals(plugin.name(), 'mail') self.assertEquals(plugin.host, 'localhost') for allowed in mail.Plugin.ALLOWED: self.assertTrue(plugin.templates.has_key(allowed)) @defer.inlineCallbacks def test01_invite(self): plugin = mail.Plugin(self.service, []) def get_player_email(player_id): if player_id == self.player1: email = self.player1_email elif player_id == self.player2: email = self.player2_email elif player_id == self.owner_id: email = self.owner_email return defer.succeed(email) self.service.auth.get_player_email = get_player_email def get_player_id(email, create=False): return defer.succeed(self.player1) self.service.auth.get_player_id = get_player_id self.count = 0 def sendmail(host, sender, recipients, email): self.count += 1 self.assertSubstring('game_id=%d' % self.game_id, email) self.assertSubstring('url=URL', email) self.assertSubstring('static_url=STATIC_URL', email) if self.count == 1: self.assertSubstring('_INVITE_', email) self.assertSubstring('owner_email=%s' % self.owner_name, email) elif self.count in (2, 3): self.assertSubstring('_PICK_', email) if self.count == 2: self.assertSubstring('player_email=%s' % self.player1_name, email) elif self.count == 3: self.assertSubstring('player_email=%s' % self.player2_name, email) elif self.count in (4, 5): self.assertSubstring('_VOTE_', email) if self.count == 4: self.assertSubstring('player_email=%s' % self.player1_name, email) elif self.count == 5: self.assertSubstring('player_email=%s' % self.player2_name, email) elif self.count == 6: self.assertSubstring('_VOTING_', email) elif self.count == 7: self.assertSubstring('_COMPLETE_', email) self.assertSubstring('owner_email=%s' % self.owner_name, email) return defer.succeed(True) plugin.sendmail = sendmail yield self.complete_game() self.assertEqual(self.count, 7) @defer.inlineCallbacks def test02_send_nothing(self): self.service.auth.get_players_emails = Mock( return_value=['not_an_email']) plugin = mail.Plugin(self.service, []) d = plugin.send('SUBJECT', [1], 'TEMPLATE', {}) def check(result): self.assertFalse(result) d.addCallback(check) yield d
class TableTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database, 'plugins-confdir': 'CONFDIR', 'plugins-libdir': 'LIBDIR', 'static': 'STATIC'}) self.service.auth = Mock() self.service.startService() # Fake an activity plugin to which the table plugin should listen self.mock_activity_instance = Mock() self.mock_activity_instance.name.return_value = 'activity' self.table_instance = table.Plugin(self.service, [self.mock_activity_instance]) self.mock_activity_instance.listen.assert_called_once_with() self.mock_activity_instance.reset_mock() def tearDown(self): # kill the service we started before the test return self.service.stopService() @defer.inlineCallbacks def test01_no_table(self): player_id = 12 game_id = 59 # Request for tables should direct the player to create his own game state = yield self.table_instance.state({'type': ['table'], 'game_id': ['undefined'], 'player_id': [player_id]}) self.assertEqual(state, [{'game_id': None, 'next_game_id': None, 'next_owner_id': player_id}, [player_id]]) # Next games of existing games should also ask to create a new game, since we have no table info state = yield self.table_instance.state({'type': ['table'], 'game_id': [game_id], 'player_id': [player_id]}) self.assertEqual(state, [{'game_id': game_id, 'next_game_id': None, 'next_owner_id': player_id}, [player_id]]) @defer.inlineCallbacks def test02_create_game_next(self): player1 = 12 player2 = 78 player3 = 98 # Show all players as online self.mock_activity_instance.is_player_online.return_value = True # Poll to know when a table gets available poll = self.table_instance.poll({'game_id': ['undefined'], 'modified': [0]}) result = yield poll modified = result['modified'][0] # Start a new poll immediately. poll = self.table_instance.poll({'game_id': ['undefined'], 'modified': [modified]}) # Make sure it doesn't return at once. self.assertFalse(poll.called) self.assertEqual(modified, self.table_instance.get_modified({'game_id': ['undefined']})) # Create first game response = yield self.service.handle([], {'action': ['create'], 'owner_id': [player1]}) game_id = response['game_id'] # Poll must return to inform players waiting for an available table result = yield poll modified = result['modified'][0] # Associate all players with the game in the tabs db table. sql = "INSERT INTO tabs (player_id, game_id, created) VALUES (%d, %d, datetime('now'))" for player_id in [player1, player2, player3]: yield self.service.db.runQuery(sql % (player_id, game_id)) state = yield self.table_instance.state({'type': ['table'], 'game_id': ['undefined'], 'player_id': [player2]}) self.assertEqual(state, [{'game_id': None, 'next_game_id': game_id, 'next_owner_id': player1}, [player1]]) # Initial state of the table itself 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': None}, []]) # Start a poll on this table to know when the next game will be available there poll = self.table_instance.poll({'game_id': [game_id], 'modified': [0]}) result = yield poll modified = result['modified'][0] poll = self.table_instance.poll({'game_id': [game_id], 'modified': [modified]}) self.assertFalse(poll.called) self.assertEqual(modified, self.table_instance.get_modified({'game_id': [game_id]})) # Complete first game yield self.complete_game(game_id, player1, player2, player3) 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': player2}, [player2]]) # Poll must return to announce the next owner result = yield poll modified = result['modified'][0] poll = self.table_instance.poll({'game_id': [game_id], 'modified': [modified]}) self.assertFalse(poll.called) # Next owner disconnects before creating the game - should chose another player def is_player_online(*args, **kw): if args[0] == player2: return False return True self.mock_activity_instance.is_player_online.side_effect = is_player_online yield self.table_instance.on_activity_notification({'type': 'player_disconnecting', 'player_id': 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': player3}, [player3]]) # Poll must return to announce the next owner result = yield poll modified = result['modified'][0] poll = self.table_instance.poll({'game_id': [game_id], 'modified': [modified]}) self.assertFalse(poll.called) # Next owner closes the tab before creating the game - should chose another player yield self.service.remove_tab({'action': ['remove_tab'], 'player_id': [player3], 'game_id': [game_id]}) # Poll must return to announce the next owner result = yield poll modified = result['modified'][0] poll = self.table_instance.poll({'game_id': [game_id], 'modified': [modified]}) self.assertFalse(poll.called) 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]]) # Create second game response = yield self.service.handle([], {'action': ['create'], 'owner_id': [player2], 'card': [1], 'previous_game_id': [game_id], 'sentence': ['sentence']}) game2_id = response['game_id'] 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': game2_id, 'next_owner_id': player2}, [player2]]) # Poll must return to announce the new game result = yield poll modified = result['modified'][0] # All players quit - deletes the table self.mock_activity_instance.is_player_online.return_value = False yield self.table_instance.on_activity_notification({'type': 'player_disconnecting', 'player_id': player1}) yield self.table_instance.on_activity_notification({'type': 'player_disconnecting', 'player_id': player3}) 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]]) @defer.inlineCallbacks def complete_game(self, game_id, owner, player1, player2): # Set card yield self.service.handle([], {'action': ['set_card'], 'card': [1], 'game_id': [game_id], 'player_id': [owner]}) # Set sentence yield self.service.handle([], {'action': ['set_sentence'], 'sentence': ['SENTENCE'], 'game_id': [game_id], 'player_id': [owner]}) # Join yield self.service.handle([], {'action': ['participate'], 'game_id': [game_id], 'player_id': [player1]}) yield self.service.handle([], {'action': ['participate'], 'game_id': [game_id], 'player_id': [player2]}) # Pick game, players_ids = yield self.table_instance.get_game_by_id(game_id, player1) yield self.service.handle([], {'action': ['pick'], 'game_id': [game_id], 'player_id': [player1], 'card': [game['self'][2][0]]}) game, players_ids = yield self.table_instance.get_game_by_id(game_id, player2) yield self.service.handle([], {'action': ['pick'], 'game_id': [game_id], 'player_id': [player2], 'card': [game['self'][2][0]]}) # Vote yield self.service.handle([], {'action': ['voting'], 'game_id': [game_id], 'owner_id': [game['owner_id']]}) @defer.inlineCallbacks def player_vote(player_id): game, players_ids = yield self.table_instance.get_game_by_id(game_id, player_id) my_card = game['self'][0] board = [x for x in game['board'] if x != my_card] yield self.service.handle([], {'action': ['vote'], 'game_id': [game_id], 'player_id': [player_id], 'card': [board[0]]}) yield player_vote(player1) yield player_vote(player2) # Complete yield self.service.handle([], {'action': ['complete'], 'game_id': [game_id], 'owner_id': [game['owner_id']]}) @defer.inlineCallbacks def test03_disconnect_with_two_tables(self): """ Bug #797 - ValueError: list.remove(x): x not in list (table.py, delete_table) """ player_id = 12 self.mock_activity_instance.is_player_online.return_value = True # Create two tables self.assertEqual(len(self.table_instance.tables), 0) response = yield self.service.handle([], {'action': ['create'], 'owner_id': [player_id],}) game1_id = response['game_id'] yield self.service.handle([], {'action': ['set_card'], 'card': [1], 'player_id': [player_id], 'game_id': [game1_id]}) yield self.service.handle([], {'action': ['set_sentence'], 'sentence': ['sentence'], 'player_id': [player_id], 'game_id': [game1_id]}) response = yield self.service.handle([], {'action': ['create'], 'owner_id': [player_id],}) game2_id = response['game_id'] yield self.service.handle([], {'action': ['set_card'], 'card': [1], 'player_id': [player_id], 'game_id': [game2_id]}) yield self.service.handle([], {'action': ['set_sentence'], 'sentence': ['sentence'], 'player_id': [player_id], 'game_id': [game2_id]}) self.assertEqual(len(self.table_instance.tables), 2) # Players quits - deletes the two tables simulteanously self.mock_activity_instance.is_player_online.return_value = False yield self.table_instance.on_activity_notification({'type': 'player_disconnecting', 'player_id': player_id}) self.assertEqual(len(self.table_instance.tables), 0) @defer.inlineCallbacks def test04_postprocess(self): game_id = 55 tab1_game_id = 17 tab2_game_id = 18 player_id = 77 mock_request = Mock() mock_request.args = {'action': ['state'], 'player_id': [player_id], 'game_id': [game_id], 'type': ['tabs']} response = [{'type': 'tabs', 'games': [{'id': tab1_game_id, 'state': 'complete'}, {'id': tab2_game_id, 'state': 'complete'}]}] def mock_state(args): game_id = args['game_id'][0] if game_id == tab1_game_id: next_game_id = 42 next_owner_id = player_id elif game_id == tab2_game_id: next_game_id = None next_owner_id = 21 result = [{'game_id': game_id, 'next_game_id': next_game_id, 'next_owner_id': next_owner_id}, [player_id]] return result self.table_instance.state = mock_state result = yield self.table_instance.postprocess(response, mock_request) # During postprocessing, next_owner_id and next_game_id should be added to # the response. self.assertEqual(result[0]['games'][0]['next_owner_id'], player_id) self.assertEqual(result[0]['games'][0]['next_game_id'], 42) self.assertEqual(result[0]['games'][1]['next_owner_id'], 21) self.assertEqual(result[0]['games'][1]['next_game_id'], None) # Make sure things don't fail if response is not of the expected shape. yield self.table_instance.postprocess({'type': 'chat'}, mock_request) yield self.table_instance.postprocess([[1, 2, {'this': 'test'}]], mock_request) @defer.inlineCallbacks def test05_close_tab_with_nonexisting_table(self): player_id = 43 game_id = 1123321 self.assertEqual(len(self.table_instance.tables), 0) result = yield self.table_instance.on_tab_closed(player_id, game_id) self.assertEqual(result, True)
class AggregateTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database}) self.service.startService() self.db = sqlite3.connect(self.database) def tearDown(self): self.db.close() os.unlink(self.database) return self.service.stopService() def test01_get_player_game_ids(self): c = self.db.cursor() player_id = 1231 game_ids = [34, 64, 322, 340] # fill in some game_ids for player. for game_id in game_ids: c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id, game_id]) # fill in some bogus ones. c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id + 3, game_ids[0]]) c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id + 2, game_ids[0]]) c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id + 2, game_ids[0] + 12]) result = aggregate.get_player_game_ids(c, player_id) self.assertEquals(sorted(result), sorted(game_ids)) def test02_get_game_activities(self): c = self.db.cursor() game1 = 99 game2 = 199 sentence1 = 'This Story' sentence2 = 'That Story' player1 = 11 player2 = 12 invitee = 878 # Define some datetimes. now = datetime.now() an_hour_ago = now - timedelta(hours=1) six_hours_ago = now - timedelta(hours=6) yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) # Create two games. sql = 'INSERT INTO games (id, owner_id, state, sentence, created) VALUES (?, ?, ?, ?, ?)' c.execute(sql, [game1, player1, 'voting', sentence1, two_days_ago]) c.execute(sql, [game2, player1, 'invitation', sentence2, yesterday]) # Fill in some log data. data = [ # Game 1 [game1, two_days_ago, event_log.GAME_CREATED, player1, ''], [game1, two_days_ago + timedelta(seconds=1), event_log.OWNER_CHOSE_CARD, player1, 22], [game1, two_days_ago + timedelta(seconds=2), event_log.OWNER_WROTE_STORY, player1, sentence1], [game1, six_hours_ago, event_log.PLAYER_JOINED, player2, 33], [game1, now, event_log.PLAYER_VOTED, player2, 33], # Game 2 [game2, yesterday, event_log.GAME_CREATED, player1, ''], [game2, yesterday + timedelta(seconds=1), event_log.OWNER_CHOSE_CARD, player1, 34], [game2, six_hours_ago, event_log.OWNER_WROTE_STORY, player1, sentence2], [game2, an_hour_ago, event_log.PLAYER_INVITED, player1, invitee], [game2, an_hour_ago + timedelta(seconds=1), event_log.PLAYER_JOINED, invitee, ''], [game2, now, event_log.PLAYER_PICKED_CARD, invitee, 23] ] for d in data: c.execute('INSERT INTO event_logs (game_id, timestamp, event_type, player_id, data) VALUES (?, ?, ?, ?, ?)', d) # Seed the playerid2name data. aggregate.seed_playerid2name([ (player1, '*****@*****.**', 'John Johnson'), (player2, '*****@*****.**', 'Bob Bobbson'), (invitee, '*****@*****.**', 'Mr. Invitee') ]) result = aggregate.get_game_activities(c, [game1], player1, happened_since=three_days_ago) self.assertEquals(len(result), 1) self.assertEquals(result[0]['game_id'], game1) self.assertEquals(result[0]['state'], 'voting') self.assertEquals(result[0]['owner_name'], 'You') events = result[0]['events'] self.assertEquals(len(events), 5) self.assertEquals(events[0], 'You created the game') self.assertEquals(events[1], 'You chose the card') self.assertEquals(events[2], 'You wrote the story') self.assertEquals(events[3], 'Bob Bobbson joined the game') self.assertEquals(events[4], 'Bob Bobbson voted') since = six_hours_ago - timedelta(seconds=1) result = aggregate.get_game_activities(c, [game1, game2], invitee, happened_since=since) self.assertEquals(len(result), 2) self.assertEquals(result[0]['game_id'], game1) self.assertEquals(result[0]['state'], 'voting') self.assertEquals(result[0]['owner_name'], 'John Johnson') events1 = result[0]['events'] self.assertEquals(len(events1), 2) self.assertEquals(events1[0], 'Bob Bobbson joined the game') self.assertEquals(events1[1], 'Bob Bobbson voted') events2 = result[1]['events'] self.assertEquals(len(events2), 4) self.assertEquals(events2[0], 'John Johnson wrote the story') self.assertEquals(events2[1], 'John Johnson invited You to join the game') self.assertEquals(events2[2], 'You joined the game') self.assertEquals(events2[3], 'You picked a fake card') def test03_get_available_games(self): c = self.db.cursor() owner_id = 42 # Define some datetimes. now = datetime.now() an_hour_ago = now - timedelta(hours=1) yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) sec = timedelta(seconds=1) # Create some games. sql = 'INSERT INTO games (id, owner_id, state, sentence, created) VALUES (?, ?, ?, ?, ?)' games = [ [1, 'invitation', 'Story 1', three_days_ago], [2, 'invitation', 'Story 2', two_days_ago], [3, 'create', '', yesterday], [4, 'voting', 'Story 4', yesterday], [5, 'canceled', 'Story 5', an_hour_ago], [6, 'complete', 'Story 6', an_hour_ago], [7, 'invitation', 'Story 7', now], ] for game in games: c.execute(sql, [game[0], owner_id, game[1], game[2], game[3]]) # Seed the playerid2name data. aggregate.seed_playerid2name([(owner_id, '*****@*****.**', 'John Johnson')]) # Fetching all available games since two days ago should yeild two results. result = aggregate.get_available_games(c, two_days_ago - sec) self.assertEquals(len(result), 2) self.assertEquals(result[0]['game_id'], 2) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 2') self.assertEquals(result[1]['game_id'], 7) self.assertEquals(result[1]['owner_name'], 'John Johnson') self.assertEquals(result[1]['sentence'], 'Story 7') # Fetching all available games since three days ago should yeild three results, # but we are excluding three of them with the third optional parameter, # so there should be only one game in the result. result = aggregate.get_available_games(c, three_days_ago - sec, [2, 7, 888]) self.assertEquals(len(result), 1) self.assertEquals(result[0]['game_id'], 1) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 1') def test04_get_completed_games(self): c = self.db.cursor() owner_id = 42 # Define some datetimes. now = datetime.now() an_hour_ago = now - timedelta(hours=1) yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) # Seed the playerid2name data. aggregate.seed_playerid2name([(owner_id, '*****@*****.**', 'John Johnson')]) # Create some games. sql = 'INSERT INTO games (id, owner_id, state, sentence, created) VALUES (?, ?, ?, ?, ?)' games = [ [1, 'invitation', 'Story 1', three_days_ago], [2, 'create', '', two_days_ago], [3, 'complete', 'Story 3', yesterday], [4, 'voting', 'Story 4', yesterday], [5, 'canceled', 'Story 5', an_hour_ago], [6, 'complete', 'Story 6', an_hour_ago], [7, 'invitation', 'Story 7', now], ] for game in games: c.execute(sql, [game[0], owner_id, game[1], game[2], game[3]]) # Fetching completed games since two days ago should yeild two results. result = aggregate.get_completed_games(c, two_days_ago) self.assertEquals(len(result), 2) self.assertEquals(result[0]['game_id'], 3) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 3') self.assertEquals(result[1]['game_id'], 6) self.assertEquals(result[1]['owner_name'], 'John Johnson') self.assertEquals(result[1]['sentence'], 'Story 6') # Fetching completed games since three days ago should again yeild two results, # but we are excluding one of them with the third optional parameter, # so there should be only one game in the result. result = aggregate.get_available_games(c, three_days_ago, [1, 4, 888]) self.assertEquals(len(result), 1) self.assertEquals(result[0]['game_id'], 7) self.assertEquals(result[0]['owner_name'], 'John Johnson') self.assertEquals(result[0]['sentence'], 'Story 7') def test05_get_all_players(self): # Fake out the django table in our test db. c = self.db.cursor() c.execute( "CREATE TABLE auth_user ( " " id INTEGER PRIMARY KEY, " " username VARCHAR(255), " " first_name VARCHAR(255) " "); ") players = [ (1, '*****@*****.**', 'John Johnson'), (2, '*****@*****.**', 'Bill Billson'), (88, '*****@*****.**', None) ] for player in players: c.execute('INSERT INTO auth_user (id, username, first_name) VALUES (?, ?, ?)', player) result = aggregate.get_all_players(c) self.assertEquals(len(result), 3) self.assertEquals(result[0], players[0]) self.assertEquals(result[1], players[1]) # For players without first name present in the database, it shouold return # the part of the email before the '@' character in place of the name. self.assertEquals(result[2], (88, '*****@*****.**', 'bigjoe99')) c.close() def test06_get_player_name(self): players = [ (1, '*****@*****.**', 'John Johnson'), (2, '*****@*****.**', 'Bob Bobbson'), (42, '*****@*****.**', 'bigjoe99') ] aggregate.seed_playerid2name(players) self.assertEquals(aggregate.get_player_name(1, 42), 'John Johnson') self.assertEquals(aggregate.get_player_name(2, 1), 'Bob Bobbson') self.assertEquals(aggregate.get_player_name(42, 2), 'bigjoe99') # Should return 'You' when current_player_id equals the requested player. self.assertEquals(aggregate.get_player_name(1, 1), 'You') self.assertEquals(aggregate.get_player_name(2, 2), 'You') self.assertEquals(aggregate.get_player_name(42, 42), 'You')
class ChatTest(unittest.TestCase): # initialise our test with a service that we can use during testing and a testing database def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) # Empty 'chat/' subdir self.test_logdir = 'test_logdir.tmp' if os.path.exists(self.test_logdir): shutil.rmtree(self.test_logdir) self.service = CardstoriesService({'db': self.database, 'plugins-confdir': 'CONFDIR', 'plugins-libdir': 'LIBDIR', 'plugins-logdir': self.test_logdir, 'static': 'STATIC' }) self.service.startService() def tearDown(self): # kill the service we started before the test return self.service.stopService() @defer.inlineCallbacks def complete_game(self): self.winner_card = winner_card = 5 sentence = 'SENTENCE' owner_id = 15 result = yield self.service.create({'card': [winner_card], 'sentence': [sentence], 'owner_id': [owner_id]}) game_id = result['game_id'] yield self.service.set_card({'action': ['set_card'], 'card': [winner_card], 'player_id': [owner_id], 'game_id': [game_id]}) yield self.service.set_sentence({'action': ['set_sentence'], 'sentence': [sentence], 'player_id': [owner_id], 'game_id': [game_id]}) self.player1 = 16 for player_id in (self.player1, 17): yield self.service.participate({ 'action': ['participate'], 'player_id': [player_id], 'game_id': [game_id] }) player = yield self.service.player2game({ 'action': ['player2game'], 'player_id': [player_id], 'game_id': [game_id] }) card = player['cards'][0] yield self.service.pick({ 'action': ['pick'], 'player_id': [player_id], 'game_id': [game_id], 'card': [card] }) yield self.service.voting({ 'action': ['voting'], 'game_id': [game_id], 'owner_id': [owner_id] }) winner_id = self.player1 yield self.service.vote({ 'action': ['vote'], 'game_id': [game_id], 'player_id': [winner_id], 'card': [winner_card] }) loser_id = 17 yield self.service.vote({ 'action': ['vote'], 'game_id': [game_id], 'player_id': [loser_id], 'card': [120] }) self.assertTrue(self.service.games.has_key(game_id)) yield self.service.complete({ 'action': ['complete'], 'game_id': [game_id], 'owner_id': [owner_id] }) self.assertFalse(self.service.games.has_key(game_id)) defer.returnValue(True) def test00_create_logdir(self): chat_instance = Plugin(self.service, []) logdir = os.path.join(self.test_logdir, 'chat') self.assertTrue(os.path.exists(logdir)) @defer.inlineCallbacks def test00_preprocess_noop(self): # create a new instance of the plugin and make sure it's the right type chat_instance = Plugin(self.service, []) self.assertEquals(chat_instance.name(), 'chat') # run a game to get into a realistic situation yield self.complete_game() # run the preprocess method and make sure it does not affect anything during a normal 'game' event result_in = 'RESULT' result_out = yield chat_instance.preprocess(result_in, Request(action=['game'])) self.assertEquals(result_in, result_out) @defer.inlineCallbacks def test01_add_message(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 sentence = "This is my sentence!" now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) # verify we have no messages yet self.assertEquals(len(chat_instance.messages), 0) # run the request result = yield chat_instance.preprocess(True, request) # verify we now have one message self.assertEquals(len(chat_instance.messages), 1) # verify the event has been removed from the pipeline self.assertFalse(request.args.has_key('action')) # verify the message we added is in the list self.assertEquals(chat_instance.messages[0]["player_id"], player_id) self.assertEquals(chat_instance.messages[0]["sentence"], sentence) # check that the message has been recorded in log file with open(os.path.join(self.test_logdir, 'chat', '%s.log' % strftime('%Y-%m-%d'))) as f: lines = f.readlines() self.assertEquals(len(lines), 1) self.assertIn(sentence, lines[0]) self.assertIn('player_%d' % player_id, lines[0]) @defer.inlineCallbacks def test02_check_added_message_after_now(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 sentence = "This is my sentence!" now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later state, players_id_list = yield chat_instance.state({"modified": [now + 1]}) self.assertTrue(state.has_key('messages')) self.assertEquals(len(state['messages']), 0) self.assertEquals(players_id_list, []) @defer.inlineCallbacks def test03_check_added_message_before_now(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 sentence = "This is my sentence!" now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later state, players_id_list = yield chat_instance.state({"modified": [now - 1]}) self.assertEquals(len(state['messages']), 1) self.assertEquals(state['messages'][0]['player_id'], player_id) self.assertEquals(state['messages'][0]['sentence'], sentence) self.assertEquals(players_id_list, [player_id]) @defer.inlineCallbacks def test04_check_multiple_messages(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_ids = [200, 220, 999] sentences = ["This is my sentence!", "Yeah another test hello.", "Ping ping poing pong."] when = [] for i in range(3): when.append(int(runtime.seconds() * 1000)) request = Request(action=['message'], player_id=[player_ids[i]], sentence=[sentences[i]]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later # we check right back to one second ago to make sure all recently added messages are caught state, players_id_list = yield chat_instance.state({"modified": [when[-1] - 1000]}) self.assertEquals(len(state['messages']), 3) for i in range(3): self.assertEquals(state['messages'][i]['player_id'], player_ids[i]) self.assertEquals(state['messages'][i]['sentence'], sentences[i]) self.assertEquals(players_id_list, player_ids) @defer.inlineCallbacks def test05_check_half_of_multiple_messages(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_ids = [200, 220, 999] sentences = ["This is my sentence!", "Yeah another test hello.", "Ping ping poing pong."] when = [] for i in range(3): sleep(0.1) when.append(int(runtime.seconds() * 1000)) request = Request(action=['message'], player_id=[player_ids[i]], sentence=[sentences[i]]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure no message is returned if we ask for now or later # we check right back to one second ago to make sure all recently added messages are caught state, players_id_list = yield chat_instance.state({"modified": [when[-1] - 150]}) # this time because of the 100ms delay between messages, and only checking to 150ms ago # we should only get the last two messages self.assertEquals(len(state['messages']), 2) for i in range(2): self.assertEquals(state['messages'][i]['player_id'], player_ids[i + 1]) self.assertEquals(state['messages'][i]['sentence'], sentences[i + 1]) self.assertEquals(players_id_list, player_ids[-2:]) @defer.inlineCallbacks def test06_touch_state(self): player_id = 200 sentence = "This is my sentence!" # new instance of chat plugin to run the test against chat_instance = Plugin(self.service, []) # put the chat instance into the service's pollable_plugins self.service.pollable_plugins.append(chat_instance) # flag to signify whether the callback has run self.called = False # service to poll instance waiting for chat d = self.service.poll({'action': ['poll'], 'player_id': [player_id], 'type': ['chat'], 'modified': [chat_instance.get_modified()]}) # callback which runs once the chat plugin calls touch() def check(event): self.called = True d.addCallback(check) # make sure our flag is false before we run self.assertFalse(self.called) # run the test request request = Request(action=['message'], player_id=[player_id], sentence=[sentence]) result = yield chat_instance.preprocess(True, request) yield d # make sure the flag is now set after we've run the test self.assertTrue(self.called) @defer.inlineCallbacks def test07_notification_messages(self): # new instance of chat plugin to run the test against chat_instance = Plugin(self.service, []) self.count = 0 def build_message(self, message): """ message == {'type': 'notification', 'game_id': GAME_ID, 'player_id': 'OWNER_ID', 'sentence': 'SENTENCE'} """ self.count += 1 self.assertEquals(self.count, 1) self.assertEquals(message['type'], 'notification') self.assertEquals(message['player_id'], '15') self.assertEquals(message['sentence'], 'SENTENCE') # build_message should only be called once, upon game creation. chat_instance.build_message = build_message # run a game to get into a realistic situation yield self.complete_game() @defer.inlineCallbacks def test08_nonascii_characters_message(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 200 # The sentence is a 'str' object. Create it by encoding a unicode string. unicode_sentence = u"你好 Matjaž Gregorič" sentence_bytes = unicode_sentence.encode('utf-8') request = Request(action=['message'], player_id=[player_id], sentence=[sentence_bytes]) # run the request result = yield chat_instance.preprocess(True, request) # check that the message has been recorded in log file with open(os.path.join(self.test_logdir, 'chat', '%s.log' % strftime('%Y-%m-%d'))) as f: lines = f.readlines() self.assertIn(unicode_sentence, lines[0].decode('utf-8')) @defer.inlineCallbacks def test09_nonascii_characters_notification(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request class FakeGame: id = 102 owner_id = 303 unicode_sentence = u"我不明白 šal čez želodec" changes = {'type': 'change', 'details': {'type': 'load', 'sentence': unicode_sentence}, 'game': FakeGame()} result = yield chat_instance.self_notify(changes) with open(os.path.join(self.test_logdir, 'chat', '%s.log' % strftime('%Y-%m-%d'))) as f: lines = f.readlines() self.assertIn(unicode_sentence, lines[0].decode('utf-8')) @defer.inlineCallbacks def test10_escape_html(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 201 naughty_sentence = '<script>alert("haha!")</script>' now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[naughty_sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure our naughty message is returned properly escaped state, players_id_list = yield chat_instance.state({"modified": [now - 1]}) self.assertEquals(state['messages'][0]['player_id'], player_id) self.assertEquals(state['messages'][0]['sentence'], '<script>alert("haha!")</script>') @defer.inlineCallbacks def test11_link_url(self): # new instance of the chat plugin to test chat_instance = Plugin(self.service, []) # create a message event request player_id = 201 url_sentence = 'For searching the web I use google.com, it\'s great!' now = int(runtime.seconds() * 1000) request = Request(action=['message'], player_id=[player_id], sentence=[url_sentence]) # run the request result = yield chat_instance.preprocess(True, request) # check to make sure our message is returned with a link for the url state, players_id_list = yield chat_instance.state({"modified": [now - 1]}) self.assertEquals(state['messages'][0]['player_id'], player_id) self.assertEquals(state['messages'][0]['sentence'], 'For searching the web I use <a target="_blank" href="http://google.com">google.com</a>, it\'s great!')
class MailTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database, 'plugins-libdir': '../fixture', 'plugins-confdir': '../fixture', 'plugins-dir': '../fixture'}) self.service.startService() def tearDown(self): return self.service.stopService() @defer.inlineCallbacks def complete_game(self): self.owner_id = 1 self.player1 = 2 self.player2 = 3 self.owner_email = '*****@*****.**' self.player1_email = '*****@*****.**' self.player2_email = '*****@*****.**' self.winner_card = winner_card = 5 sentence = 'SENTENCE' game = yield self.service.create({'owner_id': [self.owner_id]}) self.game_id = game['game_id'] yield self.service.set_card({ 'action': ['set_card'], 'card': [winner_card], 'game_id': [self.game_id], 'player_id': [self.owner_id] }) yield self.service.set_sentence({ 'action': ['set_sentence'], 'sentence': [sentence], 'game_id': [self.game_id], 'player_id': [self.owner_id] }) yield self.service.invite({ 'action': ['invite'], 'game_id': [self.game_id], 'invited_email': [self.player1_email], 'owner_id': [self.owner_id] }) for player_id in (self.player1, self.player2): yield self.service.participate({ 'action': ['participate'], 'player_id': [player_id], 'game_id': [self.game_id] }) player = yield self.service.player2game({ 'action': ['player2game'], 'player_id': [player_id], 'game_id': [self.game_id] }) card = player['cards'][0] yield self.service.pick({ 'action': ['pick'], 'player_id': [player_id], 'game_id': [self.game_id], 'card': [card] }) yield self.service.voting({ 'action': ['voting'], 'game_id': [self.game_id], 'owner_id': [self.owner_id] }) winner_id = self.player1 yield self.service.vote({ 'action': ['vote'], 'game_id': [self.game_id], 'player_id': [winner_id], 'card': [winner_card] }) loser_id = self.player2 yield self.service.vote({ 'action': ['vote'], 'game_id': [self.game_id], 'player_id': [loser_id], 'card': [120] }) self.assertTrue(self.service.games.has_key(self.game_id)) yield self.service.complete({ 'action': ['complete'], 'game_id': [self.game_id], 'owner_id': [self.owner_id] }) self.assertFalse(self.service.games.has_key(self.game_id)) defer.returnValue(True) def test00_init(self): plugin = mail.Plugin(self.service, [ ]) self.assertEquals(plugin.name(), 'mail') self.assertEquals(plugin.host, 'localhost') for allowed in mail.Plugin.ALLOWED: self.assertTrue(plugin.templates.has_key(allowed)) @defer.inlineCallbacks def test01_invite(self): plugin = mail.Plugin(self.service, [ ]) def get_player_email(player_id): if player_id == self.player1: email = self.player1_email elif player_id == self.player2: email = self.player2_email elif player_id == self.owner_id: email = self.owner_email return defer.succeed(email) self.service.auth.get_player_email = get_player_email def get_player_id(email, create=False): return defer.succeed(self.player1) self.service.auth.get_player_id = get_player_id self.count = 0 def sendmail(host, sender, recipients, email): self.count += 1 self.assertSubstring('game_id=%d' % self.game_id, email) self.assertSubstring('url=URL', email) self.assertSubstring('static_url=STATIC_URL', email) if self.count == 1: self.assertSubstring('_INVITE_', email) self.assertSubstring('owner_email=%s' % self.owner_name, email) elif self.count in (2, 3) : self.assertSubstring('_PICK_', email) if self.count == 2: self.assertSubstring('player_email=%s' % self.player1_name, email) elif self.count == 3: self.assertSubstring('player_email=%s' % self.player2_name, email) elif self.count in (4, 5) : self.assertSubstring('_VOTE_', email) if self.count == 4: self.assertSubstring('player_email=%s' % self.player1_name, email) elif self.count == 5: self.assertSubstring('player_email=%s' % self.player2_name, email) elif self.count == 6: self.assertSubstring('_VOTING_', email) elif self.count == 7: self.assertSubstring('_COMPLETE_', email) self.assertSubstring('owner_email=%s' % self.owner_name, email) return defer.succeed(True) plugin.sendmail = sendmail yield self.complete_game() self.assertEqual(self.count, 7) @defer.inlineCallbacks def test02_send_nothing(self): self.service.auth.get_players_emails = Mock(return_value=['not_an_email']) plugin = mail.Plugin(self.service, [ ]) d = plugin.send('SUBJECT', [ 1 ], 'TEMPLATE', {}) def check(result): self.assertFalse(result) d.addCallback(check) yield d
class LoopTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database}) self.service.startService() self.db = sqlite3.connect(self.database) # Fake out the django table in our test db. c = self.db.cursor() c.execute( "CREATE TABLE auth_user ( " " id INTEGER PRIMARY KEY, " " username VARCHAR(255), " " first_name VARCHAR(255) " "); ") c.close() def tearDown(self): self.db.close() os.unlink(self.database) return self.service.stopService() def test01_loop(self): player1 = 1 player2 = 2 player3 = 88 game1 = 111 game2 = 122 game3 = 133 now = datetime.now() yesterday = now - timedelta(days=1) two_days_ago = now - timedelta(days=2) three_days_ago = now - timedelta(days=3) sec = timedelta(seconds=1) c = self.db.cursor() # Prepopulate the tables with fixture data. # ------------------------------------------------------------ # 1. auth_user auth_user_fixtures = [ (player1, '*****@*****.**', 'John Johnson'), (player2, '*****@*****.**', 'Bill Billson'), (player3, '*****@*****.**', None) ] for player in auth_user_fixtures: c.execute('INSERT INTO auth_user (id, username, first_name) VALUES (?, ?, ?)', player) # 2. games games_fixtures = [ (game1, player1, 'Sentence 1', 'invitation', three_days_ago), (game2, player1, 'Sentence 2', 'complete', three_days_ago), (game3, player2, 'Sentence 3', 'invitation', now) ] for game in games_fixtures: c.execute('INSERT INTO games (id, owner_id, sentence, state, created) VALUES (?, ?, ?, ?, ?)', game) # 3. player2game player2game_fixtures =[ (player1, game1), (player1, game2), (player2, game1), (player2, game2), (player2, game3), (player3, game2) ] for player_id, game_id in player2game_fixtures: c.execute('insert into player2game (player_id, game_id) values (?, ?)', [player_id, game_id]) # 4. event_logs event_logs_fixtures = [ # Game 1 [game1, two_days_ago, event_log.GAME_CREATED, player1, ''], [game1, two_days_ago, event_log.OWNER_CHOSE_CARD, player1, 22], [game1, two_days_ago, event_log.OWNER_WROTE_STORY, player1, 'Sentence 1'], [game1, yesterday, event_log.PLAYER_JOINED, player2, ''], [game1, yesterday, event_log.PLAYER_VOTED, player2, 33], # Game 2 [game2, two_days_ago, event_log.GAME_CREATED, player1, ''], [game2, two_days_ago, event_log.OWNER_CHOSE_CARD, player1, 34], [game2, two_days_ago, event_log.OWNER_WROTE_STORY, player1, 'Sentence 2'], [game2, two_days_ago, event_log.PLAYER_INVITED, player1, player3], [game2, two_days_ago, event_log.PLAYER_JOINED, player3, ''], [game2, two_days_ago, event_log.PLAYER_PICKED_CARD, player3, 23], [game2, two_days_ago, event_log.PLAYER_JOINED, player2, ''], [game2, two_days_ago, event_log.PLAYER_PICKED_CARD, player2, 24], [game2, two_days_ago, event_log.GAME_MOVED_TO_VOTING, player1, ''], [game2, two_days_ago, event_log.PLAYER_VOTED, player2, 44], [game2, two_days_ago, event_log.PLAYER_VOTED, player3, 45], [game2, two_days_ago, event_log.GAME_COMPLETED, player1, ''], # Game 3 [game3, now, event_log.GAME_CREATED, player2, ''], [game3, now, event_log.OWNER_CHOSE_CARD, player2, 34], [game3, now, event_log.OWNER_WROTE_STORY, player2, 'Sentence 3'] ] for event in event_logs_fixtures: c.execute('INSERT INTO event_logs (game_id, timestamp, event_type, player_id, data) VALUES (?, ?, ?, ?, ?)', event) # ------------------------------------------------------------ self.db.commit() c.close() # Mock out send.send_mail to collect arguments it's been called with. calls = [] def mock_send_mail(email, name, context): calls.append([email, name, context]) send.send_mail = mock_send_mail count = loop.loop(self.database, self.database) # Should send out three emails (for each of the three players in the db). self.assertEquals(count, 3) # Let's see what send_mail has been called with. self.assertEquals(len(calls), 3) # For player1: self.assertEquals(calls[0][0], '*****@*****.**') self.assertEquals(calls[0][1], 'John Johnson') # No completed games: self.assertEquals(len(calls[0][2]['completed_games']), 0) # One available game (game3 by player2): self.assertEquals(len(calls[0][2]['available_games']), 1) game = calls[0][2]['available_games'][0] self.assertEquals(game['game_id'], game3) self.assertEquals(game['owner_name'], 'Bill Billson') self.assertEquals(game['sentence'], 'Sentence 3') # Player1 was last active two_days ago. # Since then (yesterday), two events happened on one of his games (game1). self.assertEquals(len(calls[0][2]['game_activities']), 1) activity = calls[0][2]['game_activities'][0] self.assertEquals(activity['game_id'], game1) self.assertEquals(activity['state'], 'invitation') self.assertEquals(activity['owner_name'], 'You') self.assertEquals(activity['sentence'], 'Sentence 1') self.assertEquals(len(activity['events']), 2) self.assertEquals(activity['events'][0], 'Bill Billson joined the game') self.assertEquals(activity['events'][1], 'Bill Billson voted') # For player2: self.assertEquals(calls[1][0], '*****@*****.**') self.assertEquals(calls[1][1], 'Bill Billson') # Player2 has last been active 'now', not much has happened since 'now', obviously. # No completed games: self.assertEquals(len(calls[1][2]['completed_games']), 0) # No available games: self.assertEquals(len(calls[1][2]['available_games']), 0) # No game acitvities: self.assertEquals(len(calls[1][2]['game_activities']), 0) # For player3: self.assertEquals(calls[2][0], '*****@*****.**') self.assertEquals(calls[2][1], 'bigjoe99') # No completed games: self.assertEquals(len(calls[2][2]['completed_games']), 0) # One available game (game3 by player2): self.assertEquals(len(calls[2][2]['available_games']), 1) self.assertEquals(game['game_id'], game3) self.assertEquals(game['owner_name'], 'Bill Billson') self.assertEquals(game['sentence'], 'Sentence 3') # No game acitvities - player3 has less been active two days ago, but he has only # participated in game2 which hasn't seen any activity since then: self.assertEquals(len(calls[2][2]['game_activities']), 0)
class BotTest(unittest.TestCase): # initialise our test with a service that we can use during testing and a testing database def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({ 'db': self.database, 'plugins-confdir': '../fixture', 'plugins-libdir': 'LIBDIR', 'static': 'STATIC' }) self.service.auth = Mock() self.service.startService() def tearDown(self): # kill the service we started before the test return self.service.stopService() @defer.inlineCallbacks def game_create(self): """Creates the game, sets the card, and sets the sentence in one step.""" self.winner_card = winner_card = 5 sentence = 'SENTENCE' self.owner_id = 15 result = yield self.service.create({'owner_id': [self.owner_id]}) game_id = result['game_id'] yield self.service.set_card({ 'action': ['set_card'], 'card': [winner_card], 'player_id': [self.owner_id], 'game_id': [game_id] }) yield self.service.set_sentence({ 'action': ['set_sentence'], 'sentence': [sentence], 'player_id': [self.owner_id], 'game_id': [game_id] }) defer.returnValue(result) @defer.inlineCallbacks def game_to_vote(self, game_id): yield self.service.voting({ 'action': ['voting'], 'game_id': [game_id], 'owner_id': [self.owner_id] }) self.assertTrue(self.service.games.has_key(game_id)) defer.returnValue(True) @defer.inlineCallbacks def game_to_complete(self, game_id): yield self.service.complete({ 'action': ['complete'], 'game_id': [game_id], 'owner_id': [self.owner_id] }) self.assertFalse(self.service.games.has_key(game_id)) defer.returnValue(True) @defer.inlineCallbacks def test01_play_game(self): mock_reactor = bot.reactor = Mock() # Don't delay calls bot_plugin = bot.Plugin(self.service, []) self.assertEquals(bot_plugin.name(), 'bot') bots = [bot_plugin.bots[0], bot_plugin.bots[1], bot_plugin.bots[2]] self.assertEqual(bots[0].player_id, 2) self.assertEqual(bots[1].player_id, 3) self.assertEqual(bots[2].player_id, 4) # New game game = yield self.game_create() game_id = game['game_id'] mock_reactor.callLater.assert_called_once_with( 1, bot_plugin.check_need_player, game_id) mock_reactor.reset_mock() # Only the author in the game game, players_ids = yield bots[0].get_game_by_id(game_id) self.assertEqual(len(game['players']), 1) # Bots don't join by default yield bot_plugin.check_need_player(game_id) self.assertEqual(len(mock_reactor.callLater.call_args_list), 0) # Enable joining request = Request(action=['bot'], enable_join=['true'], game_id=[str(game_id)]) result = yield bot_plugin.preprocess(True, request) self.assertFalse(request.args.has_key('action')) self.assertTrue(bot_plugin.enable_join[game_id]) mock_reactor.reset_mock() # Bots join after enabling it for i in xrange(2): yield bot_plugin.check_need_player(game_id) self.assertEqual(len(mock_reactor.callLater.call_args_list), 2) mock_reactor.reset_mock() game, player_ids = yield bots[i].get_game_by_id(game_id) self.assertEqual(game['players'][i + 1]['id'], bots[i].player_id) self.assertEqual(game['players'][i + 1]['picked'], None) # Bots pick a card for i in xrange(2): yield bots[i].pick(game_id) self.assertFalse(mock_reactor.called) game, player_ids = yield bots[i].get_game_by_id( game_id, player_id=bots[i].player_id) self.assertIsInstance(game['players'][i + 1]['picked'], int) self.assertEqual(game['players'][i + 1]['vote'], None) # Go to vote phase yield self.game_to_vote(game_id) self.assertEqual(mock_reactor.callLater.call_args_list, [((3, bots[0].vote, game_id), {}), ((3, bots[1].vote, game_id), {})]) mock_reactor.reset_mock() # A bot should never join or pick at this stage joined = yield bots[2].join(game_id) self.assertFalse(joined) picked = yield bots[2].pick(game_id) self.assertFalse(picked) # Bots vote for i in xrange(2): yield bots[i].vote(game_id) self.assertFalse(mock_reactor.called) game, player_ids = yield bots[i].get_game_by_id( game_id, player_id=bots[i].player_id) self.assertIsInstance(game['players'][i + 1]['picked'], int) self.assertEqual(game['players'][i + 1]['vote'], '') # A bot should never vote at this stage joined = yield bots[2].vote(game_id) self.assertFalse(joined) def test02_brain_not_implemented(self): brain = bot.Brain(None) self.assertRaises(NotImplementedError, brain.get_all_cards_scores_for_sentence, "Test") def test03_brain_weighted_card_choice(self): brain = bot.Brain(None) ranked_cards = [(1, 1), (2, 10000), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0)] chosen_card = brain.weighted_card_choice(ranked_cards) self.assertTrue(chosen_card == 1 or chosen_card == 2) @defer.inlineCallbacks def test04_nlwordmatcherbrain(self): bot_plugin = bot.Plugin(self.service, []) brain = bot.NLWordMatcherBrain(bot_plugin) # Make sure we can record scores for cards that are earned (card # > NCARDS) max_cards = 42 assert CardstoriesGame.NCARDS < max_cards <= CardstoriesGame.NCARDS_EARNED ranked_cards = yield brain.sort_cards_by_ranking_for_sentence( "word", [1, 2, 3, 42]) self.assertEquals(ranked_cards, [(3, 4), (2, 3), (1, 2), (max_cards, 1)])
class ExampleTest(unittest.TestCase): def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database, 'plugins-confdir': 'CONFDIR', 'plugins-libdir': 'LIBDIR', 'static': 'STATIC' }) @defer.inlineCallbacks def complete_game(self, send): self.winner_card = winner_card = 5 self.player1 = 1001 self.player2 = 1002 self.owner_id = 1003 self.sentence = sentence = 'SENTENCE' game = yield send('create', {'owner_id': [self.owner_id]}) self.game_id = game['game_id'] yield send('set_card', { 'action': ['set_card'], 'card': [winner_card], 'player_id': [self.owner_id], 'game_id': [self.game_id] }) yield send('set_sentence', { 'action': ['set_sentence'], 'sentence': [sentence], 'player_id': [self.owner_id], 'game_id': [self.game_id] }) yield send('invite', { 'action': ['invite'], 'game_id': [self.game_id], 'player_id': [self.player1], 'owner_id': [self.owner_id] }) for player_id in (self.player1, self.player2): yield send('participate', { 'action': ['participate'], 'player_id': [player_id], 'game_id': [self.game_id] }) player = yield self.service.player2game({ 'action': ['player2game'], 'player_id': [player_id], 'game_id': [self.game_id] }) card = player['cards'][0] yield send('pick', { 'action': ['pick'], 'player_id': [player_id], 'game_id': [self.game_id], 'card': [card] }) yield send('voting', { 'action': ['voting'], 'game_id': [self.game_id], 'owner_id': [self.owner_id] }) winner_id = self.player1 yield send('vote', { 'action': ['vote'], 'game_id': [self.game_id], 'player_id': [winner_id], 'card': [winner_card] }) loser_id = self.player2 yield send('vote', { 'action': ['vote'], 'game_id': [self.game_id], 'player_id': [loser_id], 'card': [120] }) self.assertTrue(self.service.games.has_key(self.game_id)) yield send('complete', { 'action': ['complete'], 'game_id': [self.game_id], 'owner_id': [self.owner_id] }) self.assertFalse(self.service.games.has_key(self.game_id)) defer.returnValue(True) def test00_init(self): plugin = example.Plugin(self.service, [ AnotherPlugin() ]) self.assertEqual(plugin.service, self.service) self.assertSubstring('example', plugin.confdir) self.assertSubstring('example', plugin.libdir) @defer.inlineCallbacks def test01_accept(self): plugin = example.Plugin(self.service, [ AnotherPlugin() ]) self.events = [] def accept(event): self.service.listen().addCallback(accept) self.events.append(plugin.event) return defer.succeed(True) self.service.listen().addCallback(accept) self.service.startService() yield self.complete_game(lambda action, args: getattr(self.service, action)(args)) yield self.service.stopService() self.assertEqual(self.events, ['START', 'CHANGE create', 'CHANGE set_card', 'CHANGE set_sentence', 'CHANGE invite', 'CHANGE participate', 'CHANGE pick', 'CHANGE participate', 'CHANGE pick', 'CHANGE voting', 'CHANGE vote', 'CHANGE vote', 'CHANGE complete', 'DELETE', 'STOP']) # Test for the load event. self.service.startService() yield self.service.create({'owner_id': [2]}) yield self.service.stopService() self.events = [] self.service.startService() yield self.service.stopService() self.assertTrue('CHANGE load' in self.events) def test02_transparent_transform(self): self.site = CardstoriesSite(CardstoriesTree(self.service), { 'plugins-pre-process': 'example', 'plugins-post-process': 'example' }, [ example.Plugin(self.service, [ AnotherPlugin() ]) ]) r = server.Request(Channel(self.site), True) r.site = r.channel.site input = '' r.gotLength(len(input)) r.handleContentChunk(input) r.queued = 0 d = r.notifyFinish() def finish(result): self.assertSubstring('\r\n\r\n{"arg1": ["val10X", "val11X"], "arg2": ["val20X"], "MORE": "YES", "echo": ["yesX"]}', r.transport.getvalue()) d.addCallback(finish) r.requestReceived('GET', '/resource?action=echo&echo=yes&arg1=val10&arg1=val11&arg2=val20', '') return d @defer.inlineCallbacks def test03_pipeline(self): plugin = example.Plugin(self.service, [ AnotherPlugin() ]) resource = CardstoriesResource(self.service) self.site = CardstoriesSite(CardstoriesTree(self.service), { 'plugins-pre-process': 'example', 'plugins-post-process': 'example' }, [ plugin ]) self.collected = [] def collect(result): self.collected.append([ plugin.preprocessed, plugin.postprocessed ]) return result def send(action, args): args['action'] = [action]; request = server.Request(Channel(self.site), True) request.site = self.site request.args = args request.method = 'GET' d = resource.wrap_http(request) d.addCallback(collect) return d self.service.startService() yield self.complete_game(send) yield self.service.stopService() count = 0 self.assertEquals(self.collected[count], [{'action': ['create'], 'owner_id': [self.owner_id]}, {'game_id': self.game_id}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['set_card'], 'card': [self.winner_card], 'player_id': [self.owner_id], 'game_id': [self.game_id]}, {'type': 'set_card', 'card': self.winner_card, 'player_id': self.owner_id, 'game_id': [self.game_id]}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['set_sentence'], 'sentence': [self.sentence], 'player_id': [self.owner_id], 'game_id': [self.game_id]}, {'type': 'set_sentence', 'sentence': self.sentence, 'game_id': [self.game_id]}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['invite'], 'game_id': [self.game_id], 'owner_id': [self.owner_id], 'player_id': [self.player1]}, {'game_id': [self.game_id], 'invited': [self.player1], 'type': 'invite'}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['participate'], 'game_id': [self.game_id], 'player_id': [self.player1]}, {'game_id': [self.game_id], 'player_id': self.player1, 'type': 'participate'}]); count += 1 del self.collected[count][1]['modified'] player1_card = self.collected[count][0]['card'][0] self.assertEquals(self.collected[count], [{'action': ['pick'], 'card': [player1_card], 'game_id': [self.game_id], 'player_id': [self.player1]}, {'card': player1_card, 'game_id': [self.game_id], 'player_id': self.player1, 'type': 'pick'}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['participate'], 'game_id': [self.game_id], 'player_id': [self.player2]}, {'game_id': [self.game_id], 'player_id': self.player2, 'type': 'participate'}]); count += 1 del self.collected[count][1]['modified'] player2_card = self.collected[count][0]['card'][0] self.assertEquals(self.collected[count], [{'action': ['pick'], 'card': [player2_card], 'game_id': [self.game_id], 'player_id': [self.player2]}, {'card': player2_card, 'game_id': [self.game_id], 'player_id': self.player2, 'type': 'pick'}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['voting'], 'game_id': [self.game_id], 'owner_id': [self.owner_id]}, {'game_id': [self.game_id], 'type': 'voting'}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['vote'], 'card': [self.winner_card], 'game_id': [self.game_id], 'player_id': [self.player1]}, {'game_id': [self.game_id], 'player_id': self.player1, 'type': 'vote', 'vote': self.winner_card}]); count += 1 del self.collected[count][1]['modified'] looser_card = self.collected[count][0]['card'][0] self.assertEquals(self.collected[count], [{'action': ['vote'], 'card': [looser_card], 'game_id': [self.game_id], 'player_id': [self.player2]}, {'game_id': [self.game_id], 'player_id': self.player2, 'type': 'vote', 'vote': looser_card}]); count += 1 del self.collected[count][1]['modified'] self.assertEquals(self.collected[count], [{'action': ['complete'], 'game_id': [self.game_id], 'owner_id': [self.owner_id]}, {'game_id': [self.game_id], 'type': 'complete'}]); count += 1 self.assertEqual(len(self.collected), count) def test04_poll(self): plugin = example.Plugin(self.service, [ AnotherPlugin() ]) d = plugin.poll({'modified': [plugin.get_modified()]}) @defer.inlineCallbacks def check(result): plugin.ok = True self.assertEquals(plugin.counter, 1) self.assertTrue(result['info']) state, players_list = yield plugin.state({'modified': [0]}) self.assertEquals(plugin.counter, state['counter']) defer.returnValue(result) d.addCallback(check) plugin.count() self.assertEquals(plugin.counter, 0) return d
class BotTest(unittest.TestCase): # initialise our test with a service that we can use during testing and a testing database def setUp(self): self.database = 'test.sqlite' if os.path.exists(self.database): os.unlink(self.database) self.service = CardstoriesService({'db': self.database, 'plugins-confdir': '../fixture', 'plugins-libdir': 'LIBDIR', 'static': 'STATIC' }) self.service.auth = Mock() self.service.startService() def tearDown(self): # kill the service we started before the test return self.service.stopService() @defer.inlineCallbacks def game_create(self): """Creates the game, sets the card, and sets the sentence in one step.""" self.winner_card = winner_card = 5 sentence = 'SENTENCE' self.owner_id = 15 result = yield self.service.create({'owner_id': [self.owner_id]}) game_id = result['game_id'] yield self.service.set_card({'action': ['set_card'], 'card': [winner_card], 'player_id': [self.owner_id], 'game_id': [game_id]}) yield self.service.set_sentence({'action': ['set_sentence'], 'sentence': [sentence], 'player_id': [self.owner_id], 'game_id': [game_id]}) defer.returnValue(result) @defer.inlineCallbacks def game_to_vote(self, game_id): yield self.service.voting({ 'action': ['voting'], 'game_id': [game_id], 'owner_id': [self.owner_id] }) self.assertTrue(self.service.games.has_key(game_id)) defer.returnValue(True) @defer.inlineCallbacks def game_to_complete(self, game_id): yield self.service.complete({ 'action': ['complete'], 'game_id': [game_id], 'owner_id': [self.owner_id] }) self.assertFalse(self.service.games.has_key(game_id)) defer.returnValue(True) @defer.inlineCallbacks def test01_play_game(self): mock_reactor = bot.reactor = Mock() # Don't delay calls bot_plugin = bot.Plugin(self.service, []) self.assertEquals(bot_plugin.name(), 'bot') bots = [bot_plugin.bots[0], bot_plugin.bots[1], bot_plugin.bots[2]] self.assertEqual(bots[0].player_id, 2) self.assertEqual(bots[1].player_id, 3) self.assertEqual(bots[2].player_id, 4) # New game game = yield self.game_create() game_id = game['game_id'] mock_reactor.callLater.assert_called_once_with(1, bot_plugin.check_need_player, game_id) mock_reactor.reset_mock() # Only the author in the game game, players_ids = yield bots[0].get_game_by_id(game_id) self.assertEqual(len(game['players']), 1) # Bots don't join by default yield bot_plugin.check_need_player(game_id) self.assertEqual(len(mock_reactor.callLater.call_args_list), 0) # Enable joining request = Request(action=['bot'], enable_join=['true'], game_id=[str(game_id)]) result = yield bot_plugin.preprocess(True, request) self.assertFalse(request.args.has_key('action')) self.assertTrue(bot_plugin.enable_join[game_id]) mock_reactor.reset_mock() # Bots join after enabling it for i in xrange(2): yield bot_plugin.check_need_player(game_id) self.assertEqual(len(mock_reactor.callLater.call_args_list), 2) mock_reactor.reset_mock() game, player_ids = yield bots[i].get_game_by_id(game_id) self.assertEqual(game['players'][i + 1]['id'], bots[i].player_id) self.assertEqual(game['players'][i + 1]['picked'], None) # Bots pick a card for i in xrange(2): yield bots[i].pick(game_id) self.assertFalse(mock_reactor.called) game, player_ids = yield bots[i].get_game_by_id(game_id, player_id=bots[i].player_id) self.assertIsInstance(game['players'][i + 1]['picked'], int) self.assertEqual(game['players'][i + 1]['vote'], None) # Go to vote phase yield self.game_to_vote(game_id) self.assertEqual(mock_reactor.callLater.call_args_list, [((3, bots[0].vote, game_id), {}), ((3, bots[1].vote, game_id), {})]) mock_reactor.reset_mock() # A bot should never join or pick at this stage joined = yield bots[2].join(game_id) self.assertFalse(joined) picked = yield bots[2].pick(game_id) self.assertFalse(picked) # Bots vote for i in xrange(2): yield bots[i].vote(game_id) self.assertFalse(mock_reactor.called) game, player_ids = yield bots[i].get_game_by_id(game_id, player_id=bots[i].player_id) self.assertIsInstance(game['players'][i + 1]['picked'], int) self.assertEqual(game['players'][i + 1]['vote'], '') # A bot should never vote at this stage joined = yield bots[2].vote(game_id) self.assertFalse(joined) def test02_brain_not_implemented(self): brain = bot.Brain(None) self.assertRaises(NotImplementedError, brain.get_all_cards_scores_for_sentence, "Test") def test03_brain_weighted_card_choice(self): brain = bot.Brain(None) ranked_cards = [(1, 1), (2, 10000), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0)] chosen_card = brain.weighted_card_choice(ranked_cards) self.assertTrue(chosen_card == 1 or chosen_card == 2) @defer.inlineCallbacks def test04_nlwordmatcherbrain(self): bot_plugin = bot.Plugin(self.service, []) brain = bot.NLWordMatcherBrain(bot_plugin) # Make sure we can record scores for cards that are earned (card # > NCARDS) max_cards = 42 assert CardstoriesGame.NCARDS < max_cards <= CardstoriesGame.NCARDS_EARNED ranked_cards = yield brain.sort_cards_by_ranking_for_sentence("word", [1, 2, 3, 42]) self.assertEquals(ranked_cards, [(3, 4), (2, 3), (1, 2), (max_cards, 1)])