Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add core tests #138

Merged
merged 98 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
20e5709
🤡 fakers: add base
JohnPetros Jun 30, 2024
2bd2d7c
🤡 fakers: add plants
JohnPetros Jun 30, 2024
81221e8
🤡 fakers: add users
JohnPetros Jun 30, 2024
d664a4c
📑 interfaces: add users repository
JohnPetros Jun 30, 2024
3f36be6
📑 interfaces: add plants repository
JohnPetros Jun 30, 2024
1c5dd2f
🏭 factories: add update active plant
JohnPetros Jun 30, 2024
0b7493b
🏭 factories: add filters plants use case
JohnPetros Jun 30, 2024
bd76465
🏭 factories: add create plant by form use case
JohnPetros Jun 30, 2024
59cb64b
🏭 factories: add delete plant use case
JohnPetros Jun 30, 2024
b7ca8bf
🏭 factories: add get plant by id factory use case
JohnPetros Jun 30, 2024
12c1838
🏭 factories: add get plants page data use case
JohnPetros Jun 30, 2024
6f236b2
🏭 factories: add update plant use case
JohnPetros Jun 30, 2024
5193794
🤡 mocks: add plants repository
JohnPetros Jun 30, 2024
3152644
🤡 mocks: add users repositories
JohnPetros Jun 30, 2024
816ed3b
🧪 tests: update active plant
JohnPetros Jun 30, 2024
cd65961
🧪 tests: create plant by form use case
JohnPetros Jun 30, 2024
fdb9077
🧪 tests: get plants page data use case
JohnPetros Jun 30, 2024
ab2a550
🧪 tests: delete plant use case
JohnPetros Jun 30, 2024
e5d1bd2
🧪 tests: update plant use case
JohnPetros Jun 30, 2024
bcb9273
🧪 tests: filter plants use case
JohnPetros Jun 30, 2024
f849c46
🧪 tests: get plant by id use case
JohnPetros Jun 30, 2024
2905cb4
🚨 errors: pass ui message to super error
JohnPetros Jun 30, 2024
439b172
♻️ refactor: use factory pattern upon plants use cases
JohnPetros Jun 30, 2024
95002c3
🚨 errors: add base error
JohnPetros Jul 1, 2024
a8f3688
🚨 errors: add email template not provided error
JohnPetros Jul 1, 2024
d71e16b
🚨 errors: incorrect admin user email error
JohnPetros Jul 1, 2024
fa44d26
🚨 errors: add sender password not provided error
JohnPetros Jul 1, 2024
745050d
🚨 errors: add user email not provided error
JohnPetros Jul 1, 2024
a0c8ef1
📑 providers: add email provider
JohnPetros Jul 1, 2024
dd399cd
📑 interfaces: add auth
JohnPetros Jul 1, 2024
c5e3150
🏭 factories: add auth
JohnPetros Jul 1, 2024
485b793
🤡 mocks: add auth
JohnPetros Jul 1, 2024
0d58fbb
🤡 mocks: add email provider
JohnPetros Jul 1, 2024
ce9a065
🧪 tests: login user
JohnPetros Jul 1, 2024
786795b
🧪 tests: reset password use case
JohnPetros Jul 1, 2024
e51de26
🧪 tests: request password reset use case
JohnPetros Jul 1, 2024
b41bbd6
♻️ refactor: all custom errors implamentations and usage
JohnPetros Jul 1, 2024
528d0f5
🧪 tests: weekday common
JohnPetros Jul 1, 2024
1c728ff
🧪 tests: csv file common
JohnPetros Jul 1, 2024
ae235f2
🧪 tests: date common
JohnPetros Jul 1, 2024
04f7860
🧪 tests: days range common
JohnPetros Jul 1, 2024
bb0e732
🧪 tests: weekday common
JohnPetros Jul 1, 2024
b61a4fd
🚨 errors: add datime not valid error
JohnPetros Jul 1, 2024
1b1854c
🚨 errors: add date not valid error
JohnPetros Jul 1, 2024
39b77cb
🧪 tests: ordered plants common
JohnPetros Jul 1, 2024
fa81fc2
🧪 tests: records filters common
JohnPetros Jul 1, 2024
896b9ed
🧪 tests: datetime common
JohnPetros Jul 1, 2024
275f813
📑 interfaces: add data analyser provider
JohnPetros Jul 1, 2024
d42222a
🚨 errors: add csv file validation
JohnPetros Jul 1, 2024
67f31f7
👥 entities: add line chart record
JohnPetros Jul 1, 2024
343323a
🥸 fakers: add sensors records
JohnPetros Jul 1, 2024
ac83f1b
🥸 fakers: add line chart records
JohnPetros Jul 1, 2024
e224de1
🧪 tests: line chart common
JohnPetros Jul 1, 2024
d7f02e6
📦 deps: install dependencies for tests
JohnPetros Jul 3, 2024
9c9a6e5
⚙️ config: set env vars for test enviroment
JohnPetros Jul 3, 2024
a274b8e
🧩 commons: enhance date and datime validation
JohnPetros Jul 3, 2024
e3b670d
🚨 errors: add for sensors records
JohnPetros Jul 3, 2024
96a1dd5
🏷️ types: add hints for each attribute of error classes
JohnPetros Jul 3, 2024
72c032c
🧩 commons: use date value on set records filters
JohnPetros Jul 3, 2024
bbb48b0
💾 database: prevent mysql from starting under test enviroment
JohnPetros Jul 3, 2024
b507776
🤡 mocks: add sensors records repository
JohnPetros Jul 3, 2024
7ca83ed
📑 interfaces: add sensors records repository
JohnPetros Jul 3, 2024
1e681e0
⚡perf: remove useless logs from app
JohnPetros Jul 3, 2024
414988e
🧪 tests: create sensors record by api use case
JohnPetros Jul 3, 2024
da9fdcd
🧪 tests: create sensors record by csv file use case
JohnPetros Jul 3, 2024
2a744d7
🧪 tests: create sensors records by form use case
JohnPetros Jul 3, 2024
0340b2d
🧪 tests: get sensors records dashboard page data use case
JohnPetros Jul 3, 2024
a0e3cfa
🧪 tests: delete sensors records use case
JohnPetros Jul 3, 2024
aeff5bf
🧪 tests: get sensors records csv file use case
JohnPetros Jul 3, 2024
0fdbb24
🧪 tests: get last record page data use case
JohnPetros Jul 3, 2024
82a7119
🧪 tests: ge sensors records csv file use case
JohnPetros Jul 3, 2024
2114afd
🏭 factories: add create sensors record by api use case
JohnPetros Jul 3, 2024
6900035
🏭 factories: add all sensors records use cases
JohnPetros Jul 3, 2024
322553b
🚨 errors: add page number
JohnPetros Jul 3, 2024
8aca9e5
🧪 tests: pagination common
JohnPetros Jul 3, 2024
77485c4
🐛 fix: sensors records use cases exportations
JohnPetros Jul 3, 2024
591049a
🧩 commons: get date on get records filters date values
JohnPetros Jul 4, 2024
450ce7c
🥸 fakers: add checklist records
JohnPetros Jul 4, 2024
0bec683
🚨 errors: add checklist record not valid
JohnPetros Jul 4, 2024
5f2192d
🚨 errors: add hour not valid
JohnPetros Jul 4, 2024
4329623
🚨 errors: add checklist record not found
JohnPetros Jul 4, 2024
e1145ee
📑 interfaces: add checklist records repository
JohnPetros Jul 4, 2024
3682e1b
🧪 tests: create checklist record by csv file use case
JohnPetros Jul 4, 2024
3287435
🧪 tests: create checklist record by csv form use case
JohnPetros Jul 4, 2024
759e2ad
🧪 tests: create delete checklist record use case
JohnPetros Jul 4, 2024
89d0116
🧪 tests: create get checklist records csv file use case
JohnPetros Jul 4, 2024
d57eb71
🧪 tests: get checklist records table page data use case
JohnPetros Jul 4, 2024
a0df5ee
🧪 tests: update checklist record use case
JohnPetros Jul 4, 2024
d4c4794
🤡 mocks: add checklist records repository
JohnPetros Jul 4, 2024
e2f09cf
🏭 factories: checklist records use cases
JohnPetros Jul 4, 2024
5f56493
🧪 tests: fix line chart common
JohnPetros Jul 4, 2024
eedde97
🏭 factories: sensors records use cases
JohnPetros Jul 4, 2024
0fbe344
🤡 mocks: add csv_file_attribute to data analyser provider
JohnPetros Jul 4, 2024
746808d
🚄 ci: run core tests on every push or pull request
JohnPetros Jul 4, 2024
a579065
🐛 fix: sensors records counting with filters
JohnPetros Jul 4, 2024
f122331
🐛 fix: delete many records using mysql conector
JohnPetros Jul 4, 2024
436b412
♻️ refactor: sensors records and checklist records views making them …
JohnPetros Jul 4, 2024
741e384
🤡 mocks: fix get sensors records count params of sensors records repo…
JohnPetros Jul 4, 2024
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
26 changes: 26 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Continuous Integration

on: [push, pull_request]

jobs:
CI:
name: Run core tests
runs-on: ubuntu-latest

steps:
- name: Init job
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.10.12
cache: 'pip'

- name: Install Python dependencies
run: pip install -r requirements.txt

- name: Run core tests
run: python -m pytest src/app/core


5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
[tool.ruff]
ignore = [
"F403" # undefined-names,
]

[tool.pytest.ini_options]
env = [
"ENVIRONMENT=test"
]
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ cowsay==6.1
dnspython==2.6.1
email_validator==2.1.1
et-xmlfile==1.1.0
exceptiongroup==1.2.1
Faker==26.0.0
Flask==3.0.2
Flask-APScheduler==1.13.1
Flask-Bcrypt==1.0.1
Expand All @@ -24,6 +26,7 @@ greenlet==3.0.3
gunicorn==22.0.0
httplib2==0.22.0
idna==3.7
iniconfig==2.0.0
itsdangerous==2.1.2
Jinja2==3.1.3
MarkupSafe==2.1.5
Expand All @@ -32,17 +35,22 @@ numpy==1.26.4
openpyxl==3.1.2
packaging==24.0
pandas==2.2.1
pluggy==1.5.0
proto-plus==1.23.0
protobuf==4.25.3
pyasn1==0.6.0
pyasn1_modules==0.4.0
pyparsing==3.1.2
pytest==8.2.2
pytest-describe==2.2.0
pytest-env==1.1.3
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
pytz==2024.1
requests==2.32.3
rsa==4.9
six==1.16.0
tomli==2.0.1
tzdata==2024.1
tzlocal==5.2
uritemplate==4.1.1
Expand Down
Empty file added src/app/core/__init__.py
Empty file.
38 changes: 22 additions & 16 deletions src/app/core/commons/csv_file.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,50 @@
from typing import Dict, List
from werkzeug.datastructures import FileStorage

from core.commons import Error

from infra.providers.data_analyser_provider import DataAnalyserProvider
from core.interfaces.providers import DataAnalyserProviderInterface
from core.errors.validation import CSVFileNotValidError, CSVColumnsNotValidError


class CsvFile:
def __init__(self, csv_file: FileStorage) -> None:
self.csv_file = csv_file
self.data_analyser_provider = DataAnalyserProvider()
def __init__(
self,
file: FileStorage,
data_analyser_provider: DataAnalyserProviderInterface,
):
if not isinstance(file, FileStorage):
raise CSVFileNotValidError()

self._file = file
self._data_analyser_provider = data_analyser_provider

def read(self):
extension = self.get_extension()
extension = self.__get_extension()

if extension in ["csv", "txt"]:
self.data_analyser_provider.read_csv(self.csv_file)
self._data_analyser_provider.read_csv(self._file)
elif extension == "xlsx":
self.data_analyser_provider.read_excel(self.csv_file)
self._data_analyser_provider.read_excel(self._file)
else:
raise Error("Arquivo CSV inválido")
raise CSVFileNotValidError()

def get_records(self) -> List[Dict]:
records = self.data_analyser_provider.convert_to_list_of_records()
records = self._data_analyser_provider.convert_to_list_of_records()

records_list = []
for record in records:
records_list.append({key.lower(): value for key, value in record.items()})

return records_list

def validate_columns(self, columns: List[str]) -> bool:
csv_columns = self.data_analyser_provider.get_columns()
def validate_columns(self, columns: List[str]):
csv_columns = self._data_analyser_provider.get_columns()

has_valid_columns = set(map(lambda x: x.lower(), csv_columns)) == set(
map(lambda x: x.lower(), columns)
)

if not has_valid_columns:
raise Error("As colunas do arquivo CSV não estão corretas")
raise CSVColumnsNotValidError()

def get_extension(self) -> str:
return self.csv_file.filename.split(".")[1]
def __get_extension(self) -> str:
return self._file.filename.split(".")[1]
8 changes: 5 additions & 3 deletions src/app/core/commons/date.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import date, datetime

from core.commons import Error
from core.errors.validation import DateNotValidError


class Date:
Expand All @@ -14,10 +14,12 @@ def __init__(self, value: date):

self.value = value
except Exception:
raise Error("Valor de data inválido")
raise DateNotValidError

def format_value(self):
self.value = self.value.strftime("%d/%m/%Y")
if isinstance(self.value, date):
self.value = self.value.strftime("%d/%m/%Y")

return self

def get_value(self, is_date: bool = False) -> str:
Expand Down
16 changes: 13 additions & 3 deletions src/app/core/commons/datetime.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
from datetime import datetime, time

from core.errors.validation import DatetimeNotValidError


class Datetime:
value: datetime

def __init__(self, value: datetime):
if not isinstance(value, datetime):
raise DatetimeNotValidError()

self.value = value

def format_value(self):
self.value = self.value.strftime("%d/%m/%Y %H:%M")
if isinstance(self.value, datetime):
self.value = self.value.strftime("%d/%m/%Y %H:%M")

return self

def get_time(self) -> time:
def get_time(self):
if isinstance(self.value, str):
return datetime.strptime(self.value, "%d/%m/%Y %H:%M").time()

return time(
hour=self.value.hour,
minute=self.value.minute,
)

def get_value(self, is_datetime: bool = False) -> str:
def get_value(self, is_datetime: bool = False):
if is_datetime:
return self.value

Expand Down
2 changes: 2 additions & 0 deletions src/app/core/commons/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ def __init__(
self.internal_message = internal_message
self.status_code = status_code

super().__init__(ui_message)

cow_say(ui_message)
cow_say(internal_message)
67 changes: 31 additions & 36 deletions src/app/core/commons/line_chart.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,14 @@
from datetime import timedelta
from dataclasses import asdict

from core.commons.error import Error
from core.entities import Plant
from core.entities.plant import Plant
from core.entities.line_chart_record import LineChartRecord
from core.constants import DAYS_RANGES


class LineChart:
def __init__(self, records: list[dict], attribute: str):
self.records = []

for record in records:
for required_attribute in ["date", "plant_id", attribute]:
if required_attribute not in record:
raise Error("Required attribute not found in record")

self.records.append(
{
"date": record["date"],
"plant_id": record["plant_id"],
"value": record[attribute],
}
)

def filter_records_by_range_of_days(self, days_range: int, plant_id: str):
last_date = self.__get_last_record_date_by_plant(plant_id)
data = []

for day in range(days_range - 1, -1, -1):
current_date = last_date - timedelta(days=day)

for record in self.records:
if record["date"] == current_date:
data.append(
{
**record,
"date": record["date"].strftime("%d/%m/%Y"),
}
)

return data
def __init__(self, records: list[LineChartRecord]):
self.records = [asdict(record) for record in records]

def get_data(self, plants: list[Plant]):
chart_data = {
Expand All @@ -51,10 +21,13 @@ def get_data(self, plants: list[Plant]):

for days_range in DAYS_RANGES:
for plant in plants:
days_range_records = self.filter_records_by_range_of_days(
days_range_records = self.__filter_records_by_range_of_days(
days_range, plant.id
)

if not len(days_range_records):
continue

values = []
dates = []

Expand All @@ -75,6 +48,28 @@ def get_data(self, plants: list[Plant]):

return chart_data

def __filter_records_by_range_of_days(self, days_range: int, plant_id: str):
last_date = self.__get_last_record_date_by_plant(plant_id)

if last_date is None:
return []

data = []

for day in range(days_range - 1, -1, -1):
current_date = last_date - timedelta(days=day)

for record in self.records:
if record["date"] == current_date:
data.append(
{
**record,
"date": record["date"].strftime("%d/%m/%Y"),
}
)

return data

def __get_last_record_date_by_plant(self, plant_id: str):
for index in range(1, len(self.records) + 1):
record = self.records[-index]
Expand Down
9 changes: 5 additions & 4 deletions src/app/core/commons/ordered_plants.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from core.entities import Plant
from core.entities.plant import Plant


class OrderedPlants:
value: list[Plant]
value: list[Plant] = []

def __init__(self, plants: list[Plant], active_plant_id: str) -> None:
def __init__(self, plants: list[Plant], active_plant_id: str):
self.value = self.__order(plants, active_plant_id)

def __order(self, plants: list[Plant], active_plant_id: str):
if len(plants) == 1:
plants_count = len(plants)
if plants_count == 0 or plants_count == 1:
return plants

filtered_plants_by_id = filter(
Expand Down
6 changes: 5 additions & 1 deletion src/app/core/commons/pagination.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from math import ceil

from core.constants import PAGINATION
from core.errors.validation import PageNumberNotValidError


class Pagination:
def __init__(self, page_number: int, records_count: int) -> None:
def __init__(self, page_number: int, records_count: int):
if not isinstance(page_number, int) or not isinstance(records_count, int):
raise PageNumberNotValidError()

self.page_number = page_number
self.records_count = records_count

Expand Down
12 changes: 8 additions & 4 deletions src/app/core/commons/records_filters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from core.commons import Date
from core.errors.validation import DateNotValidError


class RecordsFilters:
Expand All @@ -18,11 +19,14 @@ def __handle_filters(self):
if self.plant_id == "all":
self.plant_id = None

if self.start_date != "" and isinstance(self.start_date, str):
self.start_date = Date(self.start_date).get_value()
try:
if self.start_date != "" and isinstance(self.start_date, str):
self.start_date = Date(self.start_date).get_value(is_date=True)

if self.end_date != "" and isinstance(self.end_date, str):
self.end_date = Date(self.end_date).get_value()
if self.end_date != "" and isinstance(self.end_date, str):
self.end_date = Date(self.end_date).get_value(is_date=True)
except Exception:
raise DateNotValidError()

if self.start_date and (self.end_date is None or self.end_date == ""):
self.end_date = self.start_date
Empty file.
Loading
Loading