Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit 15d5c8b

Browse files
Remoção de referencias para vendor.*;
Ajustes na injeção de dependencias de classes (SQSEvents, SelfConnectionHealthCheck); Correção na validação de classe conexão para repositórios mysql; Adição de métodos extras para formatação de resultados de healthcheck; Correçẽos de testes de componentes; Implementação de vários cenários de testes de unidades; Criação de diversos mocks para testes de unidades; Adicionado tearDown para reverter alterações em objetos estáticos;
1 parent c97f414 commit 15d5c8b

File tree

25 files changed

+725
-46
lines changed

25 files changed

+725
-46
lines changed

examples/lambda_api/lambda_app/database/mysql.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from lambda_app.config import get_config
44
from lambda_app.logging import get_logger
5-
from vendor import pymysql
5+
import pymysql
66

77
logger = get_logger()
88

examples/lambda_api/lambda_app/events/aws/sqs.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@
1212

1313
class SQSEvents:
1414

15-
def __init__(self, logger=None, config=None):
15+
def __init__(self, logger=None, config=None, profile=None, session=None):
1616
# logger
1717
self.logger = logger if logger is not None else get_logger()
1818
# configurations
1919
self.config = config if config is not None else get_config()
2020
# last_exception
2121
self.exception = None
22+
# profile
23+
self.profile = profile if profile is not None else \
24+
os.environ['AWS_PROFILE'] if 'AWS_PROFILE' in os.environ else None
2225
# session
23-
self.profile = os.environ['AWS_PROFILE'] if 'AWS_PROFILE' in os.environ else None
24-
self.session = boto3.session.Session(profile_name=self.profile)
26+
self.session = session if session is not None else \
27+
boto3.session.Session(profile_name=self.profile)
2528

2629
def connect(self, retry=False):
2730
global _RETRY_COUNT, _MAX_RETRY_ATTEMPTS

examples/lambda_api/lambda_app/repositories/mysql/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from lambda_app.database.mysql import get_connection
22
from lambda_app.logging import get_logger
3-
from vendor import pymysql
3+
import pymysql
44

55

66
class AbstractRepository:
@@ -21,7 +21,9 @@ def _execute(self, sql, params=None):
2121
self.logger.info("SQL: {}".format(sql))
2222
self.logger.info("SQL Values: {}".format(params))
2323

24-
if isinstance(self.connection, pymysql.connections.Connection):
24+
# issubclass(connection_mock.__class__, pymysql.connections.Connection)
25+
if isinstance(self.connection, pymysql.connections.Connection) \
26+
or issubclass(self.connection.__class__, pymysql.connections.Connection):
2527
# always connect because is treadsafe
2628
self.connection.connect()
2729
# with self.connection.cursor() as cursor:
@@ -36,3 +38,5 @@ def _execute(self, sql, params=None):
3638

3739
def _close(self):
3840
self.connection.close()
41+
42+

examples/lambda_api/lambda_app/repositories/mysql/product_repository.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from lambda_app.logging import get_logger
66
from lambda_app.repositories.mysql import AbstractRepository
77
from lambda_app.vos.product import ProductVO
8-
from vendor import pymysql
8+
import pymysql
99

1010

1111
class ProductRepository(AbstractRepository):

examples/lambda_api/lambda_app/services/v1/healthcheck/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ def unhealthy(description):
3636
def degraded(description):
3737
return HealthCheckResult(HealthStatus.DEGRADED, description)
3838

39+
def __str__(self):
40+
return self.to_dict()
41+
42+
def __repr__(self):
43+
return self.to_json()
44+
45+
def to_dict(self):
46+
return {'status': self.status, 'description': self.description}
47+
48+
def to_json(self):
49+
return json.dumps(self.to_dict())
50+
3951

4052
class EntrySchema(Schema):
4153
status = fields.Str(example=HealthStatus.HEALTHY.value)

examples/lambda_api/lambda_app/services/v1/healthcheck/resources.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99

1010

1111
class SelfConnectionHealthCheck(AbstractHealthCheck):
12-
def __init__(self, logger=None, config=None):
12+
def __init__(self, logger=None, config=None, http_client=None):
1313
super().__init__(logger=logger, config=config)
14+
self.http_client = http_client if http_client is not None else requests
1415

1516
def check_health(self):
1617
result = False
1718
description = "Unable to connect"
1819
check_result = HealthCheckResult.unhealthy(description)
19-
response = None
2020
try:
2121
result = True
2222
url = os.environ["API_SERVER"] if "API_SERVER" in os.environ else None
2323
url = url + "/docs"
2424
self.logger.info("requesting url: {}".format(url))
25-
response = requests.get(url)
25+
response = self.http_client.get(url)
2626
if response:
2727
if response.status_code == 200:
2828
result = True

examples/lambda_api/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
# Não remover do projeto, muito útil para executar o debug via IDE Pycharm
55
http_server = WSGIServer(('0.0.0.0', 5000), app)
6-
http_server.serve_forever()
6+
http_server.serve_forever()

examples/lambda_api/tests/component/test_lambda_app/services/v1/healthcheck/test_sqs_connection_healthcheck.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from lambda_app.services.v1.healthcheck import HealthStatus, HealthCheckResult
77
from lambda_app.services.v1.healthcheck.resources import SQSConnectionHealthCheck
88
from tests.component.componenttestutils import BaseComponentTestCase
9+
from tests.component.helpers.events.aws.sqs_helper import SQSHelper
10+
from tests.unit.helpers.aws.sqs_helper import get_sqs_event_sample
911
from tests.unit.testutils import get_function_name
1012

1113

@@ -22,19 +24,41 @@ def setUpClass(cls):
2224
# fixture
2325
if cls.EXECUTE_FIXTURE:
2426
logger = get_logger()
25-
# logger.info('Fixture: create database')
26-
# todo a implementar
27+
logger.info('Fixture: create sqs queue')
28+
29+
queue_url = cls.CONFIG.APP_QUEUE
30+
cls.fixture_sqs(logger, queue_url)
31+
32+
@classmethod
33+
def fixture_sqs(cls, logger, queue_url):
34+
queue_name = SQSHelper.get_queue_name(queue_url)
35+
deleted = SQSHelper.delete_queue(queue_url)
36+
if deleted:
37+
logger.info(f'Deleting queue name: {queue_name}')
38+
39+
attributes = {'DelaySeconds': '1'}
40+
result = SQSHelper.create_queue(queue_url, attributes)
41+
if result is not None:
42+
logger.info(f'queue {queue_name} created')
43+
else:
44+
logger.error(f'queue {queue_name} not created')
45+
46+
event = get_sqs_event_sample()
47+
message = event['Records'][0]
48+
SQSHelper.create_message(message, queue_url)
49+
logger.info('created message: {}'.format(message))
2750

2851
def setUp(self):
2952
super().setUp()
30-
self.sqs_events = SQSEvents()
3153
self.config = get_config()
32-
self.service = SQSConnectionHealthCheck(self.logger, self.config, self.sqs_events)
54+
self.sqs = SQSEvents(logger=self.logger, config=self.config)
55+
self.service = SQSConnectionHealthCheck(self.logger, self.config, self.sqs)
3356

3457
def test_check_health(self):
3558
self.logger.info('Running test: %s', get_function_name(__name__))
3659

3760
result = self.service.check_health()
61+
self.logger.info(result.to_dict())
3862

3963
self.assertIsInstance(result, HealthCheckResult)
4064
self.assertEqual(result.status, HealthStatus.HEALTHY)

examples/lambda_api/tests/component/test_lambda_app/services/v1/test_healthcheck_service.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from tests.component.helpers.events.aws.sqs_helper import SQSHelper
1414
from tests.unit.helpers.aws.sqs_helper import get_sqs_event_sample
1515
from tests.unit.testutils import get_function_name
16+
from lambda_app.database.mysql import get_connection as mysql_get_connection
17+
from lambda_app.database.redis import get_connection as redis_get_connection
1618

1719

1820
class HealthCheckServiceTestCase(BaseComponentTestCase):
@@ -77,18 +79,18 @@ def fixture_table(cls, logger, mysql_connection, table_name):
7779
def setUp(self):
7880
super().setUp()
7981
self.config = get_config()
82+
self.mysql_connection = mysql_get_connection()
83+
self.redis_connection = redis_get_connection()
8084
self.service = HealthCheckService(self.logger, self.config)
8185

8286
def test_add_check(self):
8387
self.logger.info('Running test: %s', get_function_name(__name__))
84-
self.service.add_check("MysqlConnection", MysqlConnectionHealthCheck(self.logger, self.config), ["db"])
85-
86-
# self.assertEqual(len(self.service.entries), 1)
88+
self.service.add_check("MysqlConnection", MysqlConnectionHealthCheck(
89+
self.logger, self.config, self.mysql_connection), ["db"])
8790

8891
result = self.service.get_result()
89-
print(result)
92+
self.logger.info(result)
9093

91-
# self.assertEqual(result["status"], HealthStatus.HEALTHY)
9294
self.assertIsInstance(result, dict)
9395
self.assertTrue('status' in result)
9496

@@ -97,25 +99,22 @@ def test_add_lambda_check(self):
9799
self.service.add_check("Lambda test", lambda: HealthCheckResult.healthy("test success"), ["lambda_test"])
98100

99101
result = self.service.get_result()
100-
print(result)
102+
self.logger.info(result)
101103

102-
# self.assertEqual(result["status"], HealthStatus.HEALTHY)
103104
self.assertIsInstance(result, dict)
104105
self.assertTrue('status' in result)
105106

106107
def test_add_multi_checks(self):
107108
self.logger.info('Running test: %s', get_function_name(__name__))
108109
self.service.add_check("self", SelfConnectionHealthCheck(self.logger, self.config), [])
109-
self.service.add_check("mysql", MysqlConnectionHealthCheck(self.logger, self.config), ["db"])
110-
self.service.add_check("redis", RedisConnectionHealthCheck(self.logger, self.config), ["redis"])
111-
# self.service.add_check("SQSConnection", SQSConnectionHealthCheck(self.logger, self.config), ["db"])
112-
113-
#self.assertEqual(len(self.service.entries), 3)
110+
self.service.add_check("mysql", MysqlConnectionHealthCheck(
111+
self.logger, self.config, self.mysql_connection), ["db"])
112+
self.service.add_check("redis", RedisConnectionHealthCheck(
113+
self.logger, self.config, self.redis_connection), ["redis"])
114114

115115
result = self.service.get_result()
116-
print(result)
116+
self.logger.info(result)
117117

118-
# self.assertEqual(result["status"], HealthStatus.HEALTHY)
119118
self.assertIsInstance(result, dict)
120119
self.assertTrue('status' in result)
121120

@@ -126,7 +125,7 @@ def test_get_response(self):
126125
self.service.add_check("redis", RedisConnectionHealthCheck(self.logger, self.config), ["redis"])
127126

128127
response = self.service.get_response()
129-
print(response.data)
128+
self.logger.info(response.data)
130129
self.assertIsNotNone(response.data)
131130

132131

examples/lambda_api/tests/unit/mocks/database/mysql_mock.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,35 @@
1+
import random
12
from time import sleep
23

34
from mock import Mock
45
import pymysql
6+
from mock.mock import MagicMock
57

68
from pymysql import OperationalError
79

10+
# ************************
11+
# Cursor
12+
# ************************
13+
# def execute(self, query, args=None):
14+
# return True
15+
iterable = MagicMock(return_value=iter([MagicMock(return_value=1), MagicMock(return_value=2)]))
16+
cursor_mock = Mock(pymysql.cursors.DictCursor)
17+
cursor_mock.__iter__ = iterable
18+
cursor_mock.execute.side_effect = lambda query, args=None: True
19+
cursor_mock.fetchone.side_effect = lambda: None
20+
cursor_mock.fetchall.side_effect = lambda: iterable
21+
# ************************
22+
# Connect mock
23+
# ************************
24+
connect_mock = Mock(pymysql.connect)
25+
# ************************
26+
# Connection Mock
27+
# ************************
28+
connection_mock = Mock(pymysql.connections.Connection)
29+
connection_mock.connect.return_value = True
30+
connection_mock.cursor.return_value = cursor_mock
31+
connection_mock.insert_id.side_effect = lambda: random.randrange(1, 100)
32+
833
_CONNECTION = False
934
_RETRY_COUNT = 0
1035
_MAX_RETRY_ATTEMPTS = 3
@@ -15,14 +40,7 @@ def reset():
1540
_CONNECTION = False
1641

1742

18-
cursor_mock = Mock(pymysql.cursors.DictCursor)
19-
connection_mock = Mock(pymysql.connect)
20-
connection_mock.connect.return_value = True
21-
connection_mock.cursor.return_value = cursor_mock
22-
23-
2443
def mock_raise_exception():
25-
# raise Exception('Connection exception')
2644
raise OperationalError((1045, "Access denied for user 'undefined'@'192.168.160.1' (using password: YES)"))
2745

2846

0 commit comments

Comments
 (0)