def test_Controller_call_api(homedir, config, mocker): """ A new thread and APICallRunner is created / setup. Using the `config` fixture to ensure the config is written to disk. """ mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.finish_api_call = mocker.MagicMock() mocker.patch('securedrop_client.logic.QThread') mocker.patch('securedrop_client.logic.APICallRunner') mocker.patch('securedrop_client.logic.QTimer') mock_api_call = mocker.MagicMock() mock_success_callback = mocker.MagicMock() mock_failure_callback = mocker.MagicMock() co.call_api(mock_api_call, mock_success_callback, mock_failure_callback, 'foo', bar='baz') assert len(co.api_threads) == 1 thread_info = co.api_threads[list(co.api_threads.keys())[0]] thread = thread_info['thread'] runner = thread_info['runner'] thread.started.connect.assert_called_once_with(runner.call_api) thread.start.assert_called_once_with() runner.moveToThread.assert_called_once_with(thread) runner.call_succeeded.connect.call_count == 1 runner.call_failed.connect.call_count == 1 runner.call_timed_out.connect.call_count == 1
def test_Controller_on_file_download_Reply(homedir, config, mocker): """ If the handler is passed a reply, check the download_reply function is the one called against the API. Using the `config` fixture to ensure the config is written to disk. """ mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) source = factory.Source() journalist = db.User('Testy mcTestface') reply = db.Reply(uuid='reply-uuid', journalist=journalist, source=source, filename='1-my-reply.gpg', size=123) # Not a sdclientapi.Submission co.call_api = mocker.MagicMock() co.api = mocker.MagicMock() reply_sdk_object = mocker.MagicMock() mock_reply = mocker.patch('sdclientapi.Reply') mock_reply.return_value = reply_sdk_object co.on_file_download(source, reply) co.call_api.assert_called_once_with(co.api.download_reply, co.on_file_download_success, co.on_file_download_failure, reply_sdk_object, co.data_dir, current_object=reply)
def test_Controller_on_file_download_Submission(homedir, config, mocker): """ If the handler is passed a submission, check the download_submission function is the one called against the API. Using the `config` fixture to ensure the config is written to disk. """ mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.call_api = mocker.MagicMock() co.api = mocker.MagicMock() source = factory.Source() file_ = db.File(source=source, uuid='uuid', size=1234, filename='1-myfile.doc.gpg', download_url='http://myserver/myfile', is_downloaded=False) submission_sdk_object = mocker.MagicMock() mock_submission = mocker.patch('sdclientapi.Submission') mock_submission.return_value = submission_sdk_object co.on_file_download(source, file_) co.call_api.assert_called_once_with( co.api.download_submission, co.on_file_download_success, co.on_file_download_failure, submission_sdk_object, co.data_dir, current_object=file_, )
def test_Controller_unstars_a_source_if_unstarred(homedir, config, mocker): """ Ensure that the client stars a source if it is unstarred. Using the `config` fixture to ensure the config is written to disk. """ mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) source_db_object = mocker.MagicMock() source_db_object.uuid = mocker.MagicMock() source_db_object.is_starred = False co.call_api = mocker.MagicMock() co.api = mocker.MagicMock() co.api.add_star = mocker.MagicMock() co.on_update_star_success = mocker.MagicMock() co.on_update_star_failure = mocker.MagicMock() source_sdk_object = mocker.MagicMock() mock_source = mocker.patch('sdclientapi.Source') mock_source.return_value = source_sdk_object co.update_star(source_db_object) co.call_api.assert_called_once_with( co.api.add_star, co.on_update_star_success, co.on_update_star_failure, source_sdk_object, ) mock_gui.clear_error_status.assert_called_once_with()
def test_Controller_send_reply_gpg_error(homedir, mocker): ''' Check that if gpg fails when sending a message, we alert the UI and do *not* call the API. ''' mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.call_api = mocker.Mock() co.api = mocker.Mock() mock_encrypt = mocker.patch.object(co.gpg, 'encrypt_to_source', side_effect=Exception) source_uuid = 'abc123' msg_uuid = 'xyz456' msg = 'wat' mock_sdk_source = mocker.Mock() mock_source_init = mocker.patch( 'securedrop_client.logic.sdclientapi.Source', return_value=mock_sdk_source) mock_reply_failed = mocker.patch.object(co, 'reply_failed') co.send_reply(source_uuid, msg_uuid, msg) # ensure there is an attempt to encrypt the message mock_encrypt.assert_called_once_with(source_uuid, msg) # ensure we emit a failure on gpg errors mock_reply_failed.emit.assert_called_once_with(msg_uuid) # ensure api not is called after a gpg error assert not co.call_api.called assert mock_source_init.called # to prevent stale mocks
def test_Controller_sync_api_not_authenticated(homedir, config, mocker): """ If the API isn't authenticated, don't sync. Using the `config` fixture to ensure the config is written to disk. """ mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.authenticated = mocker.MagicMock(return_value=False) co.call_api = mocker.MagicMock() co.sync_api() assert co.call_api.call_count == 0
def test_Controller_sync_api(homedir, config, mocker): """ Sync the API is authenticated. Using the `config` fixture to ensure the config is written to disk. """ mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.authenticated = mocker.MagicMock(return_value=True) co.call_api = mocker.MagicMock() co.sync_api() co.call_api.assert_called_once_with(storage.get_remote_data, co.on_sync_success, co.on_sync_failure, co.api)
def test_Controller_delete_source(homedir, config, mocker): ''' Using the `config` fixture to ensure the config is written to disk. ''' mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() mock_source = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.call_api = mocker.MagicMock() co.api = mocker.MagicMock() co.delete_source(mock_source) co.call_api.assert_called_with(co.api.delete_source, co.on_delete_source_success, co.on_delete_source_failure, mock_source)
def test_Controller_login(homedir, config, mocker): """ Ensures the API is called in the expected manner for logging in the user given the username, password and 2fa token. Using the `config` fixture to ensure the config is written to disk. """ mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.call_api = mocker.MagicMock() mock_api = mocker.patch('securedrop_client.logic.sdclientapi.API') co.login('username', 'password', '123456') co.call_api.assert_called_once_with(mock_api().authenticate, co.on_authenticate_success, co.on_authenticate_failure)
def test_Controller_send_reply_success(homedir, mocker): ''' Check that the "happy path" of encrypting a message and sending it to the sever behaves as expected. ''' mock_gui = mocker.MagicMock() mock_session = mocker.MagicMock() co = Controller('http://localhost', mock_gui, mock_session, homedir) co.call_api = mocker.Mock() co.api = mocker.Mock() encrypted_reply = 's3kr1t m3ss1dg3' mock_encrypt = mocker.patch.object(co.gpg, 'encrypt_to_source', return_value=encrypted_reply) source_uuid = 'abc123' msg_uuid = 'xyz456' msg = 'wat' mock_sdk_source = mocker.Mock() mock_source_init = mocker.patch( 'securedrop_client.logic.sdclientapi.Source', return_value=mock_sdk_source) co.send_reply(source_uuid, msg_uuid, msg) # ensure message is encrypted mock_encrypt.assert_called_once_with(source_uuid, msg) # ensure api is called co.call_api.assert_called_once_with( co.api.reply_source, co.on_reply_success, co.on_reply_failure, mock_sdk_source, encrypted_reply, msg_uuid, current_object=(source_uuid, msg_uuid), ) assert mock_source_init.called # to prevent stale mocks
def test_Controller_login_offline_mode(homedir, config, mocker): """ Ensures user is not authenticated when logging in in offline mode and that the correct windows are displayed. """ co = Controller('http://localhost', mocker.MagicMock(), mocker.MagicMock(), homedir) co.call_api = mocker.MagicMock() co.gui = mocker.MagicMock() co.gui.show_main_window = mocker.MagicMock() co.gui.hide_login = mocker.MagicMock() co.start_message_thread = mocker.MagicMock() co.start_reply_thread = mocker.MagicMock() co.update_sources = mocker.MagicMock() co.login_offline_mode() assert co.call_api.called is False assert co.is_authenticated is False co.gui.show_main_window.assert_called_once_with() co.gui.hide_login.assert_called_once_with() co.start_message_thread.assert_called_once_with() co.update_sources.assert_called_once_with()