Skip to content

Commit

Permalink
Improve Test Coverage #59
Browse files Browse the repository at this point in the history
  • Loading branch information
AliRn76 authored Jan 4, 2024
2 parents 4e72329 + b584fec commit 22afe72
Show file tree
Hide file tree
Showing 19 changed files with 768 additions and 214 deletions.
22 changes: 19 additions & 3 deletions .github/workflows/pull_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,24 @@ jobs:
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Install pymongo
run: |
pip uninstall -y bson
pip install pymongo
- name: Start MongoDB
uses: supercharge/[email protected]
with:
mongodb-version: '4.4'

- name: Remove Build Directory
run: rm -rf build/

- name: Run Tests
run: pytest tests
run: coverage run -m pytest tests

- name: Show Coverage
run: coverage report

tests-windows:
name: Test Windows
Expand All @@ -46,7 +62,7 @@ jobs:
pip install -r requirements.txt
- name: Run Tests
run: pytest tests
run: pytest -m "not mongodb" tests

tests-macos:
name: Test MacOS
Expand All @@ -68,4 +84,4 @@ jobs:
pip install -r requirements.txt
- name: Run Tests
run: pytest tests
run: pytest -m "not mongodb" tests
60 changes: 55 additions & 5 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
pip install -r requirements.txt
- name: Run Tests
run: pytest tests
run: pytest -m "not mongodb" tests

tests-windows:
name: Test Windows Python${{ matrix.python-version }}
Expand All @@ -55,7 +55,7 @@ jobs:
pip install -r requirements.txt
- name: Run Tests
run: pytest tests
run: pytest -m "not mongodb" tests

tests-macos:
name: Test MacOS Python${{ matrix.python-version }}
Expand All @@ -80,12 +80,46 @@ jobs:
pip install -r requirements.txt
- name: Run Tests
run: pytest tests
run: pytest -m "not mongodb" tests

tests-mongodb:
name: Test MongoDB ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
matrix:
mongodb-version: ['4.2', '4.4', '5.0', '6.0']

steps:
- name: Checkout source
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install Requirements
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Install pymongo
run: |
pip uninstall -y bson
pip install pymongo
- name: Start MongoDB
uses: supercharge/[email protected]
with:
mongodb-version: ${{ matrix.mongodb-version }}

- name: Run Tests
run: pytest -m "mongodb" tests

coverage:
name: Coverage
runs-on: ubuntu-latest
needs: [tests-linux, tests-macos, tests-windows]
needs: [tests-linux, tests-mongodb, tests-macos, tests-windows]

steps:
- name: Checkout source
Expand All @@ -101,8 +135,24 @@ jobs:
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Install pymongo
run: |
pip uninstall -y bson
pip install pymongo
- name: Start MongoDB
uses: supercharge/[email protected]
with:
mongodb-version: '4.4'

- name: Remove Build Directory
run: rm -rf build/

- name: Run Coverage Tests
run: coverage run -m unittest tests/test_*.py
run: coverage run -m pytest tests

- name: Show Coverage
run: coverage report

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
Expand Down
2 changes: 2 additions & 0 deletions panther/_load_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ def load_jwt_config(configs: dict, /) -> JWTConfig | None:
if getattr(config['authentication'], '__name__', None) == 'JWTAuthentication':
user_config = configs.get('JWTConfig', {})
if 'key' not in user_config:
if config['secret_key'] is None:
raise PantherException('"SECRET_KEY" is required when using "JWTAuthentication"')
user_config['key'] = config['secret_key'].decode()

return JWTConfig(**user_config)
Expand Down
22 changes: 0 additions & 22 deletions panther/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,28 +121,6 @@ def is_function_async(func: Callable) -> bool:
return bool(func.__code__.co_flags & (1 << 7))


def run_sync_async_function(func: Callable):
# Async
if is_function_async(func):
# Get Event Loop
try:
loop = asyncio.get_running_loop()
except RuntimeError:
loop = None

# Add Coroutine To Event Loop
if loop and loop.is_running():
loop.create_task(func())

# Start New Event Loop
else:
asyncio.run(func())

# Sync
else:
func()


def clean_traceback_message(exception: Exception) -> str:
"""We are ignoring packages traceback message"""
tb = TracebackException(type(exception), exception, exception.__traceback__)
Expand Down
3 changes: 2 additions & 1 deletion panther/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ def handle_authentications(self) -> None:
auth_class = config['authentication']
if self.auth:
if not auth_class:
raise TypeError('"AUTHENTICATION" has not been set in core/configs')
logger.critical('"AUTHENTICATION" has not been set in configs')
raise APIException
user = auth_class.authentication(self.request)
self.request.set_user(user=user)

Expand Down
8 changes: 6 additions & 2 deletions panther/authentications.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ def get_authorization_header(cls, request: Request) -> bytes:
raise cls.exception(msg) from None

if isinstance(auth, str):
auth = auth.encode(JWTAuthentication.HTTP_HEADER_ENCODING)
try:
auth = auth.encode(JWTAuthentication.HTTP_HEADER_ENCODING)
except UnicodeEncodeError as e:
raise cls.exception(e) from None

return auth

@classmethod
Expand Down Expand Up @@ -126,6 +130,6 @@ def login(cls, user_id: IDType) -> str:
return cls.encode_jwt(user_id=user_id)

@staticmethod
def exception(message: str | JWTError, /) -> type[AuthenticationException]:
def exception(message: str | JWTError | UnicodeEncodeError, /) -> type[AuthenticationException]:
logger.error(f'JWT Authentication Error: "{message}"')
return AuthenticationException
6 changes: 4 additions & 2 deletions panther/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ class Config(TypedDict):
'default_cache_exp': None,
'throttling': None,
'secret_key': None,
'middlewares': [],
'reversed_middlewares': [],
'http_middlewares': [],
'ws_middlewares': [],
'reversed_http_middlewares': [],
'reversed_ws_middlewares': [],
'user_model': None,
'authentication': None,
'jwt_config': None,
Expand Down
7 changes: 5 additions & 2 deletions panther/db/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ def name(self) -> str:
return self._db_name

def _create_mongodb_session(self, db_url: str) -> None:
from pymongo import MongoClient

try:
from pymongo import MongoClient
except ModuleNotFoundError:
msg = "No module named 'pymongo'. Hint: `pip install pymongo`"
raise ValueError(msg)
self._client: MongoClient = MongoClient(db_url)
self._session: Database = self._client.get_database()

Expand Down
2 changes: 1 addition & 1 deletion panther/db/queries/mongodb_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,4 @@ def update_many(cls, _filter: dict, _data: dict | None = None, /, **kwargs) -> i
update_fields = {'$set': cls._merge(_data, kwargs)}

result = db.session[cls.__name__].update_many(_filter, update_fields)
return result.updated_count
return result.modified_count
5 changes: 0 additions & 5 deletions panther/db/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@

def log_query(func):
def log(*args, **kwargs):
# Check Database Connection
if config['db_engine'] == '':
msg = "You don't have active database connection, Check your middlewares"
raise NotImplementedError(msg)

if config['log_queries'] is False:
return func(*args, **kwargs)
start = perf_counter()
Expand Down
2 changes: 1 addition & 1 deletion panther/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def _create_ws_connections_instance(self):
if config['has_ws']:
config['websocket_connections'] = WebsocketConnections()
# Websocket Redis Connection
for middleware in config['middlewares']:
for middleware in config['http_middlewares']:
if middleware.__class__.__name__ == 'RedisMiddleware':
self.ws_redis_connection = middleware.redis_connection_for_ws()
break
Expand Down
7 changes: 7 additions & 0 deletions panther/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ def _serialize_with_output_model(cls, data: any, /, output_model: ModelMetaclass
msg = 'Type of Response data is not match with `output_model`.\n*hint: You may want to remove `output_model`'
raise TypeError(msg)

def __str__(self):
if len(data := str(self.data)) > 30:
data = f'{data:.27}...'
return f'Response(status_code={self.status_code}, data={data})'

__repr__ = __str__


class HTMLResponse(Response):
content_type = 'text/html; charset=utf-8'
Expand Down
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@ requires = [
"setuptools>=42",
"wheel"
]
build-backend = "setuptools.build_meta"
build-backend = "setuptools.build_meta"

[tool.pytest.ini_options]
markers = [
"mongodb: marks mongodb tests"
]
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ python-jose
faker
coverage
pytest
cryptography~=41.0
cryptography~=41.0
Loading

0 comments on commit 22afe72

Please sign in to comment.