def test_update_submissions_deletes_files_associated_with_the_submission( homedir, mocker): """ Check that: * Submissions are deleted on disk after sync. """ mock_session = mocker.MagicMock() # Test scenario: one submission locally, no submissions on server. remote_submissions = [] # A local submission object. To ensure that all files from various # stages of processing are cleaned up, we'll add several filenames. server_filename = "1-pericardial-surfacing-msg.gpg" local_filename_when_decrypted = "1-pericardial-surfacing-msg" local_submission = mocker.MagicMock() local_submission.uuid = "test-uuid" local_submission.filename = server_filename local_submission_source_journalist_filename = "pericardial_surfacing" source_directory = os.path.join( homedir, local_submission_source_journalist_filename) local_submission.location = mocker.MagicMock(return_value=os.path.join( source_directory, local_filename_when_decrypted)) abs_local_filename = add_test_file_to_temp_dir( source_directory, local_filename_when_decrypted) local_submissions = [local_submission] # There needs to be a corresponding local_source. local_source = mocker.MagicMock() local_source.uuid = "test-source-uuid" local_source.id = 666 mock_session.query().filter_by.return_value = [local_source] update_files(remote_submissions, local_submissions, mock_session, homedir) # Ensure the files associated with the submission are deleted on disk. assert not os.path.exists(abs_local_filename) # Ensure the record for the local submission is gone. mock_session.delete.assert_called_once_with(local_submission) # Session is committed to database. assert mock_session.commit.call_count == 1
def test_update_files_renames_file_on_disk(homedir, mocker): """ Check that: * Submissions are renamed on disk after sync. """ data_dir = os.path.join(homedir, 'data') mock_session = mocker.MagicMock() # Remote submission with new filename server_filename = '1-spotted-potato-msg.gpg' remote_submission = mocker.MagicMock() remote_submission.uuid = 'test-uuid' remote_submission.filename = server_filename remote_submissions = [remote_submission] # Local submission that needs to be updated local_filename = '1-pericardial-surfacing-msg.gpg' local_submission = mocker.MagicMock() local_submission.uuid = 'test-uuid' local_submission.filename = local_filename local_submissions = [local_submission] # Add submission file to test directory local_filename_decrypted = '1-pericardial-surfacing-msg' add_test_file_to_temp_dir(data_dir, local_filename_decrypted) # There needs to be a corresponding local_source. local_source = mocker.MagicMock() local_source.uuid = 'test-source-uuid' local_source.id = 123 mock_session.query().filter_by.return_value = [ local_source, ] update_files(remote_submissions, local_submissions, mock_session, data_dir) updated_local_filename = '1-spotted-potato-msg' assert local_submission.filename == remote_submission.filename assert os.path.exists(os.path.join(data_dir, updated_local_filename))
def test_update_files(homedir, mocker): """ Check that: * Existing submissions are updated in the local database. * New submissions have an entry in the local database. * Local submission not returned by the remote server are deleted from the local database. """ data_dir = os.path.join(homedir, "data") mock_session = mocker.MagicMock() # Source object related to the submissions. source = mocker.MagicMock() source.uuid = str(uuid.uuid4()) # Some submission objects from the API, one of which will exist in the # local database, the other will NOT exist in the local source database # (this will be added to the database) remote_sub_update = make_remote_submission(source.uuid) remote_sub_create = make_remote_submission(source.uuid) remote_submissions = [remote_sub_update, remote_sub_create] # Some local submission objects. One already exists in the API results # (this will be updated), one does NOT exist in the API results (this will # be deleted from the local database). local_sub_update = mocker.MagicMock() local_sub_update.uuid = remote_sub_update.uuid local_sub_update.is_downloaded = True local_sub_update.is_decrypted = False local_filename = "originalsubmissionname.txt" local_sub_update.filename = local_filename local_sub_delete = mocker.MagicMock() local_sub_delete.uuid = str(uuid.uuid4()) local_sub_delete.filename = "local_sub_delete.filename" local_submissions = [local_sub_update, local_sub_delete] # There needs to be a corresponding local_source. local_source = mocker.MagicMock() local_source.uuid = source.uuid local_source.id = 666 # };-) mock_session.query().filter_by().first.return_value = local_source mock_delete_submission_files = mocker.patch( "securedrop_client.storage.delete_single_submission_or_reply_on_disk") update_files(remote_submissions, local_submissions, mock_session, data_dir) # Check the expected local submission object has been updated with values # from the API. assert local_sub_update.filename == local_filename assert local_sub_update.size == remote_sub_update.size assert local_sub_update.is_read == remote_sub_update.is_read # Check the expected local source object has been created with values from # the API. assert mock_session.add.call_count == 1 new_sub = mock_session.add.call_args_list[0][0][0] assert new_sub.uuid == remote_sub_create.uuid assert new_sub.source_id == local_source.id assert new_sub.filename == remote_sub_create.filename # Ensure the record for the local source that is missing from the results # of the API is deleted. mock_session.delete.assert_called_once_with(local_sub_delete) mock_delete_submission_files.assert_called_once_with( local_sub_delete, data_dir) # Session is committed to database. assert mock_session.commit.call_count == 1
def test_update_files(homedir, mocker): """ Check that: * Existing submissions are updated in the local database. * New submissions have an entry in the local database. * Local submission not returned by the remote server are deleted from the local database. * `rename_file` is called if local data files need to be updated with new filenames to match remote. Note: The only reason this should happen is if there is a new journalist_designation that causes remote filenames to be updated. """ data_dir = os.path.join(homedir, 'data') mock_session = mocker.MagicMock() # Source object related to the submissions. source = mocker.MagicMock() source.uuid = str(uuid.uuid4()) # Some submission objects from the API, one of which will exist in the # local database, the other will NOT exist in the local source database # (this will be added to the database) remote_sub_update = make_remote_submission(source.uuid) remote_sub_create = make_remote_submission(source.uuid) remote_submissions = [remote_sub_update, remote_sub_create] # Some local submission objects. One already exists in the API results # (this will be updated), one does NOT exist in the API results (this will # be deleted from the local database). local_sub_update = mocker.MagicMock() local_sub_update.uuid = remote_sub_update.uuid local_sub_update.filename = "overwrite_this.filename" local_sub_update.original_filename = "overwrite_this.filename.txt" local_sub_delete = mocker.MagicMock() local_sub_delete.uuid = str(uuid.uuid4()) local_sub_delete.filename = "local_sub_delete.filename" local_sub_delete.original_filename = "local_sub_delete.filename.txt" local_submissions = [local_sub_update, local_sub_delete] # There needs to be a corresponding local_source. local_source = mocker.MagicMock() local_source.uuid = source.uuid local_source.id = 666 # };-) mock_session.query().filter_by.return_value = [ local_source, ] patch_rename_file = mocker.patch('securedrop_client.storage.rename_file') update_files(remote_submissions, local_submissions, mock_session, data_dir) # Check the expected local submission object has been updated with values # from the API. assert local_sub_update.filename == remote_sub_update.filename assert local_sub_update.size == remote_sub_update.size assert local_sub_update.is_read == remote_sub_update.is_read # Check that rename_file is called if the local storage filenames need to # be updated assert patch_rename_file.called # Check the expected local source object has been created with values from # the API. assert mock_session.add.call_count == 1 new_sub = mock_session.add.call_args_list[0][0][0] assert new_sub.uuid == remote_sub_create.uuid assert new_sub.source_id == local_source.id assert new_sub.filename == remote_sub_create.filename # Ensure the record for the local source that is missing from the results # of the API is deleted. mock_session.delete.assert_called_once_with(local_sub_delete) # Session is committed to database. assert mock_session.commit.call_count == 1