Skip to content

Commit 5825588

Browse files
add initial tests using pytest
1 parent d8019ef commit 5825588

File tree

6 files changed

+431
-0
lines changed

6 files changed

+431
-0
lines changed

requirements-test.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-r requirements.txt
2+
pytest==8.3.5

tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

tests/conftest.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import pytest
2+
import os
3+
4+
# TODO: Fix hack. Changes the env var before initializing the db for testing
5+
os.environ['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
6+
7+
from app import app, db
8+
9+
10+
@pytest.fixture
11+
def client():
12+
app.config['TESTING'] = True
13+
with app.test_client() as client:
14+
with app.app_context():
15+
db.create_all()
16+
yield client
17+
with app.app_context():
18+
db.drop_all()
19+
20+
21+
@pytest.fixture
22+
def register_user(client):
23+
def _register(email, password):
24+
return client.post('/auth/register', json={'email': email, 'password': password})
25+
return _register
26+
27+
28+
@pytest.fixture
29+
def login_user(client):
30+
def _login(email, password):
31+
return client.post('/auth/login', json={'email': email, 'password': password})
32+
return _login

tests/test_auth.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import pytest
2+
3+
from app.models import User
4+
from tests import utils
5+
6+
7+
class TestAuth:
8+
TEST_EMAIL = '[email protected]'
9+
TEST_PASSWORD = 'testpassword'
10+
11+
12+
@pytest.fixture(autouse=True)
13+
def setup(self, client):
14+
self.client = client
15+
with client.application.app_context():
16+
assert User.query.count() == 0
17+
18+
19+
def _verify_user_in_db(self, email, should_exist=True):
20+
with self.client.application.app_context():
21+
user = User.get(email=email)
22+
if should_exist:
23+
assert user is not None
24+
assert user.email == email
25+
return user
26+
else:
27+
assert user is None
28+
29+
30+
def _count_users(self):
31+
with self.client.application.app_context():
32+
return User.query.count()
33+
34+
35+
def _test_invalid_request_data(self, endpoint, expected_status=400):
36+
response = self.client.post(endpoint, json={})
37+
assert response.status_code == expected_status
38+
39+
response = self.client.post(endpoint, json={'email': self.TEST_EMAIL})
40+
assert response.status_code == expected_status
41+
42+
response = self.client.post(endpoint, json={'password': self.TEST_PASSWORD})
43+
assert response.status_code == expected_status
44+
45+
response = self.client.post(endpoint, data='not json data')
46+
assert response.status_code == 415
47+
48+
49+
def test_register_success(self, register_user):
50+
response = register_user(self.TEST_EMAIL, self.TEST_PASSWORD)
51+
52+
assert response.status_code == 201
53+
assert b'Registered!' in response.data
54+
assert self._count_users() == 1
55+
user = self._verify_user_in_db(self.TEST_EMAIL)
56+
assert user.password_hash != self.TEST_PASSWORD
57+
58+
59+
def test_register_duplicate_email(self, register_user):
60+
register_user(self.TEST_EMAIL, self.TEST_PASSWORD)
61+
response = register_user(self.TEST_EMAIL, self.TEST_PASSWORD)
62+
63+
assert response.status_code == 409
64+
assert b'Email already exists' in response.data
65+
assert self._count_users() == 1
66+
self._verify_user_in_db(self.TEST_EMAIL)
67+
68+
69+
def test_register_invalid_email_format(self, register_user):
70+
invalid_email = 'not-an-email'
71+
response = register_user(invalid_email, self.TEST_PASSWORD)
72+
73+
assert response.status_code == 400
74+
data = response.get_json()
75+
assert data['code'] == 'invalid_email_format'
76+
assert 'error' in data
77+
self._verify_user_in_db(invalid_email, should_exist=False)
78+
79+
80+
def test_register_invalid_data(self):
81+
self._test_invalid_request_data('/auth/register')
82+
assert self._count_users() == 0
83+
84+
85+
def test_login_success(self, register_user, login_user):
86+
register_user(self.TEST_EMAIL, self.TEST_PASSWORD)
87+
response = login_user(self.TEST_EMAIL, self.TEST_PASSWORD)
88+
89+
assert response.status_code == 200
90+
data = response.get_json()
91+
assert 'access_token' in data
92+
assert 'refresh_token' in data
93+
assert len(data['access_token']) > 0
94+
assert len(['refresh_token']) > 0
95+
96+
97+
def test_login_invalid_password(self, register_user, login_user):
98+
register_user(self.TEST_EMAIL, self.TEST_PASSWORD)
99+
response = login_user(self.TEST_EMAIL, 'wrongpassword')
100+
101+
assert response.status_code == 401
102+
assert b'Invalid username or password' in response.data
103+
104+
105+
def test_login_invalid_data(self):
106+
self._test_invalid_request_data('/auth/login')
107+
108+
109+
def test_refresh_token(self, register_user, login_user):
110+
register_user(self.TEST_EMAIL, self.TEST_PASSWORD)
111+
login_resp = login_user(self.TEST_EMAIL, self.TEST_PASSWORD)
112+
tokens = login_resp.get_json()
113+
refresh_token = tokens['refresh_token']
114+
115+
headers = utils.get_auth_header(refresh_token)
116+
refresh_resp = self.client.post('/auth/refresh', headers=headers)
117+
assert refresh_resp.status_code == 200
118+
data = refresh_resp.get_json()
119+
assert 'access_token' in data
120+
121+
122+
def test_refresh_token_invalid(self, register_user, login_user):
123+
# Access token test
124+
register_user(self.TEST_EMAIL, self.TEST_PASSWORD)
125+
login_resp = login_user(self.TEST_EMAIL, self.TEST_PASSWORD)
126+
tokens = login_resp.get_json()
127+
access_token = tokens['access_token']
128+
headers = utils.get_auth_header(access_token)
129+
response = self.client.post('/auth/refresh', headers=headers)
130+
131+
utils.verify_token_error_response(response, 'invalid_token')
132+
133+
# Malformed token test
134+
malformed_headers = utils.get_invalid_token_headers()
135+
response = self.client.post('/auth/refresh', headers=malformed_headers)
136+
utils.verify_token_error_response(response, 'invalid_token')
137+
138+
139+
def test_refresh_token_missing_auth(self):
140+
response = self.client.post('/auth/refresh')
141+
utils.verify_token_error_response(response, 'authorization_required')
142+
143+
144+
def test_refresh_token_expired(self):
145+
expired_headers = utils.get_expired_token_headers(self.client.application.app_context())
146+
response = self.client.post('/auth/refresh', headers=expired_headers)
147+
utils.verify_token_error_response(response, 'token_expired')

0 commit comments

Comments
 (0)