Yimaru-BackEnd/docs/TEST_PLAN.md
2026-02-27 01:15:38 -08:00

21 KiB

Yimaru LMS Backend — Test Plan

1. System Overview

Component Tech
Language Go 1.x
Framework Fiber v2
Database PostgreSQL (pgx/v5, sqlc)
Auth JWT (access + refresh tokens)
Video Vimeo API, CloudConvert
Payments ArifPay
Notifications WebSocket, SMS (AfroSMS), Resend, Push
Logging zap (MongoDB), slog

Roles: SUPER_ADMIN, ADMIN, STUDENT, INSTRUCTOR, SUPPORT Team Roles: super_admin, admin, content_manager, support_agent, instructor, finance, hr, analyst


2. Test Strategy

Test Pyramid

         ┌─────────┐
         │  E2E /  │   ← API integration tests (Postman/httptest)
         │  API    │
        ┌┴─────────┴┐
        │  Service   │  ← Business logic unit tests (mocked stores)
       ┌┴────────────┴┐
       │  Repository   │ ← DB integration tests (test DB + sqlc)
      ┌┴──────────────┴┐
      │  Domain/Utils   │ ← Pure unit tests (no deps)
      └────────────────┘

Priority Levels

  • P0 — Critical: Auth, Payments, Subscriptions — money + access
  • P1 — High: Course CRUD, Video upload pipeline, Ratings
  • P2 — Medium: Notifications, Questions, Issue Reporting, Team Mgmt
  • P3 — Low: Activity Logs, Analytics, Settings, Static files

3. Module Test Plans

3.1 Authentication & Authorization (P0)

Unit Tests

ID Test Case Input Expected
AUTH-01 Register user with valid data valid phone, email, password 201, user created with status=PENDING
AUTH-02 Register with existing email duplicate email 400/409, ErrEmailAlreadyRegistered
AUTH-03 Register with existing phone duplicate phone 400/409, ErrPhoneAlreadyRegistered
AUTH-04 Login with correct credentials valid email+password 200, access_token + refresh_token
AUTH-05 Login with wrong password valid email, bad password 401
AUTH-06 Login unverified user PENDING user 401, ErrUserNotVerified
AUTH-07 Refresh token (valid) valid refresh token 200, new access_token
AUTH-08 Refresh token (expired/revoked) expired/revoked token 401
AUTH-09 Google OAuth login (Android) valid Google ID token 200, tokens returned
AUTH-10 Logout valid token 200, refresh token revoked
AUTH-11 OTP send valid phone/email 200, OTP generated
AUTH-12 OTP verify (correct) correct OTP 200, user status → ACTIVE
AUTH-13 OTP verify (wrong/expired) wrong OTP 400
AUTH-14 OTP resend valid user 200, new OTP
AUTH-15 Password reset flow sendResetCode → verify → resetPassword 200 at each step

Middleware Tests

ID Test Case Expected
MW-01 Request without Authorization header 401
MW-02 Request with malformed JWT 401
MW-03 Request with expired JWT 401
MW-04 Valid token → user_id/role in Locals Next handler receives correct locals
MW-05 SuperAdminOnly — ADMIN role 403
MW-06 SuperAdminOnly — SUPER_ADMIN role Next called
MW-07 OnlyAdminAndAbove — STUDENT role 403
MW-08 OnlyAdminAndAbove — ADMIN role Next called

3.2 User Management (P1)

ID Test Case Input Expected
USR-01 Get user profile (own) auth token 200, profile data
USR-02 Update user profile valid fields 200, updated
USR-03 Upload profile picture (jpg) ≤5MB jpg 200, /static/profile_pictures/<uuid>.webp (if CloudConvert on)
USR-04 Upload profile picture (>5MB) 6MB file 400, file too large
USR-05 Upload profile picture (invalid type) .pdf file 400, invalid file type
USR-06 Profile picture CloudConvert fallback CloudConvert disabled 200, saved as original format
USR-07 Check profile completed user_id 200, boolean
USR-08 Update knowledge level valid level 200
USR-09 Get all users (admin) admin token 200, paginated list
USR-10 Delete user admin token, user_id 200, user deleted
USR-11 Search user by name/phone search term 200, results
USR-12 Check phone/email exist phone+email 200, exists flags

3.3 Admin Management (P1)

ID Test Case Input Expected
ADM-01 Create admin (SUPER_ADMIN) valid admin data 201
ADM-02 Create admin (ADMIN role) valid data 403, SuperAdminOnly
ADM-03 Get all admins SUPER_ADMIN token 200, list
ADM-04 Update admin SUPER_ADMIN token 200

3.4 Course Categories (P1)

ID Test Case Input Expected
CAT-01 Create category { "name": "Math" } 201, category returned
CAT-02 Create category (empty name) { "name": "" } 400
CAT-03 Get all categories (paginated) limit=10, offset=0 200, list + total_count
CAT-04 Get category by ID valid ID 200
CAT-05 Get category by ID (not found) ID=999999 404
CAT-06 Update category new name 200
CAT-07 Delete category valid ID 200
CAT-08 Delete category (cascade) category with courses 200, courses also deleted

3.5 Courses (P1)

ID Test Case Input Expected
CRS-01 Create course category_id + title 201, sends notifications to students
CRS-02 Create course (invalid category) nonexistent category_id 500 (FK violation)
CRS-03 Get course by ID valid ID 200, with thumbnail
CRS-04 Get courses by category (paginated) category_id, limit, offset 200
CRS-05 Update course title, description, thumbnail 200, activity log recorded
CRS-06 Upload course thumbnail (jpg→webp) valid image 200, stored as webp if CloudConvert enabled
CRS-07 Upload course thumbnail (>10MB) large file 400
CRS-08 Delete course valid ID 200, cascades to sub-courses

3.6 Sub-Courses (P1)

ID Test Case Input Expected
SUB-01 Create sub-course course_id, title, level=BEGINNER 201, notifications sent
SUB-02 Create sub-course (invalid level) level=EXPERT 500 (CHECK constraint)
SUB-03 List sub-courses by course course_id 200, list + count
SUB-04 List active sub-courses 200, only is_active=true
SUB-05 Update sub-course title, display_order 200
SUB-06 Upload sub-course thumbnail valid image 200
SUB-07 Deactivate sub-course valid ID 200, is_active=false
SUB-08 Delete sub-course valid ID 200, cascades to videos

3.7 Sub-Course Videos (P1)

ID Test Case Input Expected
VID-01 Create video (direct URL) video_url, title 201, provider=DIRECT
VID-02 Upload video file (with Vimeo) file + Vimeo configured 201, provider=VIMEO, status=DRAFT
VID-03 Upload video (CloudConvert + Vimeo) file + both configured 201, video compressed then uploaded
VID-04 Upload video (>500MB) large file 400
VID-05 Create video via Vimeo pull URL source_url 201
VID-06 Import from existing Vimeo ID vimeo_video_id 201, thumbnail from Vimeo
VID-07 Publish video video_id 200, is_published=true
VID-08 Get published videos by sub-course sub_course_id 200, only published
VID-09 Update video metadata title, description, status 200
VID-10 Delete video video_id 200
VID-11 CloudConvert disabled fallback upload without CC 201, no compression step

3.8 Learning Tree (P2)

ID Test Case Expected
TREE-01 Full learning tree (populated) 200, nested courses → sub-courses
TREE-02 Full learning tree (empty) 200, empty array

3.9 Questions System (P2)

ID Test Case Input Expected
Q-01 Create MCQ question question_text, type=MCQ, options 201
Q-02 Create TRUE_FALSE question type=TRUE_FALSE 201
Q-03 Create SHORT_ANSWER question type=SHORT_ANSWER, acceptable answers 201
Q-04 List questions (filtered) type=MCQ, difficulty=EASY 200, filtered list
Q-05 Search questions search query 200, matching results
Q-06 Update question with options new options 200, old options replaced
Q-07 Delete question question_id 200, cascades options/answers

3.10 Question Sets (P2)

ID Test Case Input Expected
QS-01 Create question set (PRACTICE) type=PRACTICE, owner 201
QS-02 Create question set (INITIAL_ASSESSMENT) type=INITIAL_ASSESSMENT 201
QS-03 Add question to set set_id, question_id 201
QS-04 Add duplicate question to set same set_id+question_id 409/error
QS-05 Reorder question in set display_order 200
QS-06 Remove question from set set_id, question_id 200
QS-07 Get questions in set set_id 200, ordered list
QS-08 Add user persona set_id, user_id 200
QS-09 Remove user persona set_id, user_id 200

3.11 Subscription Plans (P0)

ID Test Case Input Expected
PLAN-01 Create plan (admin) name, price, duration 201
PLAN-02 List plans (public, no auth) 200
PLAN-03 Get plan by ID (public) plan_id 200
PLAN-04 Update plan new price 200
PLAN-05 Delete plan plan_id 200
PLAN-06 Duration calculation (MONTH) start + 3 MONTH +3 months
PLAN-07 Duration calculation (YEAR) start + 1 YEAR +1 year
PLAN-08 Duration calculation (DAY) start + 30 DAY +30 days

3.12 User Subscriptions (P0)

ID Test Case Input Expected
SUBS-01 Admin creates subscription (no payment) user_id, plan_id 201, status=ACTIVE
SUBS-02 User subscribes with payment plan_id 201, status=PENDING, payment initiated
SUBS-03 Get my subscription auth token 200, current active sub
SUBS-04 Get subscription history auth token 200, all subs
SUBS-05 Check subscription status auth token 200, active/expired
SUBS-06 Cancel subscription subscription_id 200, status=CANCELLED
SUBS-07 Set auto-renew on subscription_id, true 200
SUBS-08 Set auto-renew off subscription_id, false 200
SUBS-09 Expired subscription status check expired sub status=EXPIRED

3.13 Payments — ArifPay (P0)

ID Test Case Input Expected
PAY-01 Initiate payment plan_id, phone, email 201, payment URL returned
PAY-02 Verify payment (success) valid session_id 200, status=SUCCESS, subscription activated
PAY-03 Verify payment (failed) failed session 200, status=FAILED
PAY-04 Get my payments auth token 200, payment list
PAY-05 Cancel payment payment_id 200, status=CANCELLED
PAY-06 Webhook handler (valid) valid ArifPay webhook 200, payment updated
PAY-07 Webhook handler (invalid signature) tampered data 400/401
PAY-08 Get payment methods (public) 200, methods list
PAY-09 Direct payment (OTP flow) phone, method 200, OTP sent
PAY-10 Verify direct payment OTP correct OTP 200, payment confirmed

3.14 Ratings (P1)

ID Test Case Input Expected
RAT-01 Rate app (5 stars) target_type=app, target_id=0, stars=5 201
RAT-02 Rate course (3 stars + review) target_type=course, target_id=1, stars=3, review="good" 201
RAT-03 Rate sub-course target_type=sub_course, target_id=1, stars=4 201
RAT-04 Update existing rating (upsert) same user+target, new stars 200, stars updated
RAT-05 Invalid stars (0) stars=0 400
RAT-06 Invalid stars (6) stars=6 400
RAT-07 Invalid target_type target_type=video 400
RAT-08 Get my rating for target target_type=course, target_id=1 200, my rating
RAT-09 Get my rating (not rated yet) 404
RAT-10 Get ratings by target (paginated) target_type=course, limit=20 200, list
RAT-11 Get rating summary target_type=course, target_id=1 200, avg + count
RAT-12 Get rating summary (no ratings) unrated target 200, avg=0, count=0
RAT-13 Get all my ratings auth token 200, list
RAT-14 Delete own rating rating_id 200
RAT-15 Delete other user's rating other's rating_id fails (no rows)

3.15 Notifications (P2)

ID Test Case Input Expected
NOT-01 WebSocket connection valid auth 101 upgrade
NOT-02 Get user notifications auth token 200, list
NOT-03 Mark as read notification_id 200
NOT-04 Mark all as read 200
NOT-05 Mark as unread notification_id 200
NOT-06 Count unread 200, count
NOT-07 Delete user notifications 200
NOT-08 Auto-notify on course creation create course students receive in-app notification
NOT-09 Auto-notify on sub-course creation create sub-course students notified
NOT-10 Send SMS (AfroSMS) phone + message 200
NOT-11 Register device token (push) device token 200
NOT-12 Unregister device token device token 200

3.16 Issue Reporting (P2)

ID Test Case Input Expected
ISS-01 Create issue subject, description, type=bug 201
ISS-02 Get my issues auth token 200
ISS-03 Get all issues (admin) admin token 200
ISS-04 Update issue status (admin) status=resolved 200, notifications sent
ISS-05 Delete issue (admin) issue_id 200
ISS-06 Get user issues (admin) user_id 200

3.17 Team Management (P2)

ID Test Case Input Expected
TM-01 Team member login email + password 200, tokens
TM-02 Create team member (admin) valid data, role=instructor 201
TM-03 Create team member (duplicate email) existing email 409
TM-04 Get all team members (admin) admin token 200, list
TM-05 Get team member stats (admin) admin token 200
TM-06 Update team member status status=suspended 200
TM-07 Delete team member (SUPER_ADMIN only) super_admin token 200
TM-08 Delete team member (ADMIN) admin token 403
TM-09 Change team member password old+new password 200
TM-10 Get my team profile team auth token 200

3.18 Vimeo Integration (P2)

ID Test Case Input Expected
VIM-01 Get video info vimeo_video_id 200, video details
VIM-02 Get embed code vimeo_video_id 200, iframe HTML
VIM-03 Get transcode status vimeo_video_id 200, status
VIM-04 Delete Vimeo video vimeo_video_id 200
VIM-05 Pull upload source URL 201
VIM-06 TUS upload file size + title 201, upload link
VIM-07 OEmbed Vimeo URL 200, embed data
VIM-08 Vimeo service disabled no config graceful handling

3.19 CloudConvert (P2)

ID Test Case Input Expected
CC-01 Video compression job video file compressed mp4 returned
CC-02 Image optimization job jpg file webp returned
CC-03 Job timeout slow job error after 30min (video) / 5min (image)
CC-04 Job failure invalid file error with task message
CC-05 Service disabled no config nil service, callers skip

3.20 Activity Logs & Analytics (P3)

ID Test Case Expected
LOG-01 Get activity logs (admin, filtered) 200, filtered by action/resource/date
LOG-02 Get activity log by ID 200
LOG-03 Activity log recorded on course CRUD log entry with actor, IP, UA
LOG-04 Analytics dashboard (admin) 200, dashboard data
LOG-05 MongoDB logs endpoint 200, log entries

3.21 Settings (P3)

ID Test Case Expected
SET-01 Get settings (SUPER_ADMIN) 200, settings list
SET-02 Get settings (ADMIN) 403
SET-03 Update settings 200
SET-04 Get setting by key 200

3.22 Assessment (P2)

ID Test Case Expected
ASM-01 Create assessment question 201
ASM-02 List assessment questions 200
ASM-03 Get assessment question by ID 200

4. Cross-Cutting Concerns

4.1 Input Validation

ID Test Expected
VAL-01 Empty required fields 400 with field-level errors
VAL-02 Invalid email format 400
VAL-03 Negative IDs in path params 400
VAL-04 Non-numeric path params (e.g., /courses/abc) 400
VAL-05 Malformed JSON body 400
VAL-06 Oversized request body (>500MB) 413

4.2 Cascading Deletes

ID Test Expected
CAS-01 Delete category → courses deleted verified via get
CAS-02 Delete course → sub-courses deleted verified via get
CAS-03 Delete sub-course → videos deleted verified via get
CAS-04 Delete user → ratings deleted verified via get

4.3 Concurrency / Race Conditions

ID Test Expected
RACE-01 Two users rating same target simultaneously both succeed, no duplicates
RACE-02 Same user submitting duplicate rating upsert, only one record
RACE-03 Concurrent subscription creation for same user one succeeds or both idempotent

4.4 File Upload Security

ID Test Expected
SEC-01 Upload with spoofed content-type header (exe as jpg) 400 (content sniffing rejects)
SEC-02 Path traversal in filename UUID-renamed, no traversal
SEC-03 Null bytes in filename handled safely

5. Integration Test Scenarios (E2E Flows)

Flow 1: Student Registration → Subscription → Learning

1. POST /user/register → PENDING
2. POST /user/verify-otp → ACTIVE
3. POST /auth/customer-login → tokens
4. GET /subscription-plans → choose plan
5. POST /subscriptions/checkout → payment URL
6. POST /payments/webhook → payment SUCCESS
7. GET /subscriptions/status → ACTIVE
8. GET /course-management/learning-tree → courses
9. GET /sub-courses/:id/videos/published → watch
10. POST /ratings → rate course

Flow 2: Admin Content Management

1. POST /auth/admin-login → tokens
2. POST /course-management/categories → create category
3. POST /course-management/courses → create course
4. POST /courses/:id/thumbnail → upload thumbnail
5. POST /course-management/sub-courses → create sub-course
6. POST /sub-courses/:id/thumbnail → upload thumbnail
7. POST /course-management/videos/upload → upload video (CloudConvert → Vimeo)
8. PUT /videos/:id/publish → publish
9. GET /activity-logs → verify all actions logged

Flow 3: Issue Resolution

1. Student: POST /issues → bug report
2. Admin: GET /issues → see all
3. Admin: PATCH /issues/:id/status → resolved
4. Student: GET /notifications → sees status update

Flow 4: Team Onboarding

1. SUPER_ADMIN: POST /team/members → create instructor
2. Instructor: POST /team/login → tokens
3. Instructor: GET /team/me → profile
4. SUPER_ADMIN: PATCH /team/members/:id/status → active

6. Performance & Load Testing

Test Target Threshold
Login throughput POST /auth/customer-login <200ms p95, 100 RPS
Course listing GET /categories/:id/courses <100ms p95
Video listing GET /sub-courses/:id/videos <100ms p95
Rating summary GET /ratings/summary <50ms p95
Notification list GET /notifications <100ms p95
File upload (5MB image) POST /user/:id/profile-picture <5s (without CC)
Concurrent ratings 50 users rating simultaneously no errors, correct counts

7. Test Environment Requirements

  • Test database: Isolated PostgreSQL instance, migrated with all 17 migrations
  • External services: Vimeo, CloudConvert, ArifPay, AfroSMS — stub/mock in tests
  • Test data seeding: Create fixtures for users (each role), categories, courses, sub-courses, plans
  • Cleanup: Each test suite truncates its tables or runs in a transaction with rollback

Purpose Tool
Go tests testing + testify/assert
HTTP testing net/http/httptest or Fiber's app.Test()
DB integration testcontainers-go (Postgres)
Mocking testify/mock or gomock
API collection Postman / Bruno (manual & CI)
Load testing k6 or vegeta
CI runner GitHub Actions / Gitea Actions