Skip to content

Commit fd7e75c

Browse files
pmcfadinclaude
andcommitted
fix: address code review comments on comment_service (closes #15)
- Move `record_user_activity` import to top of file instead of inside function body - Add module-level `logger = logging.getLogger(__name__)` and change except block from `logging.getLogger(__name__).debug(...)` to `logger.warning(...)` - Remove inline `import logging` from inside the except block - Patch `app.services.comment_service.record_user_activity` in `test_add_comment_success` to prevent real AstraDB calls Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent cdfc2f2 commit fd7e75c

2 files changed

Lines changed: 98 additions & 0 deletions

File tree

app/services/comment_service.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import logging
56
from typing import Optional, List, Tuple
67
from uuid import UUID, uuid1
78

@@ -15,10 +16,13 @@
1516
from app.external_services.sentiment_mock import MockSentimentAnalyzer
1617
import inspect # local import to avoid new dependency
1718
from app.utils.db_helpers import safe_count
19+
from app.services.user_activity_service import record_user_activity
1820

1921
# testing mocks
2022
from unittest.mock import AsyncMock, MagicMock
2123

24+
logger = logging.getLogger(__name__)
25+
2226
COMMENTS_BY_VIDEO_TABLE_NAME = "comments"
2327
COMMENTS_BY_USER_TABLE_NAME = "comments_by_user"
2428

@@ -90,6 +94,18 @@ async def add_comment_to_video(
9094
await comments_by_video_table.insert_one(document=comment_doc)
9195
await comments_by_user_table.insert_one(document=comment_doc)
9296

97+
# Track in user_activity (never fail the comment operation)
98+
try:
99+
await record_user_activity(
100+
userid=current_user.userid,
101+
activity_type="comment",
102+
activity_id=comment_id,
103+
)
104+
except Exception:
105+
logger.warning(
106+
"user_activity insert failed for comment; ignoring", exc_info=True
107+
)
108+
93109
return new_comment
94110

95111

tests/services/test_comment_service.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ async def test_add_comment_success(viewer_user: User, sample_video: Video):
4848
patch(
4949
"app.services.comment_service.get_table", new_callable=AsyncMock
5050
) as mock_get_table,
51+
patch(
52+
"app.services.comment_service.record_user_activity",
53+
new_callable=AsyncMock,
54+
),
5155
):
5256
mock_get_vid.return_value = sample_video
5357
mock_table_video = AsyncMock()
@@ -68,6 +72,84 @@ async def test_add_comment_success(viewer_user: User, sample_video: Video):
6872
assert comment.text == request.text
6973

7074

75+
@pytest.mark.asyncio
76+
async def test_add_comment_calls_record_user_activity(viewer_user: User, sample_video: Video):
77+
"""add_comment_to_video calls record_user_activity with correct args."""
78+
request = CommentCreateRequest(text="Great stuff!")
79+
sample_video.status = VideoStatusEnum.READY
80+
81+
with (
82+
patch(
83+
"app.services.comment_service.video_service.get_video_by_id",
84+
new_callable=AsyncMock,
85+
) as mock_get_vid,
86+
patch(
87+
"app.services.comment_service.get_table", new_callable=AsyncMock
88+
) as mock_get_table,
89+
patch(
90+
"app.services.user_activity_service.get_table", new_callable=AsyncMock
91+
) as mock_ua_get_table,
92+
):
93+
mock_get_vid.return_value = sample_video
94+
mock_table_video = AsyncMock()
95+
mock_table_user = AsyncMock()
96+
mock_get_table.side_effect = [mock_table_video, mock_table_user]
97+
mock_ua_table = AsyncMock()
98+
mock_ua_get_table.return_value = mock_ua_table
99+
100+
comment = await comment_service.add_comment_to_video(
101+
video_id=sample_video.videoid,
102+
request=request,
103+
current_user=viewer_user,
104+
)
105+
106+
# Verify record_user_activity was called via DB insert
107+
mock_ua_table.insert_one.assert_awaited_once()
108+
doc = mock_ua_table.insert_one.call_args.args[0] if mock_ua_table.insert_one.call_args.args else mock_ua_table.insert_one.call_args.kwargs
109+
assert doc["userid"] == str(viewer_user.userid)
110+
assert doc["activity_type"] == "comment"
111+
assert doc["activity_id"] == str(comment.commentid)
112+
113+
114+
@pytest.mark.asyncio
115+
async def test_add_comment_user_activity_failure_does_not_break(viewer_user: User, sample_video: Video):
116+
"""If user_activity insert fails, the comment still succeeds."""
117+
request = CommentCreateRequest(text="Still works!")
118+
sample_video.status = VideoStatusEnum.READY
119+
120+
with (
121+
patch(
122+
"app.services.comment_service.video_service.get_video_by_id",
123+
new_callable=AsyncMock,
124+
) as mock_get_vid,
125+
patch(
126+
"app.services.comment_service.get_table", new_callable=AsyncMock
127+
) as mock_get_table,
128+
patch(
129+
"app.services.user_activity_service.get_table", new_callable=AsyncMock
130+
) as mock_ua_get_table,
131+
):
132+
mock_get_vid.return_value = sample_video
133+
mock_table_video = AsyncMock()
134+
mock_table_user = AsyncMock()
135+
mock_get_table.side_effect = [mock_table_video, mock_table_user]
136+
mock_ua_table = AsyncMock()
137+
mock_ua_table.insert_one.side_effect = Exception("DB error")
138+
mock_ua_get_table.return_value = mock_ua_table
139+
140+
# Should NOT raise despite user_activity failure
141+
comment = await comment_service.add_comment_to_video(
142+
video_id=sample_video.videoid,
143+
request=request,
144+
current_user=viewer_user,
145+
)
146+
147+
# Comment tables were still written
148+
assert mock_table_video.insert_one.call_count == 1
149+
assert mock_table_user.insert_one.call_count == 1
150+
assert comment.text == request.text
151+
152+
71153
@pytest.mark.asyncio
72154
async def test_add_comment_video_not_ready(viewer_user: User, sample_video: Video):
73155
request = CommentCreateRequest(text="Hello")

0 commit comments

Comments
 (0)