Skip to content

Commit 7efc921

Browse files
author
EliuX
committed
fix: Close #94 Fix tests to support authentication
1 parent 1a41ed7 commit 7efc921

File tree

9 files changed

+480
-238
lines changed

9 files changed

+480
-238
lines changed

commons/data_access_layer/database.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ def delete(self, id):
3636

3737

3838
def init_app(app: Flask) -> None:
39-
init_sql(app) # TODO Delete after the migration to Cosmos DB has finished.
4039
init_cosmos_db(app)
4140

4241

commons/data_access_layer/sql.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
from flask_sqlalchemy import SQLAlchemy
55

66
from commons.data_access_layer.database import CRUDDao, ID_MAX_LENGTH
7-
from time_tracker_api.security import current_user_id
87

98
db: SQLAlchemy = None
10-
AuditedSQLModel = None
119

1210

1311
def handle_commit_issues(f):
@@ -25,16 +23,6 @@ def init_app(app: Flask) -> None:
2523
global db
2624
db = SQLAlchemy(app)
2725

28-
global AuditedSQLModel
29-
30-
class AuditedSQLModelClass():
31-
created_at = db.Column(db.DateTime, server_default=db.func.now())
32-
updated_at = db.Column(db.DateTime, onupdate=datetime.utcnow)
33-
created_by = db.Column(db.String(ID_MAX_LENGTH), default=current_user_id)
34-
updated_by = db.Column(db.String(ID_MAX_LENGTH), onupdate=current_user_id)
35-
36-
AuditedSQLModel = AuditedSQLModelClass
37-
3826

3927
class SQLRepository():
4028
def __init__(self, model_type: type):

tests/commons/data_access_layer/sql_test.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ def test_create(sql_repository):
1616

1717
assert result is not None
1818
assert result.id is not None
19-
assert result.created_at is not None
20-
assert result.created_by is not None
21-
assert result.updated_at is None
22-
assert result.updated_by is None
2319

2420
existing_elements_registry.append(result)
2521

@@ -43,9 +39,6 @@ def test_update(sql_repository):
4339
assert updated_element.id == existing_element.id
4440
assert updated_element.name == "Jon Snow"
4541
assert updated_element.age == 34
46-
assert updated_element.updated_at is not None
47-
assert updated_element.updated_at > updated_element.created_at
48-
assert updated_element.updated_by is not None
4942

5043

5144
def test_find_all(sql_repository):

tests/conftest.py

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,14 @@
77
from flask.testing import FlaskClient
88

99
from commons.data_access_layer.cosmos_db import CosmosDBRepository, datetime_str, current_datetime
10+
from commons.data_access_layer.database import init_sql
1011
from time_tracker_api import create_app
1112
from time_tracker_api.security import get_or_generate_dev_secret_key
1213
from time_tracker_api.time_entries.time_entries_model import TimeEntryCosmosDBRepository
1314

1415
fake = Faker()
1516
Faker.seed()
1617

17-
TEST_USER = {
18-
"name": "[email protected]",
19-
"password": "secret"
20-
}
21-
22-
23-
class User:
24-
def __init__(self, username, password):
25-
self.username = username
26-
self.password = password
27-
28-
29-
class AuthActions:
30-
"""Auth actions container in tests"""
31-
32-
def __init__(self, app, client):
33-
self._app = app
34-
self._client = client
35-
36-
# def login(self, username=TEST_USER["name"],
37-
# password=TEST_USER["password"]):
38-
# login_url = url_for("security.login", self._app)
39-
# return open_with_basic_auth(self._client,
40-
# login_url,
41-
# username,
42-
# password)
43-
#
44-
# def logout(self):
45-
# return self._client.get(url_for("security.logout", self._app),
46-
# follow_redirects=True)
47-
4818

4919
@pytest.fixture(scope='session')
5020
def app() -> Flask:
@@ -58,9 +28,12 @@ def client(app: Flask) -> FlaskClient:
5828

5929

6030
@pytest.fixture(scope="module")
61-
def sql_model_class():
62-
from commons.data_access_layer.sql import db, AuditedSQLModel
63-
class PersonSQLModel(db.Model, AuditedSQLModel):
31+
def sql_model_class(app: Flask):
32+
with app.app_context():
33+
init_sql(app)
34+
35+
from commons.data_access_layer.sql import db
36+
class PersonSQLModel(db.Model):
6437
__tablename__ = 'test'
6538
id = db.Column(db.Integer, primary_key=True)
6639
name = db.Column(db.String(80), unique=False, nullable=False)
@@ -186,11 +159,11 @@ def running_time_entry(time_entry_repository: TimeEntryCosmosDBRepository,
186159

187160

188161
@pytest.fixture(scope="session")
189-
def valid_jwt(app: Flask) -> str:
162+
def valid_jwt(app: Flask, tenant_id: str, owner_id: str) -> str:
190163
expiration_time = datetime.utcnow() + timedelta(seconds=3600)
191164
return jwt.encode({
192-
"iss": "https://securityioet.b2clogin.com/%s/v2.0/" % fake.uuid4(),
193-
"oid": fake.uuid4(),
165+
"iss": "https://securityioet.b2clogin.com/%s/v2.0/" % tenant_id,
166+
"oid": owner_id,
194167
'exp': expiration_time
195168
}, key=get_or_generate_dev_secret_key()).decode("UTF-8")
196169

tests/time_tracker_api/activities/activities_namespace_test.py

Lines changed: 69 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
from flask_restplus._http import HTTPStatus
55
from pytest_mock import MockFixture
66

7-
from time_tracker_api.security import current_user_tenant_id
8-
97
fake = Faker()
108

119
valid_activity_data = {
@@ -36,34 +34,45 @@ def test_create_activity_should_succeed_with_valid_request(client: FlaskClient,
3634
repository_create_mock.assert_called_once()
3735

3836

39-
def test_create_activity_should_reject_bad_request(client: FlaskClient, mocker: MockFixture):
37+
def test_create_activity_should_reject_bad_request(client: FlaskClient,
38+
mocker: MockFixture,
39+
valid_header: dict):
4040
from time_tracker_api.activities.activities_namespace import activity_dao
4141
repository_create_mock = mocker.patch.object(activity_dao.repository,
4242
'create',
4343
return_value=fake_activity)
4444

45-
response = client.post("/activities", json=None, follow_redirects=True)
45+
response = client.post("/activities",
46+
headers=valid_header,
47+
json=None,
48+
follow_redirects=True)
4649

4750
assert HTTPStatus.BAD_REQUEST == response.status_code
4851
repository_create_mock.assert_not_called()
4952

5053

51-
def test_list_all_activities(client: FlaskClient, mocker: MockFixture):
54+
def test_list_all_activities(client: FlaskClient,
55+
mocker: MockFixture,
56+
tenant_id: str,
57+
valid_header: dict):
5258
from time_tracker_api.activities.activities_namespace import activity_dao
5359
repository_find_all_mock = mocker.patch.object(activity_dao.repository,
5460
'find_all',
5561
return_value=[])
5662

57-
response = client.get("/activities", follow_redirects=True)
63+
response = client.get("/activities",
64+
headers=valid_header,
65+
follow_redirects=True)
5866

5967
assert HTTPStatus.OK == response.status_code
6068
json_data = json.loads(response.data)
6169
assert [] == json_data
62-
repository_find_all_mock.assert_called_once()
70+
repository_find_all_mock.assert_called_once_with(partition_key_value=tenant_id)
6371

6472

6573
def test_get_activity_should_succeed_with_valid_id(client: FlaskClient,
6674
mocker: MockFixture,
75+
tenant_id: str,
6776
valid_header: dict):
6877
from time_tracker_api.activities.activities_namespace import activity_dao
6978

@@ -79,12 +88,12 @@ def test_get_activity_should_succeed_with_valid_id(client: FlaskClient,
7988

8089
assert HTTPStatus.OK == response.status_code
8190
fake_activity == json.loads(response.data)
82-
repository_find_mock.assert_called_once_with(str(valid_id),
83-
partition_key_value=current_user_tenant_id())
91+
repository_find_mock.assert_called_once_with(str(valid_id), partition_key_value=tenant_id)
8492

8593

8694
def test_get_activity_should_return_not_found_with_invalid_id(client: FlaskClient,
8795
mocker: MockFixture,
96+
tenant_id: str,
8897
valid_header: dict):
8998
from time_tracker_api.activities.activities_namespace import activity_dao
9099
from werkzeug.exceptions import NotFound
@@ -101,10 +110,11 @@ def test_get_activity_should_return_not_found_with_invalid_id(client: FlaskClien
101110

102111
assert HTTPStatus.NOT_FOUND == response.status_code
103112
repository_find_mock.assert_called_once_with(str(invalid_id),
104-
partition_key_value=current_user_tenant_id())
113+
partition_key_value=tenant_id)
105114

106115

107-
def test_get_activity_should_return_422_for_invalid_id_format(client: FlaskClient, mocker: MockFixture):
116+
def test_get_activity_should_return_422_for_invalid_id_format(client: FlaskClient,
117+
mocker: MockFixture):
108118
from time_tracker_api.activities.activities_namespace import activity_dao
109119
from werkzeug.exceptions import UnprocessableEntity
110120

@@ -117,41 +127,54 @@ def test_get_activity_should_return_422_for_invalid_id_format(client: FlaskClien
117127
response = client.get("/activities/%s" % invalid_id, follow_redirects=True)
118128

119129
assert HTTPStatus.UNPROCESSABLE_ENTITY == response.status_code
120-
repository_find_mock.assert_called_once_with(str(invalid_id),
121-
partition_key_value=current_user_tenant_id())
130+
repository_find_mock.assert_not_called()
122131

123132

124-
def test_update_activity_should_succeed_with_valid_data(client: FlaskClient, mocker: MockFixture):
133+
def test_update_activity_should_succeed_with_valid_data(client: FlaskClient,
134+
tenant_id: str,
135+
mocker: MockFixture,
136+
valid_header: dict):
125137
from time_tracker_api.activities.activities_namespace import activity_dao
126138

127139
repository_update_mock = mocker.patch.object(activity_dao.repository,
128140
'partial_update',
129141
return_value=fake_activity)
130142

131-
valid_id = fake.random_int(1, 9999)
132-
response = client.put("/activities/%s" % valid_id, json=valid_activity_data, follow_redirects=True)
143+
valid_id = fake.uuid4()
144+
response = client.put("/activities/%s" % valid_id,
145+
headers=valid_header,
146+
json=valid_activity_data,
147+
follow_redirects=True)
133148

134149
assert HTTPStatus.OK == response.status_code
135150
fake_activity == json.loads(response.data)
136151
repository_update_mock.assert_called_once_with(str(valid_id),
137152
changes=valid_activity_data,
138-
partition_key_value=current_user_tenant_id())
153+
partition_key_value=tenant_id)
139154

140155

141-
def test_update_activity_should_reject_bad_request(client: FlaskClient, mocker: MockFixture):
156+
def test_update_activity_should_reject_bad_request(client: FlaskClient,
157+
mocker: MockFixture,
158+
valid_header: dict):
142159
from time_tracker_api.activities.activities_namespace import activity_dao
143160
repository_update_mock = mocker.patch.object(activity_dao.repository,
144161
'partial_update',
145162
return_value=fake_activity)
146163

147164
valid_id = fake.random_int(1, 9999)
148-
response = client.put("/activities/%s" % valid_id, json=None, follow_redirects=True)
165+
response = client.put("/activities/%s" % valid_id,
166+
headers=valid_header,
167+
json=None,
168+
follow_redirects=True)
149169

150170
assert HTTPStatus.BAD_REQUEST == response.status_code
151171
repository_update_mock.assert_not_called()
152172

153173

154-
def test_update_activity_should_return_not_found_with_invalid_id(client: FlaskClient, mocker: MockFixture):
174+
def test_update_activity_should_return_not_found_with_invalid_id(client: FlaskClient,
175+
tenant_id: str,
176+
mocker: MockFixture,
177+
valid_header: dict):
155178
from time_tracker_api.activities.activities_namespace import activity_dao
156179
from werkzeug.exceptions import NotFound
157180

@@ -162,16 +185,20 @@ def test_update_activity_should_return_not_found_with_invalid_id(client: FlaskCl
162185
side_effect=NotFound)
163186

164187
response = client.put("/activities/%s" % invalid_id,
188+
headers=valid_header,
165189
json=valid_activity_data,
166190
follow_redirects=True)
167191

168192
assert HTTPStatus.NOT_FOUND == response.status_code
169193
repository_update_mock.assert_called_once_with(str(invalid_id),
170194
changes=valid_activity_data,
171-
partition_key_value=current_user_tenant_id())
195+
partition_key_value=tenant_id)
172196

173197

174-
def test_delete_activity_should_succeed_with_valid_id(client: FlaskClient, mocker: MockFixture):
198+
def test_delete_activity_should_succeed_with_valid_id(client: FlaskClient,
199+
mocker: MockFixture,
200+
tenant_id: str,
201+
valid_header: dict):
175202
from time_tracker_api.activities.activities_namespace import activity_dao
176203

177204
valid_id = fake.random_int(1, 9999)
@@ -180,15 +207,20 @@ def test_delete_activity_should_succeed_with_valid_id(client: FlaskClient, mocke
180207
'delete',
181208
return_value=None)
182209

183-
response = client.delete("/activities/%s" % valid_id, follow_redirects=True)
210+
response = client.delete("/activities/%s" % valid_id,
211+
headers=valid_header,
212+
follow_redirects=True)
184213

185214
assert HTTPStatus.NO_CONTENT == response.status_code
186215
assert b'' == response.data
187216
repository_remove_mock.assert_called_once_with(str(valid_id),
188-
partition_key_value=current_user_tenant_id())
217+
partition_key_value=tenant_id)
189218

190219

191-
def test_delete_activity_should_return_not_found_with_invalid_id(client: FlaskClient, mocker: MockFixture):
220+
def test_delete_activity_should_return_not_found_with_invalid_id(client: FlaskClient,
221+
mocker: MockFixture,
222+
tenant_id: str,
223+
valid_header: dict):
192224
from time_tracker_api.activities.activities_namespace import activity_dao
193225
from werkzeug.exceptions import NotFound
194226

@@ -198,14 +230,19 @@ def test_delete_activity_should_return_not_found_with_invalid_id(client: FlaskCl
198230
'delete',
199231
side_effect=NotFound)
200232

201-
response = client.delete("/activities/%s" % invalid_id, follow_redirects=True)
233+
response = client.delete("/activities/%s" % invalid_id,
234+
headers=valid_header,
235+
follow_redirects=True)
202236

203237
assert HTTPStatus.NOT_FOUND == response.status_code
204238
repository_remove_mock.assert_called_once_with(str(invalid_id),
205-
partition_key_value=current_user_tenant_id())
239+
partition_key_value=tenant_id)
206240

207241

208-
def test_delete_activity_should_return_422_for_invalid_id_format(client: FlaskClient, mocker: MockFixture):
242+
def test_delete_activity_should_return_422_for_invalid_id_format(client: FlaskClient,
243+
mocker: MockFixture,
244+
tenant_id: str,
245+
valid_header: dict):
209246
from time_tracker_api.activities.activities_namespace import activity_dao
210247
from werkzeug.exceptions import UnprocessableEntity
211248

@@ -215,8 +252,10 @@ def test_delete_activity_should_return_422_for_invalid_id_format(client: FlaskCl
215252
'delete',
216253
side_effect=UnprocessableEntity)
217254

218-
response = client.delete("/activities/%s" % invalid_id, follow_redirects=True)
255+
response = client.delete("/activities/%s" % invalid_id,
256+
headers=valid_header,
257+
follow_redirects=True)
219258

220259
assert HTTPStatus.UNPROCESSABLE_ENTITY == response.status_code
221260
repository_remove_mock.assert_called_once_with(str(invalid_id),
222-
partition_key_value=current_user_tenant_id())
261+
partition_key_value=tenant_id)

0 commit comments

Comments
 (0)