Skip to content
This repository has been archived by the owner on Jan 7, 2024. It is now read-only.

Use pytest without unittest's TestCase class #151

Merged
merged 6 commits into from
Dec 11, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion data/setUp.json

This file was deleted.

134 changes: 69 additions & 65 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class TestAPI(TestShared):
API and API Proxy tests.
"""

def setUp(self):
def setup_method(self):
self.totp = pyotp.TOTP("JHCOGO7VCER3EJ4L")
self.username = "journalist"
self.password = "correct horse battery staple profanity oil chewy"
Expand Down Expand Up @@ -54,24 +54,60 @@ def setUp(self):
@vcr.use_cassette("data/test-baduser.yml")
def test_auth_baduser(self):
self.api = API(self.server, "no", self.password, str(self.totp.now()))
with self.assertRaises(AuthError):
with pytest.raises(AuthError):
self.api.authenticate()

@vcr.use_cassette("data/test-badpassword.yml")
def test_auth_badpassword(self):
self.api = API(self.server, self.username, "no", str(self.totp.now()))
with self.assertRaises(AuthError):
with pytest.raises(AuthError):
self.api.authenticate()

@vcr.use_cassette("data/test-badotp.yml")
def test_auth_badotp(self):
self.api = API(self.server, self.username, self.password, "no")
with self.assertRaises(AuthError):
with pytest.raises(AuthError):
self.api.authenticate()

def test_api_auth(self):
super().api_auth()

# This test is materially different in the API & API Proxy versions.
@vcr.use_cassette("data/test-download-submission.yml")
def test_download_submission(self):
submissions = self.api.get_all_submissions()
unread_submission = None
for s in submissions:
if not s.is_read:
unread_submission = s
break

if not unread_submission:
assert False, "There must be an unread submission in the db for this test to work."

assert not unread_submission.is_read

# We need a temporary directory to download
tmpdir = tempfile.mkdtemp()
etag, filepath = self.api.download_submission(s, tmpdir)

# now let us read the downloaded file
with open(filepath, "rb") as fobj:
content = fobj.read()

# Verify the ETag contains the algorithm and the hash is correct
hasher = hashlib.sha256()
hasher.update(content)

assert etag == "sha256:{}".format(hasher.hexdigest())

# is_read should still be False as of SecureDrop 1.6.0 or later
submission = self.api.get_submission(unread_submission)
assert not submission.is_read

# Let us remove the temporary directory
shutil.rmtree(tmpdir)

@vcr.use_cassette("data/test-seen.yml")
def test_seen(self):
super().seen()
Expand Down Expand Up @@ -120,22 +156,6 @@ def test_get_all_submissions(self):
def test_flag_source(self):
super().flag_source()

@vcr.use_cassette("data/test-delete-source.yml")
def test_delete_source(self):
super().delete_source()

@vcr.use_cassette("data/test-delete-source.yml")
def test_delete_source_from_string(self):
super().delete_source(from_string=True)

@vcr.use_cassette("data/test-delete-submission.yml")
def test_delete_submission(self):
super().delete_submission()

@vcr.use_cassette("data/test-delete-submission-from-string.yml")
def test_delete_submission_from_string(self):
super().delete_submission(from_string=True)

@vcr.use_cassette("data/test-get-current-user.yml")
def test_get_current_user(self):
super().get_current_user()
Expand All @@ -148,50 +168,6 @@ def test_get_users(self):
def test_error_unencrypted_reply(self):
super().error_unencrypted_reply()

@vcr.use_cassette("data/test-reply-source.yml")
def test_reply_source(self):
super().reply_source()

@vcr.use_cassette("data/test-reply-source-with-uuid.yml")
def test_reply_source_with_uuid(self):
super().reply_source_with_uuid()

# This test is materially different in the API & API Proxy versions.
@vcr.use_cassette("data/test-download-submission.yml")
def test_download_submission(self):
submissions = self.api.get_all_submissions()
unread_submission = None
for s in submissions:
if not s.is_read:
unread_submission = s
break

if not unread_submission:
self.assertFalse("There must be an unread submission in the db for this test to work.")

self.assertFalse(unread_submission.is_read)

# We need a temporary directory to download
tmpdir = tempfile.mkdtemp()
etag, filepath = self.api.download_submission(s, tmpdir)

# now let us read the downloaded file
with open(filepath, "rb") as fobj:
content = fobj.read()

# Verify the ETag contains the algorithm and the hash is correct
hasher = hashlib.sha256()
hasher.update(content)

assert etag == "sha256:{}".format(hasher.hexdigest())

# is_read should still be False as of SecureDrop 1.6.0 or later
submission = self.api.get_submission(unread_submission)
self.assertFalse(submission.is_read)

# Let us remove the temporary directory
shutil.rmtree(tmpdir)

@vcr.use_cassette("data/test-get-replies-from-source.yml")
def test_get_replies_from_source(self):
super().get_replies_from_source()
Expand Down Expand Up @@ -226,14 +202,42 @@ def test_download_reply(self):
# Let us remove the temporary directory
shutil.rmtree(tmpdir)

# ORDER MATTERS: The following tests add or delete data, and should
# not be run before other tests, which may rely on the original fixture
# state.

@vcr.use_cassette("data/test-reply-source.yml")
def test_reply_source(self):
super().reply_source()

@vcr.use_cassette("data/test-reply-source-with-uuid.yml")
def test_reply_source_with_uuid(self):
super().reply_source_with_uuid()

@vcr.use_cassette("data/test-delete-source.yml")
def test_delete_source(self):
super().delete_source()

@vcr.use_cassette("data/test-delete-source.yml")
def test_delete_source_from_string(self):
super().delete_source(from_string=True)

@vcr.use_cassette("data/test-delete-submission.yml")
def test_delete_submission(self):
super().delete_submission()

@vcr.use_cassette("data/test-delete-submission-from-string.yml")
def test_delete_submission_from_string(self):
super().delete_submission(from_string=True)

@vcr.use_cassette("data/test-delete-reply.yml")
def test_delete_reply(self):
super().delete_reply()

@vcr.use_cassette("data/test-logout.yml")
def test_zlogout(self):
r = self.api.logout()
self.assertTrue(r)
assert r


def test_request_connect_timeout(mocker):
Expand Down
69 changes: 37 additions & 32 deletions tests/test_apiproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class TestAPIProxy(TestShared):
"""

@dastollervey_datasaver
def setUp(self):
def setup_method(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we call this setup instead of setup_method?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method name is designated by pytest for the setup that runs before each test in class-based tests:
https://docs.pytest.org/en/stable/xunit_setup.html#method-and-function-level-setup-teardown

self.totp = pyotp.TOTP("JHCOGO7VCER3EJ4L")
self.username = "journalist"
self.password = "correct horse battery staple profanity oil chewy"
Expand Down Expand Up @@ -56,6 +56,7 @@ def setUp(self):
save_auth(self.api.token)
break

@dastollervey_datasaver
def test_api_auth(self):
super().api_auth()

Expand Down Expand Up @@ -107,22 +108,6 @@ def test_get_all_submissions(self):
def test_flag_source(self):
super().flag_source()

@dastollervey_datasaver
def test_delete_source(self):
super().delete_source()

@dastollervey_datasaver
def test_delete_source_from_string(self):
super().delete_source(from_string=True)

@dastollervey_datasaver
def test_delete_submission(self):
super().delete_submission()

@dastollervey_datasaver
def test_delete_submission_from_string(self):
super().delete_submission(from_string=True)

@dastollervey_datasaver
def test_get_current_user(self):
super().get_current_user()
Expand All @@ -135,14 +120,6 @@ def test_get_users(self):
def test_error_unencrypted_reply(self):
super().error_unencrypted_reply()

@dastollervey_datasaver
def test_reply_source(self):
super().reply_source()

@dastollervey_datasaver
def test_reply_source_with_uuid(self):
super().reply_source_with_uuid()

@dastollervey_datasaver
def test_get_replies_from_source(self):
super().get_replies_from_source()
Expand All @@ -155,10 +132,6 @@ def test_get_reply_from_source(self):
def test_get_all_replies(self):
super().get_all_replies()

@dastollervey_datasaver
def test_delete_reply(self):
super().delete_reply()

@dastollervey_datasaver
def test_download_reply(self):
r = self.api.get_all_replies()[0]
Expand All @@ -180,7 +153,7 @@ def test_download_reply(self):
def test_download_submission(self):
s = self.api.get_all_submissions()[0]

self.assertFalse(s.is_read)
assert not s.is_read

# We need a temporary directory to download
tmpdir = tempfile.mkdtemp()
Expand All @@ -195,15 +168,47 @@ def test_download_submission(self):
# is_read should still be False as of SecureDrop 1.6.0 or later.

s = self.api.get_submission(s)
self.assertFalse(s.is_read)
assert not s.is_read

# Let us remove the temporary directory
shutil.rmtree(tmpdir)

# ORDER MATTERS: The following tests add or delete data, and should
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💎

# not be run before other tests which may rely on the original fixture
# state.

@dastollervey_datasaver
def test_reply_source(self):
super().reply_source()

@dastollervey_datasaver
def test_reply_source_with_uuid(self):
super().reply_source_with_uuid()

@dastollervey_datasaver
def test_delete_source(self):
super().delete_source()

@dastollervey_datasaver
def test_delete_source_from_string(self):
super().delete_source(from_string=True)

@dastollervey_datasaver
def test_delete_submission(self):
super().delete_submission()

@dastollervey_datasaver
def test_delete_submission_from_string(self):
super().delete_submission(from_string=True)

@dastollervey_datasaver
def test_delete_reply(self):
super().delete_reply()

@dastollervey_datasaver
def test_logout(self):
r = self.api.logout()
self.assertTrue(r)
assert r
if os.path.exists("login.txt"):
os.unlink("login.txt")
if os.path.exists("testtoken.json"):
Expand Down
Loading