Sau khi deploy backend thành công, bạn cần test tất cả API endpoints để đảm bảo hệ thống hoạt động đúng từ đầu đến cuối. Workshop này hướng dẫn chi tiết cách test từng module của hệ thống EveryoneCook.
Dự án EveryoneCook sử dụng API Router Pattern với các thành phần:
api-dev.everyonecook.cloudauth-user-lambda: Authentication & User Managementsocial-lambda: Posts, Comments, Reactions, Friends, Notificationsrecipe-ai-lambda: Recipes & AI Featuresadmin-lambda: Admin Dashboard & Content Moderationupload-lambda: File Upload với S3 Presigned URLs1. Lấy API Endpoint
2. Test Health Check (Public)
3. Test User Registration & Verification
4. Test User Login & Get JWT Token
5. Test Profile Management
6. Test Social Features (Posts, Friends, Notifications)
7. Test Recipe Management
8. Test AI Features (Recipe Generation, Translation)
9. Test File Upload (S3 + CloudFront)
10. Test Admin Features (nếu có quyền admin)
1. Lấy API URL từ CloudFormation Outputs
# Get API endpoint từ Backend Stack
$API_ENDPOINT = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Backend `
--query 'Stacks[0].Outputs[?OutputKey==`ApiCustomDomain`].OutputValue' `
--output text
Write-Host "API Endpoint: $API_ENDPOINT"
# Output: https://api-dev.everyonecook.cloud
2. Hoặc lấy từ file outputs.json
# Đọc từ infrastructure/outputs.json
cd D:\Project_AWS\everyonecook\infrastructure
$outputs = Get-Content outputs.json | ConvertFrom-Json
$API_ENDPOINT = $outputs.'EveryoneCook-dev-Backend'.ApiCustomDomain
Write-Host "API Endpoint: $API_ENDPOINT"
3. Setup biến môi trường
# Set API endpoint cho PowerShell session
$API_ENDPOINT = "https://api-dev.everyonecook.cloud"
$HEADERS_JSON = @{"Content-Type"="application/json"}
Write-Host "Environment configured:"
Write-Host " API Endpoint: $API_ENDPOINT"
Health check endpoint không cần authentication.
1. Test với PowerShell
# Test health endpoint
$response = Invoke-RestMethod -Uri "$API_ENDPOINT/health" -Method Get
$response | ConvertTo-Json
# Expected Output:
# {
# "status": "healthy",
# "timestamp": "2025-12-09T10:30:00.000Z",
# "service": "EveryoneCook API",
# "environment": "dev"
# }
2. Test với curl (nếu có WSL hoặc Git Bash)
curl -X GET "$API_ENDPOINT/health" | jq
3. Verify API Router hoạt động
# Check API Router Lambda logs
aws logs tail /aws/lambda/everyonecook-dev-api-router --follow
✅ Expected Result: Status 200, response JSON có "status": "healthy"
1. Lấy User Pool Client ID
# Get Cognito User Pool Client ID
$CLIENT_ID = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Auth `
--query 'Stacks[0].Outputs[?OutputKey==`UserPoolClientId`].OutputValue' `
--output text
Write-Host "User Pool Client ID: $CLIENT_ID"
2. Register User mới
# Đăng ký user với Cognito (không qua API - trực tiếp với Cognito)
$username = "testuser_$(Get-Random -Maximum 9999)"
$email = "test_$username@example.com"
$password = "TestPassword123!"
aws cognito-idp sign-up `
--client-id $CLIENT_ID `
--username $username `
--password $password `
--user-attributes `
Name=email,Value=$email `
Name=given_name,Value="Test User"
Write-Host "User registered: $username"
Write-Host "Email: $email"
Write-Host "Password: $password"
3. Verify Pre-Signup Trigger (Lambda Cognito Trigger)
# Check logs của Pre-Signup trigger
aws logs tail /aws/lambda/EveryoneCook-dev-PreSignup --since 5m
✅ Expected:
1. Lấy Confirmation Code
# Trong môi trường dev, có thể lấy code từ email hoặc dùng admin command
# Cách 1: Check email (nếu dùng real email)
# Cách 2: Admin confirm (cho testing)
aws cognito-idp admin-confirm-sign-up `
--user-pool-id ap-southeast-1_PKoL34PF0 `
--username $username
Write-Host "User confirmed: $username"
2. Verify Post-Confirmation Trigger
Post-Confirmation trigger sẽ tự động tạo user profile trong DynamoDB.
# Check DynamoDB - User profile được tạo tự động
aws dynamodb get-item `
--table-name EveryoneCook-dev `
--key "{\"PK\":{\"S\":\"USER#$username\"},\"SK\":{\"S\":\"PROFILE\"}}"
# Expected: User profile với các fields:
# - userId (Cognito sub ID)
# - email
# - fullName
# - createdAt
# - updatedAt
3. Check Post-Confirmation Lambda logs
aws logs tail /aws/lambda/EveryoneCook-dev-PostConfirmation --since 5m
✅ Expected: User profile được tạo trong DynamoDB table
1. Login để lấy JWT tokens
# Sign in với Cognito
$authResult = aws cognito-idp initiate-auth `
--client-id $CLIENT_ID `
--auth-flow USER_PASSWORD_AUTH `
--auth-parameters USERNAME=$username,PASSWORD=$password `
| ConvertFrom-Json
# Extract tokens
$ID_TOKEN = $authResult.AuthenticationResult.IdToken
$ACCESS_TOKEN = $authResult.AuthenticationResult.AccessToken
$REFRESH_TOKEN = $authResult.AuthenticationResult.RefreshToken
Write-Host "Login successful!"
Write-Host "ID Token length: $($ID_TOKEN.Length)"
2. Verify Post-Authentication Trigger
Post-Authentication trigger update lastLoginAt trong DynamoDB.
# Check lastLoginAt updated
aws dynamodb get-item `
--table-name EveryoneCook-dev `
--key "{\"PK\":{\"S\":\"USER#$username\"},\"SK\":{\"S\":\"PROFILE\"}}" `
--projection-expression "lastLoginAt"
3. Setup Authorization Header
# Create headers with JWT token
$HEADERS_AUTH = @{
"Content-Type" = "application/json"
"Authorization" = "Bearer $ID_TOKEN"
}
✅ Expected: Login thành công, nhận được JWT tokens
Endpoint: /users/me, /users/profile
1. Get Current User Profile
# GET /users/me
$response = Invoke-RestMethod `
-Uri "$API_ENDPOINT/users/me" `
-Method Get `
-Headers $HEADERS_AUTH
$response | ConvertTo-Json -Depth 5
# Expected Response:
# {
# "userId": "...",
# "username": "testuser_1234",
# "email": "test_testuser_1234@example.com",
# "fullName": "Test User",
# "birthday": null,
# "gender": null,
# "country": null,
# "createdAt": "2025-12-09T10:30:00.000Z",
# "lastLoginAt": "2025-12-09T11:00:00.000Z"
# }
2. Update Profile (Onboarding)
# PUT /users/profile - Complete onboarding
$profileUpdate = @{
birthday = "1990-01-01"
gender = "male"
country = "Vietnam"
bio = "Test user for EveryoneCook platform"
} | ConvertTo-Json
$response = Invoke-RestMethod `
-Uri "$API_ENDPOINT/users/profile" `
-Method Put `
-Headers $HEADERS_AUTH `
-Body $profileUpdate
$response | ConvertTo-Json
3. Get Privacy Settings
# GET /users/profile/privacy
$privacy = Invoke-RestMethod `
-Uri "$API_ENDPOINT/users/profile/privacy" `
-Method Get `
-Headers $HEADERS_AUTH
$privacy | ConvertTo-Json
4. Update Privacy Settings
# PUT /users/profile/privacy
$privacyUpdate = @{
profileVisibility = "public"
showEmail = $false
showBirthday = $false
allowFriendRequests = $true
} | ConvertTo-Json
Invoke-RestMethod `
-Uri "$API_ENDPOINT/users/profile/privacy" `
-Method Put `
-Headers $HEADERS_AUTH `
-Body $privacyUpdate
✅ Expected: Profile được update thành công trong DynamoDB
Endpoints: /posts, /posts/{postId}
1. Create Post
# POST /posts
$newPost = @{
content = "My first post on EveryoneCook! Testing the platform 🍳"
visibility = "public"
type = "text"
} | ConvertTo-Json
$postResponse = Invoke-RestMethod `
-Uri "$API_ENDPOINT/posts" `
-Method Post `
-Headers $HEADERS_AUTH `
-Body $newPost
$POST_ID = $postResponse.postId
Write-Host "Created Post ID: $POST_ID"
$postResponse | ConvertTo-Json
2. Get All Posts (Feed)
# GET /posts - Get all posts
$posts = Invoke-RestMethod `
-Uri "$API_ENDPOINT/posts?limit=10" `
-Method Get `
-Headers $HEADERS_AUTH
Write-Host "Found $($posts.items.Count) posts"
$posts.items | ConvertTo-Json -Depth 3
3. Get Specific Post
# GET /posts/{postId}
$post = Invoke-RestMethod `
-Uri "$API_ENDPOINT/posts/$POST_ID" `
-Method Get `
-Headers $HEADERS_AUTH
$post | ConvertTo-Json
4. Like Post
# POST /posts/{postId}/like
Invoke-RestMethod `
-Uri "$API_ENDPOINT/posts/$POST_ID/like" `
-Method Post `
-Headers $HEADERS_AUTH
Write-Host "Post liked successfully"
5. Add Comment
# POST /posts/{postId}/comments
$comment = @{
content = "Great post! 👍"
} | ConvertTo-Json
$commentResponse = Invoke-RestMethod `
-Uri "$API_ENDPOINT/posts/$POST_ID/comments" `
-Method Post `
-Headers $HEADERS_AUTH `
-Body $comment
$COMMENT_ID = $commentResponse.commentId
Write-Host "Comment ID: $COMMENT_ID"
6. Get Post Comments
# GET /posts/{postId}/comments
$comments = Invoke-RestMethod `
-Uri "$API_ENDPOINT/posts/$POST_ID/comments" `
-Method Get `
-Headers $HEADERS_AUTH
$comments | ConvertTo-Json -Depth 3
✅ Expected: Posts, likes, comments được lưu trong DynamoDB
Endpoints: /friends/*
1. Search Users
# GET /users/search?q=test
$users = Invoke-RestMethod `
-Uri "$API_ENDPOINT/users/search?q=test&limit=10" `
-Method Get `
-Headers $HEADERS_AUTH
$users | ConvertTo-Json
2. Send Friend Request (cần 2 users)
# POST /friends/{userId}/request
# Giả sử có USER_ID của user khác
$TARGET_USER_ID = "another-user-id"
Invoke-RestMethod `
-Uri "$API_ENDPOINT/friends/$TARGET_USER_ID/request" `
-Method Post `
-Headers $HEADERS_AUTH
Write-Host "Friend request sent"
3. Get Friend Requests
# GET /friends/requests
$requests = Invoke-RestMethod `
-Uri "$API_ENDPOINT/friends/requests" `
-Method Get `
-Headers $HEADERS_AUTH
$requests | ConvertTo-Json
✅ Expected: Friend requests được tạo với status “pending”
Endpoints: /recipes, /recipes/{recipeId}
1. Create Recipe
# POST /recipes
$newRecipe = @{
title = "Phở Bò Hà Nội"
description = "Traditional Vietnamese beef noodle soup"
ingredients = @(
@{ name = "beef bones"; amount = "2"; unit = "kg" }
@{ name = "rice noodles"; amount = "500"; unit = "g" }
@{ name = "ginger"; amount = "1"; unit = "piece" }
@{ name = "star anise"; amount = "3"; unit = "pieces" }
)
instructions = @(
"Boil beef bones for 2-3 hours to make broth"
"Add spices (ginger, star anise, cinnamon) and simmer"
"Prepare rice noodles separately"
"Serve noodles with broth and garnish with herbs"
)
cuisine = "Vietnamese"
difficulty = "medium"
prepTime = 30
cookTime = 180
servings = 4
} | ConvertTo-Json -Depth 5
$recipeResponse = Invoke-RestMethod `
-Uri "$API_ENDPOINT/recipes" `
-Method Post `
-Headers $HEADERS_AUTH `
-Body $newRecipe
$RECIPE_ID = $recipeResponse.recipeId
Write-Host "Created Recipe ID: $RECIPE_ID"
$recipeResponse | ConvertTo-Json -Depth 5
2. Get User’s Recipes
# GET /users/{userId}/recipes
$userId = $authResult.AuthenticationResult.AccessToken |
ForEach-Object { [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(($_.Split('.')[1]))) } |
ConvertFrom-Json |
Select-Object -ExpandProperty sub
$recipes = Invoke-RestMethod `
-Uri "$API_ENDPOINT/users/$userId/recipes" `
-Method Get `
-Headers $HEADERS_AUTH
$recipes | ConvertTo-Json -Depth 3
3. Search Recipes
# POST /recipes/search
$searchQuery = @{
query = "phở"
filters = @{
cuisine = "Vietnamese"
difficulty = "medium"
}
limit = 10
} | ConvertTo-Json
$searchResults = Invoke-RestMethod `
-Uri "$API_ENDPOINT/recipes/search" `
-Method Post `
-Headers $HEADERS_AUTH `
-Body $searchQuery
$searchResults | ConvertTo-Json -Depth 3
✅ Expected: Recipes được lưu trong DynamoDB với proper structure
Endpoints: /recipes/generate-ai, /ai/nutrition, /dictionary/{ingredient}
1. Generate Recipe with AI
# POST /recipes/generate-ai
$aiRequest = @{
ingredients = @("chicken", "rice", "vegetables", "fish sauce")
cuisine = "Vietnamese"
dietaryRestrictions = @("gluten-free")
servings = 4
difficulty = "medium"
} | ConvertTo-Json
Write-Host "Generating recipe with AI... (this takes 5-10 seconds)"
$aiRecipe = Invoke-RestMethod `
-Uri "$API_ENDPOINT/recipes/generate-ai" `
-Method Post `
-Headers $HEADERS_AUTH `
-Body $aiRequest
$aiRecipe | ConvertTo-Json -Depth 5
# Expected: AI-generated recipe with Vietnamese ingredient names
# Uses Amazon Bedrock Claude model
2. Get Nutrition Analysis
# POST /ai/nutrition
$nutritionRequest = @{
ingredients = @(
@{ name = "chicken breast"; amount = "200"; unit = "g" }
@{ name = "rice"; amount = "100"; unit = "g" }
)
} | ConvertTo-Json
$nutrition = Invoke-RestMethod `
-Uri "$API_ENDPOINT/ai/nutrition" `
-Method Post `
-Headers $HEADERS_AUTH `
-Body $nutritionRequest
$nutrition | ConvertTo-Json
3. Translate Ingredient (Vietnamese Dictionary)
# GET /dictionary/{ingredient}
$translation = Invoke-RestMethod `
-Uri "$API_ENDPOINT/dictionary/tomato" `
-Method Get `
-Headers $HEADERS_AUTH
Write-Host "Translation: $($translation.vietnamese)"
# Expected: { "ingredient": "tomato", "vietnamese": "cà chua" }
✅ Expected:
Endpoint: /upload/presigned-url
1. Request Presigned URL
# POST /upload/presigned-url
$uploadRequest = @{
fileType = "avatar"
fileName = "test-avatar.jpg"
contentType = "image/jpeg"
fileSize = 1024000 # 1MB
} | ConvertTo-Json
$uploadResponse = Invoke-RestMethod `
-Uri "$API_ENDPOINT/upload/presigned-url" `
-Method Post `
-Headers $HEADERS_AUTH `
-Body $uploadRequest
$PRESIGNED_URL = $uploadResponse.url
$UPLOAD_KEY = $uploadResponse.key
Write-Host "Presigned URL: $PRESIGNED_URL"
Write-Host "Upload Key: $UPLOAD_KEY"
2. Upload File to S3
# Create test image file
$testImage = "D:\test-avatar.jpg"
# (Tạo file test image hoặc dùng file có sẵn)
# Upload file using presigned URL
Invoke-RestMethod `
-Uri $PRESIGNED_URL `
-Method Put `
-InFile $testImage `
-ContentType "image/jpeg"
Write-Host "File uploaded to S3 successfully"
3. Access via CloudFront CDN
# Get CloudFront distribution domain
$CDN_DOMAIN = "d2shrpzup69rju.cloudfront.net" # Từ outputs.json
# Access file via CloudFront
$fileUrl = "https://$CDN_DOMAIN/$UPLOAD_KEY"
Invoke-WebRequest -Uri $fileUrl -Method Head
# Check caching headers
# First request: X-Cache: Miss from cloudfront
# Second request: X-Cache: Hit from cloudfront
✅ Expected: File được upload lên S3 và serve qua CloudFront
Endpoints: /admin/*
1. Get System Stats
# GET /admin/stats
$stats = Invoke-RestMethod `
-Uri "$API_ENDPOINT/admin/stats" `
-Method Get `
-Headers $HEADERS_AUTH
$stats | ConvertTo-Json
# Expected (nếu có admin role):
# {
# "totalUsers": 123,
# "totalPosts": 456,
# "totalRecipes": 789,
# "activeUsers": 45
# }
2. Get All Users
# GET /admin/users
$allUsers = Invoke-RestMethod `
-Uri "$API_ENDPOINT/admin/users?limit=20" `
-Method Get `
-Headers $HEADERS_AUTH
$allUsers | ConvertTo-Json
3. Get Reported Posts
# GET /admin/posts/reported
$reportedPosts = Invoke-RestMethod `
-Uri "$API_ENDPOINT/admin/posts/reported" `
-Method Get `
-Headers $HEADERS_AUTH
$reportedPosts | ConvertTo-Json
⚠️ Note: Admin endpoints require user có group “Admins” trong Cognito User Pool
1. Check SQS Queues
# List all queues
aws sqs list-queues --queue-name-prefix everyonecook-dev
# Get AI Queue attributes
$AI_QUEUE_URL = "https://sqs.ap-southeast-1.amazonaws.com/616580903213/everyonecook-dev-ai-queue"
aws sqs get-queue-attributes `
--queue-url $AI_QUEUE_URL `
--attribute-names ApproximateNumberOfMessages,ApproximateNumberOfMessagesNotVisible
2. Monitor Worker Lambdas
# Check Image Processing Worker logs
aws logs tail /aws/lambda/everyonecook-dev-image-worker --follow
# Check AI Worker logs (for recipe generation)
aws logs tail /aws/lambda/everyonecook-dev-ai-worker --follow
✅ Expected: Messages được process bởi worker Lambdas
Sử dụng checklist này để track progress:
GET /health - Health check respondsGET /status - Status check respondsGET /users/me - Get current user profilePUT /users/profile - Update profileGET /users/profile/privacy - Get privacy settingsPUT /users/profile/privacy - Update privacy settingsPOST /posts - Create postGET /posts - Get posts feedGET /posts/{postId} - Get specific postPOST /posts/{postId}/like - Like postPOST /posts/{postId}/comments - Add commentGET /posts/{postId}/comments - Get commentsPOST /friends/{userId}/request - Send friend requestGET /friends/requests - Get friend requestsGET /notifications - Get notificationsPOST /recipes - Create recipeGET /recipes - Get all recipesGET /recipes/{recipeId} - Get specific recipePOST /recipes/search - Search recipesPOST /recipes/generate-ai - AI recipe generation (Bedrock)POST /ai/nutrition - Nutrition analysisGET /dictionary/{ingredient} - Ingredient translationPOST /upload/presigned-url - Get presigned URLGET /admin/stats - Get system statsGET /admin/users - List all usersGET /admin/posts/reported - Get reported contentExpected Response Times:
| Endpoint | Expected Time | Notes |
|---|---|---|
GET /health | < 50ms | Direct response |
POST /auth/login | < 200ms | Cognito validation |
GET /users/me | < 100ms | DynamoDB single query |
POST /posts | < 300ms | DynamoDB write + notifications |
GET /posts | < 500ms | DynamoDB query with pagination |
POST /recipes/generate-ai | 5-10 seconds | Bedrock AI generation |
POST /upload/presigned-url | < 100ms | S3 presigned URL generation |
POST /recipes/search | < 200ms | DynamoDB GSI query |
# Verify JWT token not expired
$ID_TOKEN = "your-token-here"
$parts = $ID_TOKEN.Split('.')
$payload = [System.Text.Encoding]::UTF8.GetString(
[System.Convert]::FromBase64String($parts[1])
) | ConvertFrom-Json
$exp = [DateTimeOffset]::FromUnixTimeSeconds($payload.exp).DateTime
Write-Host "Token expires at: $exp"
# If expired, login again
# Check WAF logs
aws wafv2 get-web-acl `
--name EveryoneCook-API-WAF-dev `
--scope REGIONAL `
--region ap-southeast-1
# Check if IP blocked
# Check Lambda function logs
aws logs tail /aws/lambda/everyonecook-dev-api-router --follow
aws logs tail /aws/lambda/everyonecook-dev-social --follow
# Check DynamoDB table
aws dynamodb describe-table --table-name EveryoneCook-dev
# Check Bedrock model availability
aws bedrock list-foundation-models --region us-east-1
# Check AI Queue
aws sqs get-queue-attributes `
--queue-url $AI_QUEUE_URL `
--attribute-names All
Sau khi test thành công tất cả endpoints:
Proceed to: 5.09 - Push to GitLab
2. Confirm User
# Confirm user with code
aws cognito-idp confirm-sign-up \
--client-id $CLIENT_ID \
--username testuser \
--confirmation-code 123456
3. Verify Post-Confirmation Trigger
# Check if user profile was created in DynamoDB
aws dynamodb get-item \
--table-name EveryoneCook-dev \
--key '{"PK":{"S":"USER#testuser"},"SK":{"S":"PROFILE"}}'
# Should return user profile with:
# - PK: USER#testuser
# - SK: PROFILE
# - userId: cognito-sub-id
# - email: test@example.com
# - fullName: Test User
# - birthday: null
# - gender: null
# - country: null
1. Sign In
# Sign in to get tokens
TOKENS=$(aws cognito-idp initiate-auth \
--client-id $CLIENT_ID \
--auth-flow USER_PASSWORD_AUTH \
--auth-parameters USERNAME=testuser,PASSWORD=TestPassword123!)
# Extract tokens
ACCESS_TOKEN=$(echo $TOKENS | jq -r '.AuthenticationResult.AccessToken')
ID_TOKEN=$(echo $TOKENS | jq -r '.AuthenticationResult.IdToken')
REFRESH_TOKEN=$(echo $TOKENS | jq -r '.AuthenticationResult.RefreshToken')
echo "ID Token: $ID_TOKEN"
2. Verify Post-Authentication Trigger
# Check if lastLoginAt was updated
aws dynamodb get-item \
--table-name EveryoneCook-dev \
--key '{"PK":{"S":"USER#testuser"},"SK":{"S":"PROFILE"}}' \
--projection-expression "lastLoginAt"
1. Get Profile
# Get user profile
curl -X GET \
-H "Authorization: Bearer $ID_TOKEN" \
$API_ENDPOINT/auth/profile
# Expected: User profile data
2. Update Profile
# Update profile (onboarding)
curl -X PUT \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"birthday": "1990-01-01",
"gender": "male",
"country": "US"
}' \
$API_ENDPOINT/auth/profile
# Expected: Updated profile
3. Verify Update in DynamoDB
# Check updated profile
aws dynamodb get-item \
--table-name EveryoneCook-dev \
--key '{"PK":{"S":"USER#testuser"},"SK":{"S":"PROFILE"}}'
# Should show birthday, gender, country updated
1. Create Post
# Create a post
POST_RESPONSE=$(curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "My first post on EveryoneCook!",
"visibility": "public"
}' \
$API_ENDPOINT/social/posts)
POST_ID=$(echo $POST_RESPONSE | jq -r '.postId')
echo "Created post: $POST_ID"
2. Get Posts Feed
# Get posts
curl -X GET \
-H "Authorization: Bearer $ID_TOKEN" \
$API_ENDPOINT/social/posts
# Expected: Array of posts including the one just created
3. Like Post
# Like the post
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
$API_ENDPOINT/social/posts/$POST_ID/like
# Expected: Success message
4. Comment on Post
# Add comment
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"Great post!"}' \
$API_ENDPOINT/social/posts/$POST_ID/comment
# Expected: Comment created
1. Create Recipe
# Create a recipe
RECIPE_RESPONSE=$(curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Pho Bo (Vietnamese Beef Noodle Soup)",
"description": "Traditional Vietnamese beef noodle soup",
"ingredients": [
{"name": "beef bones", "amount": "2", "unit": "kg"},
{"name": "rice noodles", "amount": "500", "unit": "g"},
{"name": "ginger", "amount": "1", "unit": "piece"}
],
"instructions": [
"Boil beef bones for 2 hours",
"Add spices and simmer",
"Prepare noodles and serve"
],
"cuisine": "Vietnamese",
"difficulty": "medium",
"prepTime": 30,
"cookTime": 120
}' \
$API_ENDPOINT/recipes)
RECIPE_ID=$(echo $RECIPE_RESPONSE | jq -r '.recipeId')
echo "Created recipe: $RECIPE_ID"
2. Get Recipes
# Get all recipes
curl -X GET \
-H "Authorization: Bearer $ID_TOKEN" \
$API_ENDPOINT/recipes
# Expected: Array of recipes
3. Get Recipe by ID
# Get specific recipe
curl -X GET \
-H "Authorization: Bearer $ID_TOKEN" \
$API_ENDPOINT/recipes/$RECIPE_ID
# Expected: Recipe details
1. Generate Recipe with AI
# Generate recipe using Bedrock
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ingredients": ["chicken", "rice", "vegetables"],
"cuisine": "Vietnamese",
"dietaryRestrictions": ["gluten-free"],
"servings": 4
}' \
$API_ENDPOINT/ai/generate-recipe
# Expected: AI-generated recipe (takes 5-10 seconds)
# Response includes Vietnamese ingredient names
2. Translate Ingredient
# Translate ingredient to Vietnamese
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ingredient": "tomato",
"targetLanguage": "vi"
}' \
$API_ENDPOINT/ai/translate
# Expected: {"translation": "cà chua", "confidence": 0.99}
1. Request Pre-signed URL
# Get pre-signed URL for avatar upload
UPLOAD_RESPONSE=$(curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fileType": "avatar",
"fileName": "avatar.jpg",
"contentType": "image/jpeg",
"fileSize": 1024000
}' \
$API_ENDPOINT/upload/presigned-url)
PRESIGNED_URL=$(echo $UPLOAD_RESPONSE | jq -r '.url')
UPLOAD_KEY=$(echo $UPLOAD_RESPONSE | jq -r '.key')
echo "Pre-signed URL: $PRESIGNED_URL"
echo "Upload Key: $UPLOAD_KEY"
2. Upload File to S3
# Create test image
echo "Test image content" > test-avatar.jpg
# Upload using pre-signed URL
curl -X PUT \
-H "Content-Type: image/jpeg" \
--upload-file test-avatar.jpg \
"$PRESIGNED_URL"
# Expected: 200 OK
3. Mark Upload Complete
# Notify backend that upload is complete
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"key\":\"$UPLOAD_KEY\"}" \
$API_ENDPOINT/upload/complete
# Expected: Success message
4. Access via CloudFront
# Access file via CloudFront CDN
curl -I https://cdn.everyonecook.cloud/$UPLOAD_KEY
# First request: X-Cache: Miss from cloudfront
# Second request: X-Cache: Hit from cloudfront
If OpenSearch is enabled:
# Search recipes with Vietnamese query
curl -X POST \
-H "Authorization: Bearer $ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "phở bò",
"filters": {
"cuisine": "Vietnamese",
"difficulty": "medium"
},
"limit": 10
}' \
$API_ENDPOINT/ai/search
# Expected: Array of matching recipes
# Vietnamese analyzer handles: "phở bò" = "pho bo" = "beef noodle soup"
1. List Users (Admin Only)
# Get all users (requires admin role)
curl -X GET \
-H "Authorization: Bearer $ID_TOKEN" \
$API_ENDPOINT/admin/users
# Expected: Array of users or 403 Forbidden if not admin
1. Check SQS Queue Processing
# Send message to SearchIndex queue
QUEUE_URL=$(aws sqs list-queues \
--queue-name-prefix EveryoneCook-dev-SearchIndexQueue \
| jq -r '.QueueUrls[0]')
aws sqs send-message \
--queue-url $QUEUE_URL \
--message-body "{
\"eventName\": \"INSERT\",
\"tableName\": \"recipes\",
\"keys\": {\"PK\": \"USER#testuser\", \"SK\": \"RECIPE#$RECIPE_ID\"},
\"newImage\": {
\"title\": \"Pho Bo\",
\"ingredients\": [\"beef\", \"noodles\"],
\"cuisine\": \"Vietnamese\"
}
}"
# Check worker logs
aws logs tail /aws/lambda/EveryoneCook-dev-SearchSyncWorker --follow
Expected Response Times:
Once all tests pass, proceed to Push to GitLab to version control your code and set up CI/CD.