Skip to content

Commit 721629e

Browse files
committed
add more tests
1 parent e91be7c commit 721629e

File tree

11 files changed

+248
-47
lines changed

11 files changed

+248
-47
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
pkg-manager: poetry
3232
- run: poetry run isort . --check
3333
- run: poetry run black . --check
34+
- run: poetry run pylint src
3435
- run: poetry run mypy -p src.bss_web_file_server
3536
verify-requirements:
3637
executor: python

src/bss_web_file_server/main.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
"""Main module for the FastAPI application."""
22

3-
from typing import Annotated
4-
53
from fastapi import FastAPI
64

75
from .routers import health, member, video
@@ -14,12 +12,12 @@
1412
app.include_router(video.router)
1513
app.include_router(member.router)
1614

15+
member_service = MemberService()
16+
video_service = VideoService()
17+
1718

1819
@app.on_event("startup")
19-
async def startup_event(
20-
member_service=MemberService(),
21-
video_service=VideoService(),
22-
):
20+
async def startup_event():
2321
"""Create the base paths for the video and member folders on startup."""
2422
video_service.create_base_path()
2523
member_service.create_base_path()

src/bss_web_file_server/routers/health.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88

99
@router.get("/health", response_class=PlainTextResponse)
1010
async def health():
11+
"""Health check endpoint."""
1112
return "UP"
1213

1314

1415
@router.get("/ping", response_class=PlainTextResponse)
1516
async def ping():
17+
"""Ping check endpoint."""
1618
return "PONG"

src/bss_web_file_server/routers/member.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,32 @@
33
import re
44
from uuid import UUID
55

6-
from fastapi import APIRouter, Depends, Response, UploadFile, status
6+
from fastapi import APIRouter, Response, UploadFile, status
77

88
from ..models.member import Member
99
from ..services.member import MemberService
1010

1111
router = APIRouter(tags=["Member"], prefix="/api/v1/member")
12+
service: MemberService = MemberService()
1213

1314

1415
@router.post("", response_model=Member)
15-
def create_member_folder(
16-
member: Member,
17-
service: MemberService = Depends(MemberService),
18-
):
16+
def create_member_folder(member: Member):
1917
"""
2018
Create a folder structure for a member and return the member object.
2119
:param member: Member object
22-
:param service: MemberService
2320
:return: 200 and the original member object
2421
"""
2522
service.create_folder_structure(member)
2623
return member
2724

2825

2926
@router.put("", response_model=Member)
30-
def update_member_folder(
31-
member: Member,
32-
service: MemberService = Depends(MemberService),
33-
):
27+
def update_member_folder(member: Member):
3428
"""
3529
Update the folder structure for a member and return the member object.
3630
If the member does not exist, return a 404.
3731
:param member: Member object
38-
:param service: MemberService
3932
:return: 200 and the original member object
4033
"""
4134
if not service.to_id_path(member.id).exists():
@@ -45,30 +38,25 @@ def update_member_folder(
4538

4639

4740
@router.post("/{member_id}/profilePicture", response_model=UUID)
48-
async def upload_member_picture(
49-
member_id: UUID,
50-
file: UploadFile,
51-
service: MemberService = Depends(MemberService),
52-
):
41+
async def upload_member_picture(member_id: UUID, file: UploadFile):
5342
"""
5443
Upload a picture for a member to convert
5544
and store the profile picture in different formats
5645
If the member does not exist, return a 404.
5746
If the file is not an image, return a 500.
5847
:param member_id: the id of the member
5948
:param file: the image file
60-
:param service: MemberService
6149
:return: 200 and the original member_id
6250
"""
51+
# pylint: disable=duplicate-code
6352
if not service.to_id_path(member_id).exists():
6453
return Response(status_code=status.HTTP_404_NOT_FOUND)
65-
# pylint: disable=duplicate-code
6654
if file.content_type is not None and not re.match("image/.+", file.content_type):
6755
return Response(
6856
content="Mime is not an image format",
6957
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
7058
)
71-
# pylint: enable=duplicate-code
7259
file_content = await file.read()
60+
# pylint: enable=duplicate-code
7361
service.create_profile_picture(file_content, member_id)
7462
return member_id

src/bss_web_file_server/routers/video.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,32 @@
33
import re
44
from uuid import UUID
55

6-
from fastapi import APIRouter, Depends, Response, UploadFile, status
6+
from fastapi import APIRouter, Response, UploadFile, status
77

88
from ..models.video import Video
99
from ..services.video import VideoService
1010

1111
router = APIRouter(tags=["Video"], prefix="/api/v1/video")
12+
service: VideoService = VideoService()
1213

1314

1415
@router.post("", response_model=Video)
15-
def create_video_folder(
16-
video: Video,
17-
service: VideoService = Depends(VideoService),
18-
):
16+
def create_video_folder(video: Video):
1917
"""
2018
Create a folder structure for a video and return the video object.
2119
:param video: Video object
22-
:param service: VideoService
2320
:return: 200 and the original video object
2421
"""
2522
service.create_folder_structure(video)
2623
return video
2724

2825

2926
@router.put("", response_model=Video)
30-
def update_video_folder(
31-
video: Video,
32-
service: VideoService = Depends(VideoService),
33-
):
27+
def update_video_folder(video: Video):
3428
"""
3529
Update the folder structure for a video and return the video object.
3630
If the video does not exist, return a 404.
3731
:param video: Video object
38-
:param service: VideoService
3932
:return: 200 and the original video object
4033
"""
4134
if not service.to_id_path(video.id).exists():
@@ -45,30 +38,25 @@ def update_video_folder(
4538

4639

4740
@router.post("/{video_id}/thumbnail", response_model=UUID)
48-
async def upload_video_poster(
49-
video_id: UUID,
50-
file: UploadFile,
51-
service: VideoService = Depends(VideoService),
52-
):
41+
async def upload_video_poster(video_id: UUID, file: UploadFile):
5342
"""
5443
Upload a picture for a video thumbnail to convert
5544
and store the thumbnail in different formats
5645
If the video does not exist, return a 404.
5746
If the file is not an image, return a 500.
5847
:param video_id: the id of the video
5948
:param file: the image file
60-
:param service: VideoService
6149
:return: 200 and the original video_id
6250
"""
51+
# pylint: disable=duplicate-code
6352
if not service.to_id_path(video_id).exists():
6453
return Response(status_code=status.HTTP_404_NOT_FOUND)
65-
# pylint: disable=duplicate-code
6654
if file.content_type is not None and not re.match("image/.+", file.content_type):
6755
return Response(
6856
content="Mime is not an image format",
6957
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
7058
)
71-
# pylint: enable=duplicate-code
7259
file_content = await file.read()
60+
# pylint: enable=duplicate-code
7361
service.create_thumbnails(file_content, video_id)
7462
return video_id

src/bss_web_file_server/services/member.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010

1111
class MemberService:
12+
"""Member service class."""
1213

1314
def __init__(self, base_path: str = settings.server_base_path):
1415
self.id_paths_base = Path(base_path, "m")

src/bss_web_file_server/services/video.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""This module contains all video related service logic."""
22

33
from pathlib import Path
4-
from typing import Annotated
54
from uuid import UUID
65

76
from ..models.video import Video
@@ -10,6 +9,7 @@
109

1110

1211
class VideoService:
12+
"""Video service class."""
1313

1414
def __init__(self, base_path: str = settings.server_base_path):
1515
self.id_paths_base = Path(base_path, "v")

tests/bss_web_file_server/routers/test_health.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
from bss_web_file_server.routers import health
55

66
app = FastAPI()
7-
87
app.include_router(health.router)
9-
108
client = TestClient(app)
119

1210

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import pytest
2+
from fastapi import FastAPI
3+
from fastapi.testclient import TestClient
4+
5+
from bss_web_file_server.models.member import Member
6+
from bss_web_file_server.routers import member
7+
8+
9+
@pytest.fixture
10+
def client():
11+
app = FastAPI()
12+
app.include_router(member.router)
13+
return TestClient(app)
14+
15+
16+
member_object = Member(id="00000000-0000-0000-0000-000000000000", url="bcsik")
17+
18+
19+
def test_create_member_folder(client, mocker):
20+
service_mock = mocker.patch("bss_web_file_server.routers.member.service")
21+
service_mock.create_folder_structure.return_value = None
22+
23+
member_data = {"id": str(member_object.id), "url": member_object.url}
24+
25+
response = client.post("/api/v1/member", json=member_data)
26+
27+
assert service_mock.create_folder_structure.call_count == 1
28+
assert service_mock.create_folder_structure.call_args[0][0] == member_object
29+
assert response.status_code == 200
30+
assert response.json() == member_data
31+
32+
33+
def test_update_member_folder_no_id(client, mocker):
34+
service_mock = mocker.patch("bss_web_file_server.routers.member.service")
35+
service_mock.to_id_path.return_value.exists.return_value = False
36+
37+
member_data = {"id": str(member_object.id), "url": member_object.url}
38+
39+
response = client.put("/api/v1/member", json=member_data)
40+
41+
assert service_mock.update_symlink.call_count == 0
42+
assert response.status_code == 404
43+
44+
45+
def test_update_member_folder(client, mocker):
46+
service_mock = mocker.patch("bss_web_file_server.routers.member.service")
47+
service_mock.to_id_path.return_value.exists.return_value = True
48+
service_mock.update_symlink.return_value = None
49+
50+
member_data = {"id": str(member_object.id), "url": member_object.url}
51+
52+
response = client.put("/api/v1/member", json=member_data)
53+
54+
assert service_mock.update_symlink.call_count == 1
55+
assert service_mock.update_symlink.call_args[0][0] == member_object
56+
assert response.status_code == 200
57+
assert response.json() == member_data
58+
59+
60+
def test_upload_member_picture_no_id(client, mocker):
61+
service_mock = mocker.patch("bss_web_file_server.routers.member.service")
62+
service_mock.to_id_path.return_value.exists.return_value = False
63+
64+
response = client.post(
65+
f"/api/v1/member/{member_object.id}/profilePicture",
66+
files={"file": ("file.jpg", "file_content", "image/jpeg")},
67+
)
68+
69+
assert service_mock.create_profile_picture.call_count == 0
70+
assert response.status_code == 404
71+
72+
73+
def test_upload_member_picture_not_image(client, mocker):
74+
service_mock = mocker.patch("bss_web_file_server.routers.member.service")
75+
service_mock.to_id_path.return_value.exists.return_value = True
76+
77+
response = client.post(
78+
f"/api/v1/member/{member_object.id}/profilePicture",
79+
files={"file": ("file.jpg", "file_content", "text/plain")},
80+
)
81+
82+
assert service_mock.create_profile_picture.call_count == 0
83+
assert response.status_code == 500
84+
assert response.text == "Mime is not an image format"
85+
86+
87+
def test_upload_member_picture(client, mocker):
88+
service_mock = mocker.patch("bss_web_file_server.routers.member.service")
89+
service_mock.to_id_path.return_value.exists.return_value = True
90+
service_mock.create_profile_picture.return_value = None
91+
92+
response = client.post(
93+
f"/api/v1/member/{member_object.id}/profilePicture",
94+
files={"file": ("file.jpg", "file_content", "image/jpeg")},
95+
)
96+
97+
assert service_mock.create_profile_picture.call_count == 1
98+
assert service_mock.create_profile_picture.call_args[0][0] == b"file_content"
99+
assert service_mock.create_profile_picture.call_args[0][1] == member_object.id
100+
assert response.status_code == 200
101+
assert response.json() == str(member_object.id)

0 commit comments

Comments
 (0)