Skip to content

Commit 10ec2bb

Browse files
ararcosJobzi
andauthored
feat: TT-417-crud-v2-projects (#360)
* feat: TT-417 created CRUD project * test: TT-417 add test with customer id * refactor: TT-417 created enums and use * test: TT-417 add missing tests and resolve comments * refactor: TT-417 add HTTPStatus from http * refactor: TT-417 test name correction Co-authored-by: Jipson Murillo <[email protected]>
1 parent 48f6411 commit 10ec2bb

30 files changed

+1066
-4
lines changed

V2/serverless.yml

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ functions:
9797
route: time-entries/{id}
9898
authLevel: anonymous
9999

100-
101100
update_time_entry:
102101
handler: time_tracker/time_entries/interface.update_time_entry
103102
events:
@@ -117,4 +116,43 @@ functions:
117116
- POST
118117
route: customers/
119118
authLevel: anonymous
120-
119+
120+
get_projects:
121+
handler: time_tracker/projects/interface.get_projects
122+
events:
123+
- http: true
124+
x-azure-settings:
125+
methods:
126+
- GET
127+
route: projects/{id:?}
128+
authLevel: anonymous
129+
130+
delete_project:
131+
handler: time_tracker/projects/interface.delete_project
132+
events:
133+
- http: true
134+
x-azure-settings:
135+
methods:
136+
- DELETE
137+
route: projects/{id}
138+
authLevel: anonymous
139+
140+
update_project:
141+
handler: time_tracker/projects/interface.update_project
142+
events:
143+
- http: true
144+
x-azure-settings:
145+
methods:
146+
- PUT
147+
route: projects/{id}
148+
authLevel: anonymous
149+
150+
create_project:
151+
handler: time_tracker/projects/interface.create_project
152+
events:
153+
- http: true
154+
x-azure-settings:
155+
methods:
156+
- POST
157+
route: projects/
158+
authLevel: anonymous
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
import json
2+
from http import HTTPStatus
3+
4+
import pytest
5+
from faker import Faker
6+
import azure.functions as func
7+
8+
from time_tracker.projects._application import _projects as azure_projects
9+
from time_tracker.projects import _domain as domain
10+
from time_tracker.projects import _infrastructure as infrastructure
11+
12+
PROJECT_URL = '/api/projects/'
13+
14+
15+
@pytest.fixture(name='insert_project')
16+
def _insert_project(test_db, insert_customer, project_factory, customer_factory) -> domain.Project:
17+
inserted_customer = insert_customer(customer_factory(), test_db)
18+
19+
def _new_project():
20+
project_to_insert = project_factory(customer_id=inserted_customer.id)
21+
dao = infrastructure.ProjectsSQLDao(test_db)
22+
inserted_project = dao.create(project_to_insert)
23+
return inserted_project
24+
return _new_project
25+
26+
27+
def test__project_azure_endpoint__returns_all_projects(
28+
insert_project
29+
):
30+
inserted_projects = [
31+
insert_project().__dict__,
32+
insert_project().__dict__
33+
]
34+
35+
req = func.HttpRequest(method='GET', body=None, url=PROJECT_URL)
36+
response = azure_projects._get_projects.get_projects(req)
37+
projects_json_data = response.get_body().decode("utf-8")
38+
39+
assert response.status_code == HTTPStatus.OK
40+
assert projects_json_data == json.dumps(inserted_projects)
41+
42+
43+
def test__project_azure_endpoint__returns_a_project__when_project_matches_its_id(
44+
insert_project
45+
):
46+
inserted_project = insert_project().__dict__
47+
48+
req = func.HttpRequest(
49+
method='GET',
50+
body=None,
51+
url=PROJECT_URL,
52+
route_params={"id": inserted_project["id"]},
53+
)
54+
55+
response = azure_projects._get_projects.get_projects(req)
56+
activitiy_json_data = response.get_body().decode("utf-8")
57+
58+
assert response.status_code == HTTPStatus.OK
59+
assert activitiy_json_data == json.dumps(inserted_project)
60+
61+
62+
def test__projects_azure_endpoint__returns_a_status_code_400__when_project_receive_invalid_id(
63+
):
64+
req = func.HttpRequest(
65+
method="GET",
66+
body=None,
67+
url=PROJECT_URL,
68+
route_params={"id": "invalid id"},
69+
)
70+
71+
response = azure_projects._get_projects.get_projects(req)
72+
73+
assert response.status_code == HTTPStatus.BAD_REQUEST
74+
assert response.get_body() == b"Invalid Format ID"
75+
76+
77+
def test__project_azure_endpoint__returns_a_project_with_inactive_status__when_a_project_matching_its_id_is_found(
78+
insert_project
79+
):
80+
inserted_project = insert_project().__dict__
81+
82+
req = func.HttpRequest(
83+
method='DELETE',
84+
body=None,
85+
url=PROJECT_URL,
86+
route_params={"id": inserted_project["id"]},
87+
)
88+
89+
response = azure_projects._delete_project.delete_project(req)
90+
project_json_data = json.loads(response.get_body().decode("utf-8"))
91+
92+
assert response.status_code == HTTPStatus.OK
93+
assert project_json_data['status'] == 0
94+
assert project_json_data['deleted'] is True
95+
96+
97+
def test__delete_projects_azure_endpoint__returns_a_status_code_400__when_project_receive_invalid_id(
98+
):
99+
req = func.HttpRequest(
100+
method="DELETE",
101+
body=None,
102+
url=PROJECT_URL,
103+
route_params={"id": "invalid id"},
104+
)
105+
106+
response = azure_projects._delete_project.delete_project(req)
107+
108+
assert response.status_code == HTTPStatus.BAD_REQUEST
109+
assert response.get_body() == b"Invalid Format ID"
110+
111+
112+
def test__delete_projects_azure_endpoint__returns_a_status_code_404__when_no_found_a_project_to_delete(
113+
):
114+
req = func.HttpRequest(
115+
method="DELETE",
116+
body=None,
117+
url=PROJECT_URL,
118+
route_params={"id": Faker().pyint()},
119+
)
120+
121+
response = azure_projects._delete_project.delete_project(req)
122+
123+
assert response.status_code == HTTPStatus.NOT_FOUND
124+
assert response.get_body() == b"Not found"
125+
126+
127+
def test__update_project_azure_endpoint__returns_a_project__when_found_a_project_to_update(
128+
insert_project
129+
):
130+
inserted_project = insert_project().__dict__
131+
132+
project_body = {"description": Faker().sentence()}
133+
req = func.HttpRequest(
134+
method='PUT',
135+
body=json.dumps(project_body).encode("utf-8"),
136+
url=PROJECT_URL,
137+
route_params={"id": inserted_project["id"]},
138+
)
139+
140+
response = azure_projects._update_project.update_project(req)
141+
activitiy_json_data = response.get_body().decode("utf-8")
142+
inserted_project.update(project_body)
143+
144+
assert response.status_code == HTTPStatus.OK
145+
assert activitiy_json_data == json.dumps(inserted_project)
146+
147+
148+
def test__update_projects_azure_endpoint__returns_a_status_code_404__when_no_found_a_project_to_update(
149+
project_factory
150+
):
151+
project_body = project_factory().__dict__
152+
153+
req = func.HttpRequest(
154+
method="PUT",
155+
body=json.dumps(project_body).encode("utf-8"),
156+
url=PROJECT_URL,
157+
route_params={"id": project_body["id"]},
158+
)
159+
160+
response = azure_projects._update_project.update_project(req)
161+
162+
assert response.status_code == HTTPStatus.NOT_FOUND
163+
assert response.get_body() == b"Not found"
164+
165+
166+
def test__update_projects_azure_endpoint__returns_a_status_code_400__when_receive_an_incorrect_body(
167+
):
168+
project_body = Faker().pydict(5, True, str)
169+
req = func.HttpRequest(
170+
method="PUT",
171+
body=json.dumps(project_body).encode("utf-8"),
172+
url=PROJECT_URL,
173+
route_params={"id": Faker().pyint()},
174+
)
175+
176+
response = azure_projects._update_project.update_project(req)
177+
178+
assert response.status_code == HTTPStatus.BAD_REQUEST
179+
assert response.get_body() == b"Incorrect body"
180+
181+
182+
def test__update_projects_azure_endpoint__returns_a_status_code_400__when_project_receive_invalid_id(
183+
):
184+
req = func.HttpRequest(
185+
method="PUT",
186+
body=None,
187+
url=PROJECT_URL,
188+
route_params={"id": "invalid id"},
189+
)
190+
191+
response = azure_projects._update_project.update_project(req)
192+
193+
assert response.status_code == HTTPStatus.BAD_REQUEST
194+
assert response.get_body() == b"Invalid Format ID"
195+
196+
197+
def test__project_azure_endpoint__creates_a_project__when_project_has_all_attributes(
198+
test_db, project_factory, insert_customer, customer_factory
199+
):
200+
inserted = insert_customer(customer_factory(), test_db)
201+
project_body = project_factory(inserted.id).__dict__
202+
203+
req = func.HttpRequest(
204+
method='POST',
205+
body=json.dumps(project_body).encode("utf-8"),
206+
url=PROJECT_URL,
207+
)
208+
209+
response = azure_projects._create_project.create_project(req)
210+
project_json_data = json.loads(response.get_body())
211+
project_body['id'] = project_json_data['id']
212+
213+
assert response.status_code == HTTPStatus.CREATED
214+
assert project_json_data == project_body
215+
216+
217+
def test__project_azure_endpoint__returns_a_status_code_400__when_project_does_not_all_attributes(
218+
test_db, project_factory, insert_customer, customer_factory
219+
):
220+
inserted_customer = insert_customer(customer_factory(), test_db)
221+
project_body = project_factory(customer_id=inserted_customer.id).__dict__
222+
project_body.pop('name')
223+
224+
req = func.HttpRequest(
225+
method='POST',
226+
body=json.dumps(project_body).encode("utf-8"),
227+
url=PROJECT_URL,
228+
)
229+
230+
response = azure_projects._create_project.create_project(req)
231+
232+
assert response.status_code == HTTPStatus.BAD_REQUEST
233+
assert response.get_body() == json.dumps(['The name key is missing in the input data']).encode()
234+
235+
236+
def test__project_azure_endpoint__returns_a_status_code_500__when_project_receive_incorrect_type_data(
237+
project_factory, insert_customer, customer_factory, test_db
238+
):
239+
insert_customer(customer_factory(), test_db)
240+
project_body = project_factory(technologies=Faker().pylist(2, True, str)).__dict__
241+
242+
req = func.HttpRequest(
243+
method='POST',
244+
body=json.dumps(project_body).encode("utf-8"),
245+
url=PROJECT_URL,
246+
)
247+
248+
response = azure_projects._create_project.create_project(req)
249+
250+
assert response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
251+
assert response.get_body() == b"could not be created"

V2/tests/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# flake8: noqa
22
from fixtures import _activity_factory, _test_db, _insert_activity
33
from fixtures import _time_entry_factory
4-
from fixtures import _customer_factory
4+
from fixtures import _customer_factory, _insert_customer
5+
from fixtures import _project_factory

V2/tests/fixtures.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
from faker import Faker
33

44
import time_tracker.activities._domain as activities_domain
5+
import time_tracker.activities._infrastructure as activities_infrastructure
56
import time_tracker.time_entries._domain as time_entries_domain
67
import time_tracker.customers._domain as customers_domain
7-
import time_tracker.activities._infrastructure as activities_infrastructure
8+
import time_tracker.customers._infrastructure as customers_infrastructure
9+
import time_tracker.projects._domain as projects_domain
810
from time_tracker._infrastructure import DB
911

1012

@@ -94,3 +96,38 @@ def _make_customer(
9496
return customer
9597

9698
return _make_customer
99+
100+
101+
@pytest.fixture(name='project_factory')
102+
def _project_factory() -> projects_domain.Project:
103+
def _make_project(
104+
id=Faker().pyint(),
105+
name=Faker().name(),
106+
description=Faker().sentence(),
107+
project_type_id=Faker().pyint(),
108+
customer_id=Faker().pyint(),
109+
status=Faker().pyint(),
110+
deleted=False,
111+
technologies=str(Faker().pylist())
112+
):
113+
project = projects_domain.Project(
114+
id=id,
115+
name=name,
116+
description=description,
117+
project_type_id=project_type_id,
118+
customer_id=customer_id,
119+
status=status,
120+
deleted=deleted,
121+
technologies=technologies
122+
)
123+
return project
124+
return _make_project
125+
126+
127+
@pytest.fixture(name='insert_customer')
128+
def _insert_customer() -> customers_domain.Customer:
129+
def _new_customer(customer: customers_domain.Customer, database: DB):
130+
dao = customers_infrastructure.CustomersSQLDao(database)
131+
new_customer = dao.create(customer)
132+
return new_customer
133+
return _new_customer

0 commit comments

Comments
 (0)