Skip to content

Commit

Permalink
test: update tests for pending/failed/draft replies
Browse files Browse the repository at this point in the history
  • Loading branch information
redshiftzero committed Oct 24, 2019
1 parent e55e45f commit 0a76bcf
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 11 deletions.
45 changes: 38 additions & 7 deletions tests/api_jobs/test_uploads.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ def test_SendReplyJobTimeoutError():
assert str(error) == 'mock_message'


def test_send_reply_success(homedir, mocker, session, session_maker):
def test_send_reply_success(homedir, mocker, session, session_maker,
reply_status_codes):
'''
Check that the "happy path" of encrypting a message and sending it to the
server behaves as expected.
'''
source = factory.Source()
session.add(source)
msg_uuid = 'xyz456'
draft_reply = factory.DraftReply(uuid=msg_uuid)
session.add(draft_reply)
session.commit()

gpg = GpgHelper(homedir, session_maker, is_qubes=False)
Expand All @@ -29,7 +33,6 @@ def test_send_reply_success(homedir, mocker, session, session_maker):

encrypted_reply = 's3kr1t m3ss1dg3'
mock_encrypt = mocker.patch.object(gpg, 'encrypt_to_source', return_value=encrypted_reply)
msg_uuid = 'xyz456'
msg = 'wat'

mock_reply_response = sdclientapi.Reply(uuid=msg_uuid, filename='5-dummy-reply')
Expand Down Expand Up @@ -58,14 +61,18 @@ def test_send_reply_success(homedir, mocker, session, session_maker):
assert reply.journalist_id == api_client.token_journalist_uuid


def test_send_reply_failure_gpg_error(homedir, mocker, session, session_maker):
def test_send_reply_failure_gpg_error(homedir, mocker, session, session_maker,
reply_status_codes):
'''
Check that if gpg fails when sending a message, we do not call the API, and ensure that
SendReplyJobError is raised when there is a CryptoError so we can handle it in
ApiJob._do_call_api.
'''
source = factory.Source()
session.add(source)
msg_uuid = 'xyz456'
draft_reply = factory.DraftReply(uuid=msg_uuid)
session.add(draft_reply)
session.commit()

gpg = GpgHelper(homedir, session_maker, is_qubes=False)
Expand All @@ -74,7 +81,6 @@ def test_send_reply_failure_gpg_error(homedir, mocker, session, session_maker):
api_client.token_journalist_uuid = 'journalist ID sending the reply'

mock_encrypt = mocker.patch.object(gpg, 'encrypt_to_source', side_effect=CryptoError)
msg_uuid = 'xyz456'
msg = 'wat'

mock_reply_response = sdclientapi.Reply(uuid=msg_uuid, filename='5-dummy-reply')
Expand Down Expand Up @@ -103,14 +109,21 @@ def test_send_reply_failure_gpg_error(homedir, mocker, session, session_maker):
replies = session.query(db.Reply).filter_by(uuid=msg_uuid).all()
assert len(replies) == 0

# Ensure that the draft reply is still in the db
drafts = session.query(db.DraftReply).filter_by(uuid=msg_uuid).all()
assert len(drafts) == 1

def test_send_reply_failure_unknown_error(homedir, mocker, session, session_maker):

def test_send_reply_failure_unknown_error(homedir, mocker, session, session_maker,
reply_status_codes):
'''
Check that if the SendReplyJob api call fails when sending a message that SendReplyJobError
is raised and the reply is not added to the local database.
'''
source = factory.Source()
session.add(source)
draft_reply = factory.DraftReply(uuid='mock_reply_uuid')
session.add(draft_reply)
session.commit()
api_client = mocker.MagicMock()
mocker.patch.object(api_client, 'reply_source', side_effect=Exception)
Expand All @@ -125,14 +138,21 @@ def test_send_reply_failure_unknown_error(homedir, mocker, session, session_make
replies = session.query(db.Reply).filter_by(uuid='mock_reply_uuid').all()
assert len(replies) == 0

# Ensure that the draft reply is still in the db
drafts = session.query(db.DraftReply).filter_by(uuid='mock_reply_uuid').all()
assert len(drafts) == 1


def test_send_reply_failure_timeout_error(homedir, mocker, session, session_maker):
def test_send_reply_failure_timeout_error(homedir, mocker, session, session_maker,
reply_status_codes):
'''
Check that if the SendReplyJob api call fails because of a RequestTimeoutError that a
SendReplyJobTimeoutError is raised.
'''
source = factory.Source()
session.add(source)
draft_reply = factory.DraftReply(uuid='mock_reply_uuid')
session.add(draft_reply)
session.commit()
api_client = mocker.MagicMock()
mocker.patch.object(api_client, 'reply_source', side_effect=sdclientapi.RequestTimeoutError)
Expand All @@ -147,8 +167,13 @@ def test_send_reply_failure_timeout_error(homedir, mocker, session, session_make
replies = session.query(db.Reply).filter_by(uuid='mock_reply_uuid').all()
assert len(replies) == 0

# Ensure that the draft reply is still in the db
drafts = session.query(db.DraftReply).filter_by(uuid='mock_reply_uuid').all()
assert len(drafts) == 1

def test_send_reply_failure_when_repr_is_none(homedir, mocker, session, session_maker):

def test_send_reply_failure_when_repr_is_none(homedir, mocker, session, session_maker,
reply_status_codes):
'''
Check that the SendReplyJob api call results in a SendReplyJobError and nothing else, e.g.
no TypeError, when an api call results in an exception that returns None for __repr__
Expand All @@ -160,6 +185,8 @@ def __repr__(self):

source = factory.Source(uuid='mock_reply_uuid')
session.add(source)
draft_reply = factory.DraftReply(uuid='mock_reply_uuid')
session.add(draft_reply)
session.commit()
api_client = mocker.MagicMock()
mocker.patch.object(api_client, 'reply_source', side_effect=MockException('mock'))
Expand All @@ -175,3 +202,7 @@ def __repr__(self):
encrypt_fn.assert_called_once_with(source.uuid, 'mock_message')
replies = session.query(db.Reply).filter_by(uuid='mock_reply_uuid').all()
assert len(replies) == 0

# Ensure that the draft reply is still in the db
drafts = session.query(db.DraftReply).filter_by(uuid='mock_reply_uuid').all()
assert len(drafts) == 1
18 changes: 18 additions & 0 deletions tests/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
MESSAGE_COUNT = 0
FILE_COUNT = 0
REPLY_COUNT = 0
DRAFT_REPLY_COUNT = 0
USER_COUNT = 0


Expand Down Expand Up @@ -82,6 +83,23 @@ def Reply(**attrs):
return db.Reply(**defaults)


def DraftReply(**attrs):
global DRAFT_REPLY_COUNT
DRAFT_REPLY_COUNT += 1
defaults = dict(
timestamp=datetime.utcnow(),
source_id=1,
journalist_id=1,
file_counter=1,
uuid='draft-reply-uuid-{}'.format(REPLY_COUNT),
content='content',
)

defaults.update(attrs)

return db.DraftReply(**defaults)


def File(**attrs):
global FILE_COUNT
FILE_COUNT += 1
Expand Down
6 changes: 5 additions & 1 deletion tests/gui/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,7 @@ def test_ReplyWidget_init(mocker):
ReplyWidget(
'mock id',
'hello',
'dummy',
mock_update_signal,
mock_success_signal,
mock_failure_signal,
Expand Down Expand Up @@ -1857,7 +1858,7 @@ def test_ConversationView_add_reply_from_reply_box(mocker):
cv.add_reply_from_reply_box('abc123', 'test message')

reply_widget.assert_called_once_with(
'abc123', 'test message', reply_ready, reply_succeeded, reply_failed)
'abc123', 'test message', 'PENDING', reply_ready, reply_succeeded, reply_failed)
cv.conversation_layout.addWidget.assert_called_once_with(
reply_widget_res, alignment=Qt.AlignRight)

Expand Down Expand Up @@ -1895,6 +1896,7 @@ def test_ConversationView_add_reply(mocker, session, source):
mock_reply_widget.assert_called_once_with(
reply.uuid,
content,
'SUCCEEDED',
mock_reply_ready_signal,
mock_reply_succeeded_signal,
mock_reply_failed_signal)
Expand Down Expand Up @@ -1938,6 +1940,7 @@ def test_ConversationView_add_reply_no_content(mocker, session, source):
mock_reply_widget.assert_called_once_with(
reply.uuid,
'<Reply not yet available>',
'SUCCEEDED',
mock_reply_ready_signal,
mock_reply_succeeded_signal,
mock_reply_failed_signal)
Expand Down Expand Up @@ -2244,6 +2247,7 @@ def test_ReplyWidget_success_failure_slots(mocker):

widget = ReplyWidget(msg_id,
'lol',
'PENDING',
mock_update_signal,
mock_success_signal,
mock_failure_signal)
Expand Down
6 changes: 4 additions & 2 deletions tests/test_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1220,12 +1220,14 @@ def test_Controller_delete_source(homedir, config, mocker, session_maker):
)


def test_Controller_send_reply_success(homedir, config, mocker, session_maker, session):
def test_Controller_send_reply_success(homedir, config, mocker, session_maker, session,
reply_status_codes):
'''
Check that a SendReplyJob is submitted to the queue when send_reply is called.
'''
mock_gui = mocker.MagicMock()
co = Controller('http://localhost', mock_gui, session_maker, homedir)
co.user = factory.User()

mock_success_signal = mocker.MagicMock()
mock_failure_signal = mocker.MagicMock()
Expand All @@ -1237,9 +1239,9 @@ def test_Controller_send_reply_success(homedir, config, mocker, session_maker, s

source = factory.Source()
session.add(source)
msg_uuid = 'xyz456'
session.commit()

msg_uuid = 'xyz456'
msg = 'wat'

co.send_reply(source.uuid, msg_uuid, msg)
Expand Down
45 changes: 44 additions & 1 deletion tests/test_models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import datetime
import pytest

from tests import factory
from securedrop_client.db import Reply, File, Message, User
from securedrop_client.db import DraftReply, Reply, File, Message, ReplySendStatus, User


def test_user_fullname():
Expand Down Expand Up @@ -72,6 +73,18 @@ def test_string_representation_of_reply():
reply.__repr__()


def test_string_representation_of_draft_reply():
user = User(username='hehe')
source = factory.Source()
draft_reply = DraftReply(source=source, journalist=user, uuid='test')
draft_reply.__repr__()


def test_string_representation_of_send_reply_status():
reply_status = ReplySendStatus(name='teehee')
reply_status.__repr__()


def test_source_collection():
# Create some test submissions and replies
source = factory.Source()
Expand All @@ -92,6 +105,36 @@ def test_source_collection():
assert source.collection[2] == message


def test_source_collection_ordering_with_multiple_draft_replies():
# Create some test submissions, replies, and draft replies.
source = factory.Source()
file_1 = File(source=source, uuid="test", size=123, filename="1-test.doc.gpg",
download_url='http://test/test')
message_2 = Message(source=source, uuid="test", size=123, filename="2-test.doc.gpg",
download_url='http://test/test')
user = User(username='hehe')
reply_3 = Reply(source=source, journalist=user, filename="3-reply.gpg",
size=1234, uuid='test')
draft_reply_4 = DraftReply(uuid='4', source=source, journalist=user, file_counter=3,
timestamp=datetime.datetime(2001, 6, 6, 6, 0))
draft_reply_5 = DraftReply(uuid='5', source=source, journalist=user, file_counter=3,
timestamp=datetime.datetime(2000, 6, 6, 6, 0))
reply_6 = Reply(source=source, journalist=user, filename="4-reply.gpg",
size=1234, uuid='test2')
source.files = [file_1]
source.messages = [message_2]
source.replies = [reply_3, reply_6]
source.draftreplies = [draft_reply_4, draft_reply_5]

# Now these items should be in the source collection in the proper order
assert source.collection[0] == file_1
assert source.collection[1] == message_2
assert source.collection[2] == reply_3
assert source.collection[3] == draft_reply_4
assert source.collection[4] == draft_reply_5
assert source.collection[5] == reply_6


def test_file_init():
'''
Check that:
Expand Down

0 comments on commit 0a76bcf

Please sign in to comment.