Spaces:
Sleeping
Sleeping
| # Ticket Comments - Testing Guide | |
| ## Manual Testing Checklist | |
| ### 1. Create Comment ✅ | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/v1/tickets/{ticket_id}/comments" \ | |
| -H "Authorization: Bearer {token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "comment_text": "Customer prefers morning visits", | |
| "is_internal": true, | |
| "comment_type": "note" | |
| }' | |
| ``` | |
| **Expected:** 201 Created with comment details | |
| --- | |
| ### 2. Create Reply (Threading) ✅ | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/v1/tickets/{ticket_id}/comments" \ | |
| -H "Authorization: Bearer {token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "comment_text": "I will handle this", | |
| "parent_comment_id": "{parent_comment_id}", | |
| "is_internal": true, | |
| "comment_type": "note" | |
| }' | |
| ``` | |
| **Expected:** 201 Created with parent_comment_id set | |
| --- | |
| ### 3. List Comments ✅ | |
| ```bash | |
| curl -X GET "http://localhost:7860/api/v1/tickets/{ticket_id}/comments?page=1&page_size=20" \ | |
| -H "Authorization: Bearer {token}" | |
| ``` | |
| **Expected:** 200 OK with paginated list | |
| --- | |
| ### 4. Get Comment Replies ✅ | |
| ```bash | |
| curl -X GET "http://localhost:7860/api/v1/comments/{comment_id}/replies" \ | |
| -H "Authorization: Bearer {token}" | |
| ``` | |
| **Expected:** 200 OK with array of replies | |
| --- | |
| ### 5. Update Comment ✅ | |
| ```bash | |
| curl -X PUT "http://localhost:7860/api/v1/comments/{comment_id}" \ | |
| -H "Authorization: Bearer {token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "comment_text": "Updated: Customer prefers afternoon" | |
| }' | |
| ``` | |
| **Expected:** 200 OK with is_edited=true | |
| --- | |
| ### 6. Delete Comment ✅ | |
| ```bash | |
| curl -X DELETE "http://localhost:7860/api/v1/comments/{comment_id}" \ | |
| -H "Authorization: Bearer {token}" | |
| ``` | |
| **Expected:** 200 OK with success message | |
| --- | |
| ## Error Cases to Test | |
| ### 1. Create Comment on Non-Existent Ticket | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/v1/tickets/00000000-0000-0000-0000-000000000000/comments" \ | |
| -H "Authorization: Bearer {token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"comment_text": "Test", "is_internal": true, "comment_type": "note"}' | |
| ``` | |
| **Expected:** 404 Not Found - "Ticket not found" | |
| --- | |
| ### 2. Update Someone Else's Comment | |
| ```bash | |
| # Create comment as User A | |
| # Try to update as User B | |
| curl -X PUT "http://localhost:7860/api/v1/comments/{comment_id}" \ | |
| -H "Authorization: Bearer {user_b_token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"comment_text": "Hacked!"}' | |
| ``` | |
| **Expected:** 403 Forbidden - "You can only edit your own comments" | |
| --- | |
| ### 3. Reply to Non-Existent Comment | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/v1/tickets/{ticket_id}/comments" \ | |
| -H "Authorization: Bearer {token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "comment_text": "Reply", | |
| "parent_comment_id": "00000000-0000-0000-0000-000000000000", | |
| "is_internal": true, | |
| "comment_type": "note" | |
| }' | |
| ``` | |
| **Expected:** 404 Not Found - "Parent comment not found" | |
| --- | |
| ### 4. Mention Non-Existent User | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/v1/tickets/{ticket_id}/comments" \ | |
| -H "Authorization: Bearer {token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "comment_text": "Test", | |
| "mentioned_user_ids": ["00000000-0000-0000-0000-000000000000"], | |
| "is_internal": true, | |
| "comment_type": "note" | |
| }' | |
| ``` | |
| **Expected:** 400 Bad Request - "One or more mentioned users not found" | |
| --- | |
| ### 5. Empty Comment Text | |
| ```bash | |
| curl -X POST "http://localhost:7860/api/v1/tickets/{ticket_id}/comments" \ | |
| -H "Authorization: Bearer {token}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "comment_text": "", | |
| "is_internal": true, | |
| "comment_type": "note" | |
| }' | |
| ``` | |
| **Expected:** 422 Validation Error - "comment_text must be at least 1 character" | |
| --- | |
| ## Integration Testing | |
| ### Scenario 1: Threaded Conversation | |
| 1. User A creates comment: "Need help with this ticket" | |
| 2. User B replies: "I can help" | |
| 3. User A replies to B: "Thanks!" | |
| 4. Verify reply_count increments | |
| 5. Load replies and verify order (oldest first) | |
| ### Scenario 2: Edit Tracking | |
| 1. User creates comment | |
| 2. User edits comment | |
| 3. Verify is_edited=true, edited_at set, edited_by_user_id set | |
| 4. Edit again | |
| 5. Verify edited_at updated | |
| ### Scenario 3: Soft Delete | |
| 1. User creates comment | |
| 2. User deletes comment | |
| 3. Verify deleted_at set | |
| 4. Try to list comments - deleted comment should not appear | |
| 5. Try to get deleted comment by ID - should return 404 | |
| ### Scenario 4: Pagination | |
| 1. Create 100 comments | |
| 2. List with page_size=20 | |
| 3. Verify pages=5 | |
| 4. Load each page | |
| 5. Verify no duplicates, no missing comments | |
| --- | |
| ## Performance Testing | |
| ### Load Test: Create 1000 Comments | |
| ```python | |
| import asyncio | |
| import aiohttp | |
| async def create_comment(session, ticket_id, token): | |
| async with session.post( | |
| f"http://localhost:7860/api/v1/tickets/{ticket_id}/comments", | |
| headers={"Authorization": f"Bearer {token}"}, | |
| json={ | |
| "comment_text": "Load test comment", | |
| "is_internal": True, | |
| "comment_type": "note" | |
| } | |
| ) as response: | |
| return await response.json() | |
| async def main(): | |
| async with aiohttp.ClientSession() as session: | |
| tasks = [create_comment(session, ticket_id, token) for _ in range(1000)] | |
| results = await asyncio.gather(*tasks) | |
| print(f"Created {len(results)} comments") | |
| asyncio.run(main()) | |
| ``` | |
| **Expected:** All 1000 comments created successfully in < 30 seconds | |
| --- | |
| ## Database Verification | |
| ### Check Comment Count | |
| ```sql | |
| SELECT COUNT(*) FROM ticket_comments WHERE deleted_at IS NULL; | |
| ``` | |
| ### Check Threading | |
| ```sql | |
| SELECT | |
| id, | |
| comment_text, | |
| parent_comment_id, | |
| (SELECT COUNT(*) FROM ticket_comments c2 WHERE c2.parent_comment_id = c1.id) as reply_count | |
| FROM ticket_comments c1 | |
| WHERE ticket_id = '{ticket_id}' AND deleted_at IS NULL | |
| ORDER BY created_at DESC; | |
| ``` | |
| ### Check Edit History | |
| ```sql | |
| SELECT | |
| id, | |
| comment_text, | |
| is_edited, | |
| edited_at, | |
| edited_by_user_id | |
| FROM ticket_comments | |
| WHERE is_edited = TRUE AND deleted_at IS NULL; | |
| ``` | |
| --- | |
| ## Common Issues & Solutions | |
| ### Issue: 500 Internal Server Error | |
| **Cause:** Missing relationship loading | |
| **Solution:** Ensure all relationships use `joinedload()` in service layer | |
| ### Issue: Comments not appearing | |
| **Cause:** Soft delete not filtered | |
| **Solution:** Always filter `deleted_at IS NULL` | |
| ### Issue: Reply count incorrect | |
| **Cause:** Not counting replies properly | |
| **Solution:** Use subquery to count replies in `_to_response()` | |
| ### Issue: Mentions not working | |
| **Cause:** User IDs not validated | |
| **Solution:** Query users table to verify all mentioned_user_ids exist | |
| --- | |
| ## Monitoring | |
| ### Key Metrics to Track | |
| - Comment creation rate (comments/hour) | |
| - Average reply depth (threading level) | |
| - Edit frequency (edits/comments ratio) | |
| - Delete frequency (deletes/comments ratio) | |
| - Response time for list endpoint | |
| ### Alerts to Set Up | |
| - Comment creation failures > 1% | |
| - List endpoint response time > 2 seconds | |
| - Database connection errors | |
| - Validation errors > 5% | |