def test_MessageDownloadJob_with_crypto_error(mocker, homedir, session, session_maker): """ Test when a message successfully downloads, but does not successfully decrypt. Use the `homedir` fixture to get a GPG keyring. """ message = factory.Message(source=factory.Source(), is_downloaded=False, is_decrypted=None, content=None) session.add(message) session.commit() gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MessageDownloadJob(message.uuid, homedir, gpg) mocker.patch.object(job.gpg, 'decrypt_submission_or_reply', side_effect=CryptoError) api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() path = os.path.join(homedir, 'data') api_client.download_submission = mocker.MagicMock(return_value=('', path)) with pytest.raises(DownloadDecryptionException): job.call_api(api_client, session) assert message.content is None assert message.is_downloaded is True assert message.is_decrypted is False
def test_MessageDownloadJob_happiest_path(mocker, homedir, session, session_maker): """ Test when a message successfully downloads and decrypts. Use the `homedir` fixture to get a GPG keyring. """ message = factory.Message(source=factory.Source(), is_downloaded=False, is_decrypted=None, content=None) session.add(message) session.commit() gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MessageDownloadJob(message.uuid, homedir, gpg) mocker.patch.object(job.gpg, 'decrypt_submission_or_reply') api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() data_dir = os.path.join(homedir, 'data') api_client.download_submission = mocker.MagicMock(return_value=('', data_dir)) job.call_api(api_client, session) assert message.content is not None assert message.is_downloaded is True assert message.is_decrypted is True
def test_MessageDownloadJob_with_base_error(mocker, homedir, session, session_maker): """ Test when a message does not successfully download. """ message = factory.Message(source=factory.Source(), is_downloaded=False, is_decrypted=None, content=None) session.add(message) session.commit() gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MessageDownloadJob(message.uuid, homedir, gpg) api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() mocker.patch.object(api_client, 'download_submission', side_effect=BaseError) decrypt_fn = mocker.patch.object(job.gpg, 'decrypt_submission_or_reply') with pytest.raises(BaseError): job.call_api(api_client, session) assert message.content is None assert message.is_downloaded is False assert message.is_decrypted is None decrypt_fn.assert_not_called()
def test_MessageDownloadJob_no_download_or_decrypt(mocker, homedir, session, session_maker): """ Test that an already-downloaded message successfully decrypts. Use the `homedir` fixture to get a GPG keyring. """ message_is_decrypted_false = factory.Message(source=factory.Source(), is_downloaded=True, is_decrypted=False, content=None) message_is_decrypted_none = factory.Message(source=factory.Source(), is_downloaded=True, is_decrypted=None, content=None) session.add(message_is_decrypted_false) session.add(message_is_decrypted_none) session.commit() gpg = GpgHelper(homedir, session_maker, is_qubes=False) job_1 = MessageDownloadJob(message_is_decrypted_false.uuid, homedir, gpg) job_2 = MessageDownloadJob(message_is_decrypted_none.uuid, homedir, gpg) mocker.patch.object(job_1.gpg, 'decrypt_submission_or_reply') mocker.patch.object(job_2.gpg, 'decrypt_submission_or_reply') api_client = mocker.MagicMock() path = os.path.join(homedir, 'data') api_client.download_submission = mocker.MagicMock(return_value=('', path)) job_1.call_api(api_client, session) job_2.call_api(api_client, session) assert message_is_decrypted_false.content is not None assert message_is_decrypted_false.is_downloaded is True assert message_is_decrypted_false.is_decrypted is True assert message_is_decrypted_none.content is not None assert message_is_decrypted_none.is_downloaded is True assert message_is_decrypted_none.is_decrypted is True
def test_RunnableQueue_duplicate_jobs(mocker): """ Verify that duplicate jobs are not added to the queue. """ mock_api_client = mocker.MagicMock() mock_session = mocker.MagicMock() mock_session_maker = mocker.MagicMock(return_value=mock_session) dl_job = FileDownloadJob("mock", "mock", "mock") msg_dl_job = MessageDownloadJob("mock", "mock", "mock") queue = RunnableQueue(mock_api_client, mock_session_maker) debug_logger = mocker.patch("securedrop_client.queue.logger.debug") # Queue begins empty (0 entries). assert len(queue.queue.queue) == 0 queue.add_job(dl_job) assert len(queue.queue.queue) == 1 # Now add the same job again. queue.add_job(dl_job) assert len(queue.queue.queue) == 1 log_msg = "Duplicate job {}, skipping".format(dl_job) debug_logger.call_args[1] == log_msg # Now add a _different_ job with the same arguments (same uuid). queue.add_job(msg_dl_job) assert len(queue.queue.queue) == 2 # Ensure that using _re_add_job in the case of a timeout won't allow duplicate # jobs to be added. with queue.condition_add_or_remove_job: queue._re_add_job(msg_dl_job) assert len(queue.queue.queue) == 2
def _submit_download_job(self, object_type: Union[Type[db.Reply], Type[db.Message], Type[db.File]], uuid: str) -> None: if object_type == db.Reply: job = ReplyDownloadJob( uuid, self.data_dir, self.gpg ) # type: Union[ReplyDownloadJob, MessageDownloadJob, FileDownloadJob] job.success_signal.connect(self.on_reply_download_success, type=Qt.QueuedConnection) job.failure_signal.connect(self.on_reply_download_failure, type=Qt.QueuedConnection) elif object_type == db.Message: job = MessageDownloadJob(uuid, self.data_dir, self.gpg) job.success_signal.connect(self.on_message_download_success, type=Qt.QueuedConnection) job.failure_signal.connect(self.on_message_download_failure, type=Qt.QueuedConnection) elif object_type == db.File: job = FileDownloadJob(uuid, self.data_dir, self.gpg) job.success_signal.connect(self.on_file_download_success, type=Qt.QueuedConnection) job.failure_signal.connect(self.on_file_download_failure, type=Qt.QueuedConnection) self.api_job_queue.enqueue(job)
def test_MessageDownloadJob_message_already_downloaded(mocker, homedir, session, session_maker): """ Test that call_api just decrypts and returns uuid if already downloaded. """ message = factory.Message(source=factory.Source(), is_downloaded=True, is_decrypted=None) session.add(message) session.commit() gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MessageDownloadJob(message.uuid, homedir, gpg) mocker.patch.object(job.gpg, 'decrypt_submission_or_reply') api_client = mocker.MagicMock() download_fn = mocker.patch.object(api_client, 'download_submission') return_uuid = job.call_api(api_client, session) assert message.uuid == return_uuid assert message.is_decrypted is True download_fn.assert_not_called()
def test_MessageDownloadJob_message_already_decrypted(mocker, homedir, session, session_maker, download_error_codes): """ Test that call_api just returns uuid if already decrypted. """ message = factory.Message(source=factory.Source(), is_downloaded=True, is_decrypted=True) session.add(message) session.commit() gpg = GpgHelper(homedir, session_maker, is_qubes=False) job = MessageDownloadJob(message.uuid, homedir, gpg) decrypt_fn = mocker.patch.object(job.gpg, "decrypt_submission_or_reply") api_client = mocker.MagicMock() api_client.default_request_timeout = mocker.MagicMock() download_fn = mocker.patch.object(api_client, "download_submission") return_uuid = job.call_api(api_client, session) assert message.uuid == return_uuid decrypt_fn.assert_not_called() download_fn.assert_not_called()