Skip to content

Commit d6c4c4d

Browse files
authored
feat: TT-418 CRUD customer v2 (#359)
* feat: TT-418 create added * feat: TT-418 create tests added * fix: TT-418 problems solved
1 parent 6de0063 commit d6c4c4d

File tree

23 files changed

+312
-1
lines changed

23 files changed

+312
-1
lines changed

V2/serverless.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,13 @@ functions:
9696
- DELETE
9797
route: time-entries/{id}
9898
authLevel: anonymous
99+
100+
create_customer:
101+
handler: time_tracker/customers/interface.create_customer
102+
events:
103+
- http: true
104+
x-azure-settings:
105+
methods:
106+
- POST
107+
route: customers/
108+
authLevel: anonymous
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import json
2+
from faker import Faker
3+
4+
import azure.functions as func
5+
6+
import time_tracker.customers._application._customers as azure_customers
7+
8+
CUSTOMER_URL = "/api/customers/"
9+
10+
11+
def test__customer_azure_endpoint__creates_a_customer__when_customer_has_all_necesary_attributes(
12+
customer_factory
13+
):
14+
customer_body = customer_factory().__dict__
15+
16+
body = json.dumps(customer_body).encode("utf-8")
17+
req = func.HttpRequest(
18+
method='POST',
19+
body=body,
20+
url=CUSTOMER_URL,
21+
)
22+
23+
response = azure_customers._create_customer.create_customer(req)
24+
customer_json_data = json.loads(response.get_body())
25+
customer_body['id'] = customer_json_data['id']
26+
27+
assert response.status_code == 201
28+
assert customer_json_data == customer_body
29+
30+
31+
def test__customer_azure_endpoint__returns_a_status_400__when_dont_recieve_all_necessary_attributes():
32+
customer_to_insert = {
33+
"id": None,
34+
"name": Faker().user_name(),
35+
"deleted": False,
36+
"status": 1
37+
}
38+
39+
body = json.dumps(customer_to_insert).encode("utf-8")
40+
req = func.HttpRequest(
41+
method='POST',
42+
body=body,
43+
url=CUSTOMER_URL,
44+
)
45+
46+
response = azure_customers._create_customer.create_customer(req)
47+
48+
assert response.status_code == 400
49+
assert response.get_body() == b'Invalid format or structure of the attributes of the customer'

V2/tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
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

V2/tests/fixtures.py

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

44
import time_tracker.activities._domain as activities_domain
5-
import time_tracker.activities._infrastructure as activities_infrastructure
65
import time_tracker.time_entries._domain as time_entries_domain
6+
import time_tracker.customers._domain as customers_domain
7+
import time_tracker.activities._infrastructure as activities_infrastructure
78
from time_tracker._infrastructure import DB
89

910

@@ -73,3 +74,23 @@ def _new_activity(activity: activities_domain.Activity, database: DB):
7374
new_activity = dao.create(activity)
7475
return new_activity
7576
return _new_activity
77+
78+
79+
@pytest.fixture(name='customer_factory')
80+
def _customer_factory() -> customers_domain.Customer:
81+
def _make_customer(
82+
name: str = Faker().name(),
83+
description: str = Faker().sentence(),
84+
deleted: bool = False,
85+
status: int = 1,
86+
):
87+
customer = customers_domain.Customer(
88+
id=None,
89+
name=name,
90+
description=description,
91+
deleted=deleted,
92+
status=status
93+
)
94+
return customer
95+
96+
return _make_customer
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import pytest
2+
3+
import time_tracker.customers._domain as domain
4+
import time_tracker.customers._infrastructure as infrastructure
5+
from time_tracker._infrastructure import DB
6+
7+
8+
@pytest.fixture(name='create_fake_dao')
9+
def _fake_dao() -> domain.CustomersDao:
10+
def _create_fake_dao(db_fake: DB) -> domain.CustomersDao:
11+
dao = infrastructure.CustomersSQLDao(db_fake)
12+
return dao
13+
return _create_fake_dao
14+
15+
16+
@pytest.fixture(name='clean_database', autouse=True)
17+
def _clean_database():
18+
yield
19+
db_fake = DB()
20+
dao = infrastructure.CustomersSQLDao(db_fake)
21+
query = dao.customer.delete()
22+
dao.db.get_session().execute(query)
23+
24+
25+
def test__customer_dao__returns_a_customer_dto__when_saves_correctly_with_sql_database(
26+
test_db, customer_factory, create_fake_dao
27+
):
28+
dao = create_fake_dao(test_db)
29+
30+
customer_to_insert = customer_factory()
31+
32+
inserted_customer = dao.create(customer_to_insert)
33+
34+
assert isinstance(inserted_customer, domain.Customer)
35+
assert inserted_customer == customer_to_insert
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from time_tracker.customers._domain import CustomerService
2+
3+
4+
def test__create_customer__uses_the_customer_dao__to_create_a_customer(mocker, customer_factory):
5+
expected_customer = mocker.Mock()
6+
customer_dao = mocker.Mock(
7+
create=mocker.Mock(return_value=expected_customer)
8+
)
9+
customer_service = CustomerService(customer_dao)
10+
11+
new_customer = customer_service.create(customer_factory())
12+
13+
assert customer_dao.create.called
14+
assert expected_customer == new_customer
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from pytest_mock import MockFixture
2+
3+
from time_tracker.customers._domain import _use_cases
4+
5+
6+
def test__create_customer_function__uses_the_customer_service__to_create_a_customer(
7+
mocker: MockFixture, customer_factory
8+
):
9+
expected_customer = mocker.Mock()
10+
customer_service = mocker.Mock(
11+
create=mocker.Mock(return_value=expected_customer)
12+
)
13+
14+
customer_use_case = _use_cases.CreateCustomerUseCase(customer_service)
15+
new_customer = customer_use_case.create_customer(customer_factory())
16+
17+
assert customer_service.create.called
18+
assert expected_customer == new_customer
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# flake8: noqa
2+
from ._customers import create_customer
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# flake8: noqa
2+
from ._create_customer import create_customer
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import dataclasses
2+
import json
3+
import typing
4+
5+
import azure.functions as func
6+
7+
from ... import _domain
8+
from ... import _infrastructure
9+
from time_tracker._infrastructure import DB
10+
11+
12+
def create_customer(req: func.HttpRequest) -> func.HttpResponse:
13+
try:
14+
database = DB()
15+
customer_dao = _infrastructure.CustomersSQLDao(database)
16+
customer_service = _domain.CustomerService(customer_dao)
17+
use_case = _domain._use_cases.CreateCustomerUseCase(customer_service)
18+
customer_data = req.get_json()
19+
20+
customer_is_valid = _validate_customer(customer_data)
21+
if not customer_is_valid:
22+
raise ValueError
23+
24+
customer_to_create = _domain.Customer(
25+
id=None,
26+
deleted=None,
27+
status=None,
28+
name=str(customer_data["name"]).strip(),
29+
description=str(customer_data["description"]),
30+
)
31+
created_customer = use_case.create_customer(customer_to_create)
32+
33+
if created_customer:
34+
body = json.dumps(created_customer.__dict__)
35+
status_code = 201
36+
else:
37+
body = b'This customer already exists'
38+
status_code = 409
39+
40+
return func.HttpResponse(
41+
body=body,
42+
status_code=status_code,
43+
mimetype="application/json"
44+
)
45+
except ValueError:
46+
return func.HttpResponse(
47+
body=b'Invalid format or structure of the attributes of the customer',
48+
status_code=400,
49+
mimetype="application/json"
50+
)
51+
52+
53+
def _validate_customer(customer_data: dict) -> bool:
54+
if [field.name for field in dataclasses.fields(_domain.Customer)
55+
if (field.name not in customer_data) and (field.type != typing.Optional[field.type])]:
56+
return False
57+
return True

0 commit comments

Comments
 (0)