def test_reuse_quit(self): # if the user replies with QUIT, then we should always return QUIT # for future errors self.run_choice_dialog.return_value = dialogs.BUTTON_QUIT dialog = mock.Mock(title='test 1', description='test 2') # handle a backend error self.run_backend_dialog(dialog) self.assertEquals(self.run_choice_dialog.call_count, 1) self.assertEquals(dialog.run_callback.call_args[0][0], dialogs.BUTTON_QUIT) # for future errors, we should assume the user still wants to quit # try a bunch of frontend errors retry_callback = mock.Mock() self.run_dialog('test 1', 'test 2', retry_callback) self.run_dialog('test 1', 'test 2', retry_callback) self.run_dialog('test 1', 'test 2', retry_callback) self.assertEquals(self.run_choice_dialog.call_count, 1) self.assertEquals(retry_callback.call_count, 0) # try a bunch of backend errors self.run_backend_dialog(dialog) self.run_backend_dialog(dialog) self.run_backend_dialog(dialog) self.assertEquals(self.run_choice_dialog.call_count, 1) self.assertEquals(dialog.run_callback.call_args_list, [((dialogs.BUTTON_QUIT, ), {}), ((dialogs.BUTTON_QUIT, ), {}), ((dialogs.BUTTON_QUIT, ), {}), ((dialogs.BUTTON_QUIT, ), {})])
def test_on_item_changes(self): # Test that calling on_item_changes on the ItemListPool calls it on # all lists inside that pool. self.item_list.on_item_changes = mock.Mock() self.item_list2.on_item_changes = mock.Mock() fake_message = mock.Mock() app.item_tracker_updater.on_item_changes(fake_message) self.item_list.on_item_changes.assert_called_once_with(fake_message) self.item_list2.on_item_changes.assert_called_once_with(fake_message)
def setUp(self): ExtensionTestBase.setUp(self) # Make a Mock object to use as a hook function. Nest inside another # Mock object to test hook parser better global hook_holder hook_holder = mock.Mock() hook_holder.hook_func = mock.Mock() self.mock_hook = hook_holder.hook_func # make our extension self.create_extension()
def test_quit(self): # Check that we call Frontend.quit() self.run_choice_dialog.return_value = dialogs.BUTTON_QUIT dialog = mock.Mock(title='test 1', description='test 2') self.run_backend_dialog(dialog) self.assertEquals(self.frontend.quit.call_count, 1) # another error shouldn't result in 2 quit calls self.run_choice_dialog.return_value = dialogs.BUTTON_QUIT dialog = mock.Mock(title='test 1', description='test 2') self.run_backend_dialog(dialog) self.assertEquals(self.frontend.quit.call_count, 1)
def setUp(self): MiroTestCase.setUp(self) self.mock_item_list_pool = self.patch_for_test( 'miro.app.item_list_pool') self.items = [ mock.Mock(id=0, title='one', is_playable=True), mock.Mock(id=1, title='two', is_playable=True), mock.Mock(id=2, title='three', is_playable=False), mock.Mock(id=3, title='four', is_playable=True), ] self.item_list = MockItemList(self.items)
def make_tracker(self): query = itemtrack.ItemTrackerQuery() query.add_condition('feed_id', '=', self.feed.id) query.set_order_by(['release_date']) item_tracker = itemtrack.ItemTracker(self.idle_scheduler, query, item.ItemSource()) self.list_changed_callback = mock.Mock() self.items_changed_callback = mock.Mock() item_tracker.connect('list-changed', self.list_changed_callback) item_tracker.connect('items-changed', self.items_changed_callback) return item_tracker
def setUp(self): MiroTestCase.setUp(self) self.init_data_package() self.feed = models.Feed(u'http://example.com/feed.rss') self.items = [ testobjects.make_item(self.feed, u'item-%s' % i) for i in xrange(10) ] app.db.finish_transaction() self.item_list = itemlist.ItemList('feed', self.feed.id) self.items_changed_handler = mock.Mock() self.list_changed_handler = mock.Mock() self.item_list.connect("items-changed", self.items_changed_handler) self.item_list.connect("list-changed", self.list_changed_handler)
def test_path_sql_arguments(self): # Check that DeviceItem converts paths to unicode when sending values # to sqlite and does case-insensitive comparisons path = PlatformFilenameType('Foo.mp3') mock_make_view = self.patch_for_test( 'miro.item.DeviceItem.make_view', autospec=False) # test get_by_path item.DeviceItem.get_by_path(path, self.device.db_info) self.assertEquals(mock_make_view.call_count, 1) sql, params = mock_make_view.call_args[0] self.assertEquals(type(params[0]), unicode) if 'LOWER' not in sql: raise AssertionError("this doesn't look like lower case " "comparison: %s " % sql) self.assertEquals(params[0], 'Foo.mp3') self.assertEquals(type(mock_make_view.call_args[0][1][0]), unicode) mock_make_view.reset_mock() # test_items_for_paths mock_make_view.return_value = [mock.Mock(filename='foo.mp3')] item.DeviceItem.items_for_paths([path], self.device.db_info) sql, params = mock_make_view.call_args[0] self.assertEquals(type(params[0]), unicode) if 'LOWER' not in sql: raise AssertionError("this doesn't look like lower case " "comparison: %s " % sql) self.assertEquals(params[0], 'Foo.mp3')
def test_add_image(self): layout = cellpack.Layout() image = mock.Mock() image.get_size.return_value = (20, 50) layout.add_image(image, 100, 100) layout.draw(self.context) image.draw.assert_called_with(self.context, 100, 100, 20, 50)
def force_db_error(self): def execute_that_fails(*args, **kwargs): raise sqlite3.DatabaseError("Test Error") mock_execute = mock.Mock(side_effect=execute_that_fails) return mock.patch('miro.data.connectionpool.Connection.execute', mock_execute)
def test_add_text_line(self): layout = cellpack.Layout() textbox = mock.Mock() textbox.font.line_height.return_value = 30 layout.add_text_line(textbox, 100, 100, 50) layout.draw(self.context) textbox.draw.assert_called_with(self.context, 100, 100, 50, 30)
def test_error_in_retry_callback(self): self.run_choice_dialog.return_value = dialogs.BUTTON_RETRY # the frontend calls run_dialog() when it sees an error mock_retry_callback = mock.Mock() def retry_callback(): # the first time this one is called, we similate another error # happening if mock_retry_callback.call_count == 1: self.db_error_handler.run_dialog('test 1', 'test 2', mock_retry_callback) mock_retry_callback.side_effect = retry_callback self.run_dialog('test 1', 'test 2', mock_retry_callback) # the first run through retry_callback resulted in an error. We # should have a new dialog scheduled to pop up. We shouldn't call # retry_callback() again yet, nor have actually popped up the dialog. self.assertEquals(self.run_choice_dialog.call_count, 1) args = self.check_run_dialog_scheduled('test 1', 'test 2', 'ui thread') self.assertEquals(mock_retry_callback.call_count, 1) # Run the dialog again. The second time through our retry callback # won't have an error self.db_error_handler._run_dialog(*args) self.assertEquals(self.run_choice_dialog.call_count, 2) self.assertEquals(mock_retry_callback.call_count, 2) self.check_run_dialog_not_scheduled()
def setUp(self): MiroTestCase.setUp(self) self.save_path = os.path.join(self.tempdir, 'test-db') # set up an error handler that tells LiveStorage to use temporary # storage if it fails to open a new database use_temp = storedatabase.LiveStorageErrorHandler.ACTION_USE_TEMPORARY self.error_handler = mock.Mock() self.error_handler.handle_open_error.return_value = use_temp self.row_data = [] self.mock_add_timeout = mock.Mock() self.patch_function('miro.eventloop.add_timeout', self.mock_add_timeout) self.real_sqlite3_connect = sqlite3.connect self.patch_function('sqlite3.connect', self.mock_sqlite3_connect)
def setUp(self): ItemTrackTestCase.setUp(self) # setup mock objects to track when the items-changed and list-changed # signals get emitted self.signal_handlers = {} for signal in ("items-changed", "list-changed"): self.signal_handlers[signal] = mock.Mock() self.tracker.connect(signal, self.signal_handlers[signal])
def test_backend_then_frontend_errors(self): retry_callback = mock.Mock() def run_choice_dialog(title, description, buttons): # while inside the choice dialog for the backend, we trigger # another error from the frontend. self.run_dialog('test 1', 'test 2', retry_callback) return dialogs.BUTTON_RETRY self.run_choice_dialog.side_effect = run_choice_dialog dialog = mock.Mock(title='test 1', description='test 2') self.run_backend_dialog(dialog) # even though we saw 2 errors, only 1 dialog should be shown self.assertEquals(self.run_choice_dialog.call_count, 1) # since RETRY was chosen for the dialog, both backend and frontend # should see that self.assertEquals(dialog.run_callback.call_args[0][0], dialogs.BUTTON_RETRY) self.assertEquals(retry_callback.call_count, 1)
def setup_mock_message_handler(self): """Install a mock object to handle frontend messages. We use this to intercept the ItemChanges message """ self.mock_message_handler = mock.Mock() messages.FrontendMessage.install_handler(self.mock_message_handler) # move past the the SharingItemChanges method for our initial items. eventloop._eventloop.emit('event-finished', True) self.mock_message_handler.reset_mock()
def test_client_disconnects_in_get_revision(self): # get_revision() blocks waiting for chainges, but it should return if # the client disconnects. Test that this happens self.setup_sharing_manager_backend() mock_socket = mock.Mock() # We use a threading.Condition object to wait for changes. self.wait_count = 0 def mock_wait(timeout=None): # we must use a timeout since we want to poll the socket self.assertNotEquals(timeout, None) if self.wait_count > 2: raise AssertionError("wait called too many times") self.wait_count += 1 self.backend.data_set.condition.wait = mock_wait # We use select() to check if the socket is closed. self.select_count = 0 def mock_select(rlist, wlist, xlist, timeout=None): self.assertEquals(timeout, 0) self.assertEquals(rlist, [mock_socket]) if self.select_count == 0: # first time around, return nothing rv = [], [], [] elif self.select_count == 1: # second time around, return the socket as available for # reading. This happens when the socket gets closed rv = [mock_socket], [], [] else: raise AssertionError("select called too much") self.select_count += 1 return rv self.patch_function('select.select', mock_select) # calling get_revision() should set all the wheels in motion initial_revision = self.backend.data_set.revision new_revision = self.backend.get_revision(mock.Mock(), initial_revision, mock_socket) # get_revision() should have returned before any changes happened. self.assertEquals(initial_revision, new_revision)
def test_reuse_retry(self): # if we get an error on one thread and the user response with RETRY, # then we should reuse that response if another thread sees an error. self.run_choice_dialog.return_value = dialogs.BUTTON_RETRY dialog = mock.Mock(title='test 1', description='test 2') # handle a backend error self.run_backend_dialog(dialog) self.assertEquals(self.run_choice_dialog.call_count, 1) self.assertEquals(dialog.run_callback.call_args[0][0], dialogs.BUTTON_RETRY) # handle a frontend error, we should reuse the RETRY response retry_callback = mock.Mock() self.run_dialog('test 1', 'test 2', retry_callback) self.assertEquals(self.run_choice_dialog.call_count, 1) self.assertEquals(retry_callback.call_count, 1) # handle another frontend error this time we shouldn't reuse the RETRY # response self.run_dialog('test 1', 'test 2', retry_callback) self.assertEquals(self.run_choice_dialog.call_count, 2) self.assertEquals(retry_callback.call_count, 2)
def test_remove_from_list(self): playlist = playback.PlaybackPlaylist(self.item_list, 0, False, False) mock_handler = mock.Mock() playlist.connect("playing-info-changed", mock_handler) self.check_currently_playing(playlist, 0) # simulate an item getting removed from the list, we should still keep # playing the item removed = self.item_list.items.pop(0) self.item_list.emit('list-changed') self.assertEquals(mock_handler.call_count, 0) self.assertEquals(playlist.currently_playing, removed)
def setUp(self): MiroTestCase.setUp(self) self.renderer = itemrenderer.ItemRenderer() self.feed = models.Feed(u'http://example.com/feed.rss') self.item = testobjects.make_item(self.feed, u'item') self.manual_feed = models.Feed(u'dtv:manualFeed', initiallyAutoDownloadable=False) self.file_item = models.FileItem(self.make_temp_path(), self.manual_feed.id) app.saved_items = set() app.playback_manager = mock.Mock() app.playback_manager.item_resume_policy.return_value = False
def check_render(self, item): """Check that ItemRenderer can sucessfully render a row. NOTE: we don't actually check the correctness of the render, just that it doesn't crash. """ self.renderer.attrs = {} self.renderer.info = self._get_item(item.id) context = mock.Mock() layout_manager = mock.Mock() hotspot = hover = None context.width = self.renderer.MIN_WIDTH context.height = self.renderer.HEIGHT mock_textbox = layout_manager.textbox.return_value mock_textbox.font.line_height.return_value = 16 mock_textbox.get_size.return_value = (100, 16) layout_manager.current_font.line_height.return_value = 16 layout_manager.current_font.ascent.return_value = 12 for selected in (False, True): self.renderer.render(context, layout_manager, selected, hotspot, hover)
def test_backend_error_handling(self): # when the backend sees an error, it should send the # DatabaseErrorDialog to the frontend and the frontend should call # DBErrorHandler.run_backend_dialog(). This test is testing what # happens when run_backend_dialog() is called. self.run_choice_dialog.return_value = dialogs.BUTTON_RETRY dialog = mock.Mock(title='test 1', description='test 2') self.run_backend_dialog(dialog) self.assertEquals(self.run_choice_dialog.call_count, 1) self.assertEquals(dialog.run_callback.call_count, 1) self.assertEquals(dialog.run_callback.call_args, ((dialogs.BUTTON_RETRY, ), {}))
def patch_function(self, function_name, new_function): """Use Mock to replace an existing function for a single test. function_name should be in the form "full.module.name.object". For example "miro.startup.startup" This can also be used on a class object in order to return a different object, if we only use class objects as factory functions. :param function_name: name of the function to patch :param new_function: function object to replace it with """ self.patch_for_test(function_name, mock.Mock(side_effect=new_function))
def setUp(self): EventLoopTest.setUp(self) self.updater = metadataprogress.MetadataProgressUpdater() # make messages send immediately to speed up test execution self.updater.message_interval = 0.0 # setup a fake device to use self.device = mock.Mock() self.device.id = 123 # make our handler self.test_handler = TestFrontendMessageHandler() messages.FrontendMessage.install_handler(self.test_handler) # the warnings from MetadataProgressUpdater should be errors in the # test case self.log_filter.set_exception_level(logging.WARNING)
def test_item_change(self): playlist = playback.PlaybackPlaylist(self.item_list, 0, False, False) mock_handler = mock.Mock() playlist.connect("playing-info-changed", mock_handler) self.check_currently_playing(playlist, 0) # simulate an item changing titles new_item = mock.Mock(id=0, title='New item one', is_playable=True) self.item_list.items[0] = new_item self.item_list.emit('items-changed', set([new_item.id])) self.assertEquals(mock_handler.call_count, 1) self.assertEquals(playlist.currently_playing, new_item) # simulate an item that's not playing changing mock_handler.reset_mock() new_item2 = mock.Mock(id=2, title='New item three', is_playable=True) self.item_list.items[2] = new_item2 self.item_list.emit('items-changed', set([new_item2.id])) self.assertEquals(mock_handler.call_count, 0) # simulate an item changing to not playable new_item3 = mock.Mock(id=0, title='New item one', is_playable=False) self.item_list.items[0] = new_item3 self.item_list.emit('items-changed', set([new_item3.id])) self.assertEquals(mock_handler.call_count, 1) self.assertEquals(playlist.currently_playing, None)
def setUp(self): MiroTestCase.setUp(self) self.idle_scheduler = mock.Mock() self.init_data_package() self.setup_items() self.setup_connection_pool() self.force_wal_mode() self.setup_mock_message_handler() self.setup_tracker() # make the change tracker start fresh for the unittests. Since we # don't know which change tracker our item type will use, we go for # the sledge hammer approach here and reset them all. models.Item.change_tracker.reset() models.DeviceItem.change_tracker.reset() models.SharingItem.change_tracker.reset()
def init_data_package(self): """Initialize the data package The data package is used by the frontend to get data. Note: Since data uses a different connection than the backend system (storedatabase and friends), we need to create an on-disk database. """ self.db_path = self.make_temp_path(".sqlite") if os.path.exists(self.db_path): os.unlink(self.db_path) self.reload_database(FilenameType(self.db_path)) data.init(self.db_path) # use a mock objects for the database error handler app.db_error_handler = mock.Mock()
def patch_for_test(self, object_name, mock_object=None): """Use Mock to replace a function/class/object with a mock object. We will unpatch the object during teardown :param object_name: name of the object to patch :param mock_object: object to patch with, if None we will create a new Mock :returns: object used to patch """ if mock_object is None: mock_object = mock.Mock() patcher = mock.patch(object_name, mock_object) patcher.start() self.mock_patchers.append(patcher) return mock_object
def test_nested_frontend_errors(self): retry_callback = mock.Mock() def run_choice_dialog(title, description, buttons): # simulate several other errors while running the dialog self.run_dialog('test 1', 'test 2', retry_callback) self.run_dialog('test 1', 'test 2', retry_callback) self.run_dialog('test 1', 'test 2', retry_callback) return dialogs.BUTTON_RETRY self.run_choice_dialog.side_effect = run_choice_dialog self.run_dialog('test 1', 'test 2', retry_callback) # even though we saw 4 errors, only 1 dialog should be shown self.assertEquals(self.run_choice_dialog.call_count, 1) # the retry_callback should be called for each run_dialog() call. self.assertEquals(retry_callback.call_count, 4)
def test_frontend_error_handling(self): self.run_choice_dialog.return_value = dialogs.BUTTON_RETRY # the frontend calls run_dialog() when it sees an error retry_callback = mock.Mock() self.run_dialog('test 1', 'test 2', retry_callback) # run_dialog() should pop up a choice dialog self.assertEquals(self.run_choice_dialog.call_count, 1) self.assertEquals( self.run_choice_dialog.call_args[0], ('test 1', 'test 2', [dialogs.BUTTON_RETRY, dialogs.BUTTON_QUIT])) self.assertEquals(self.run_choice_dialog.call_args[1], {}) # since RETRY was chosen, the retry callback should be called self.assertEquals(retry_callback.call_count, 1) # try again with QUIT chosen. In that case, the retry callback # shouldn't be called retry_callback.reset_mock() self.run_choice_dialog.return_value = dialogs.BUTTON_QUIT self.run_dialog('test 1', 'test 2', retry_callback) self.assertEquals(retry_callback.call_count, 0)