diff --git a/.gitignore b/.gitignore index ea44a67..71f155e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ .env.development .env.staging .env.production +**/**.log \ No newline at end of file diff --git a/imphnen-cms/src/v1/landing/testimonials/testimonials_schema.rs b/imphnen-cms/src/v1/landing/testimonials/testimonials_schema.rs index 39fdca4..cce2772 100644 --- a/imphnen-cms/src/v1/landing/testimonials/testimonials_schema.rs +++ b/imphnen-cms/src/v1/landing/testimonials/testimonials_schema.rs @@ -5,80 +5,87 @@ use surrealdb::Uuid; use surrealdb::sql::Thing; use super::testimonials_dto::{ - TestimonialsCreateRequestDto, TestimonialsQueryDto, TestimonialsUpdateRequestDto, + TestimonialsCreateRequestDto, TestimonialsQueryDto, TestimonialsUpdateRequestDto, }; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TestimonialsSchema { - pub id: Thing, - pub user: Thing, - pub role: String, - pub content: String, - pub is_deleted: bool, - pub created_at: String, - pub updated_at: String, + pub id: Thing, + pub user: Thing, + pub role: String, + pub content: String, + pub is_deleted: bool, + pub created_at: String, + pub updated_at: String, } impl Default for TestimonialsSchema { - fn default() -> Self { - Self { - id: make_thing( - &ResourceEnum::Testimonials.to_string(), - &Uuid::new_v4().to_string(), - ), - user: make_thing( - &ResourceEnum::Users.to_string(), - &Uuid::new_v4().to_string(), - ), - role: String::new(), - content: String::new(), - is_deleted: false, - created_at: get_iso_date(), - updated_at: get_iso_date(), - } - } + fn default() -> Self { + Self { + id: make_thing( + &ResourceEnum::Testimonials.to_string(), + &Uuid::new_v4().to_string(), + ), + user: make_thing( + &ResourceEnum::Users.to_string(), + &Uuid::new_v4().to_string(), + ), + role: String::new(), + content: String::new(), + is_deleted: false, + created_at: get_iso_date(), + updated_at: get_iso_date(), + } + } } impl TestimonialsSchema { - pub fn from(dto: TestimonialsQueryDto) -> Self { - Self { - id: dto.id, - user: dto.user.id, - role: dto.role, - content: dto.content, - is_deleted: dto.is_deleted, - created_at: dto.created_at, - updated_at: dto.updated_at, - } - } + pub fn from(dto: TestimonialsQueryDto) -> Self { + Self { + id: dto.id, + user: dto.user.id, + role: dto.role, + content: dto.content, + is_deleted: dto.is_deleted, + created_at: dto.created_at, + updated_at: dto.updated_at, + } + } - pub fn create(payload: TestimonialsCreateRequestDto, user_id: &Thing) -> Self { - Self { - id: make_thing( - &ResourceEnum::Testimonials.to_string(), - &Uuid::new_v4().to_string(), - ), - user: user_id.clone(), - role: payload.role, - content: payload.content, - is_deleted: false, - created_at: get_iso_date(), - updated_at: get_iso_date(), - } - } + pub fn create(payload: TestimonialsCreateRequestDto, user_id: &Thing) -> Self { + Self { + id: make_thing( + &ResourceEnum::Testimonials.to_string(), + &Uuid::new_v4().to_string(), + ), + user: user_id.clone(), + role: payload.role, + content: payload.content, + is_deleted: false, + created_at: get_iso_date(), + updated_at: get_iso_date(), + } + } - pub fn update( - payload: TestimonialsUpdateRequestDto, - id: String, - user_id: &Thing, - ) -> Self { - Self { - id: make_thing(&ResourceEnum::Testimonials.to_string(), &id), - role: payload.role, - content: payload.content, - updated_at: get_iso_date(), - user: user_id.clone(), - ..Default::default() - } - } + pub fn update( + payload: TestimonialsUpdateRequestDto, + id: String, + user_id: &Thing, + ) -> Self { + // Normalize id: accept either raw id (uuid) or Thing-formatted id like "table:⟨id⟩" + let raw_id = if id.contains(':') { + id.split(':').last().unwrap().trim_matches(|c| c == '⟨' || c == '⟩').to_string() + } else { + id + }; + + Self { + id: make_thing(&ResourceEnum::Testimonials.to_string(), &raw_id), + role: payload.role, + content: payload.content, + updated_at: get_iso_date(), + user: user_id.clone(), + ..Default::default() + } + } } diff --git a/run-all-tests.sh b/run-all-tests.sh new file mode 100644 index 0000000..c948638 --- /dev/null +++ b/run-all-tests.sh @@ -0,0 +1,130 @@ +#!/bin/bash + +# ============================================================================== +# IMPHNEN API - Master Test Runner +# Menjalankan semua test suite untuk coverage lengkap +# ============================================================================== + +# Colors +CYAN='\033[0;36m' +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +NC='\033[0m' + +echo -e "${CYAN}================================================================${NC}" +echo -e "${CYAN} IMPHNEN Backend - Complete API Test Suite${NC}" +echo -e "${CYAN}================================================================${NC}" +echo "" + +# Check if server is running +BASE_URL="http://127.0.0.1:4099" +if curl -s --head "$BASE_URL/v1/cms/landing/events" > /dev/null 2>&1; then + echo -e "${GREEN}✓ Server is running at $BASE_URL${NC}" +else + echo -e "${RED}✗ Server is not running!${NC}" + echo -e "${YELLOW}Please start the server first with: cargo run --bin api --release${NC}" + exit 1 +fi + +echo "" + +# Counters +TOTAL_SUITES=0 +PASSED_SUITES=0 +FAILED_SUITES=0 + +run_test_suite() { + local suite_name=$1 + local suite_command=$2 + local suite_description=$3 + + ((TOTAL_SUITES++)) + + echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${CYAN}Test Suite #${TOTAL_SUITES}: ${suite_name}${NC}" + echo -e "${CYAN}Description: ${suite_description}${NC}" + echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" + + # Run the test suite + if eval "$suite_command"; then + echo "" + echo -e "${GREEN}✓ Suite Passed: ${suite_name}${NC}" + ((PASSED_SUITES++)) + else + echo "" + echo -e "${RED}✗ Suite Failed: ${suite_name}${NC}" + ((FAILED_SUITES++)) + fi + + echo "" +} + +# ============================================================================== +# RUN ALL TEST SUITES +# ============================================================================== + +echo -e "${YELLOW}Starting comprehensive API testing...${NC}" +echo "" +sleep 1 + +# Suite 1: Main Test Suite (dari test.sh) +run_test_suite \ + "Main API Test Suite" \ + "bash test.sh -dk" \ + "Comprehensive tests covering all major endpoints with multiple user roles" + +# Suite 2: Comprehensive API Coverage +run_test_suite \ + "Extended API Coverage" \ + "bash test-comprehensive-api.sh" \ + "Detailed tests for all CRUD operations on every endpoint" + +# Suite 3: Cargo Unit Tests +run_test_suite \ + "Rust Unit Tests" \ + "cargo test --lib 2>&1 | grep -E '(test result|running)'" \ + "Unit tests for Rust codebase" + +# Suite 4: Cargo Integration Tests +run_test_suite \ + "Rust Integration Tests" \ + "cargo test --test '*' 2>&1 | grep -E '(test result|running)'" \ + "Integration tests for full system behavior" + +# ============================================================================== +# FINAL SUMMARY +# ============================================================================== + +echo "" +echo -e "${CYAN}================================================================${NC}" +echo -e "${CYAN} FINAL TEST SUMMARY${NC}" +echo -e "${CYAN}================================================================${NC}" +echo "" +echo -e "Total Test Suites Run: ${TOTAL_SUITES}" +echo -e "${GREEN}Passed Suites: ${PASSED_SUITES}${NC}" +echo -e "${RED}Failed Suites: ${FAILED_SUITES}${NC}" +echo "" + +SUCCESS_RATE=0 +if [ "$TOTAL_SUITES" -gt 0 ]; then + SUCCESS_RATE=$(( (PASSED_SUITES * 100) / TOTAL_SUITES )) +fi + +echo -e "Overall Success Rate: ${SUCCESS_RATE}%" +echo "" + +if [ "$FAILED_SUITES" -eq 0 ]; then + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} ✓ ALL TEST SUITES PASSED!${NC}" + echo -e "${GREEN}========================================${NC}" + exit 0 +else + echo -e "${RED}========================================${NC}" + echo -e "${RED} ✗ SOME TEST SUITES FAILED${NC}" + echo -e "${RED}========================================${NC}" + echo "" + echo -e "${YELLOW}Please review the output above to identify failed tests.${NC}" + exit 1 +fi diff --git a/run-tests.sh b/run-tests.sh new file mode 100644 index 0000000..2aff59a --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,242 @@ +#!/bin/bash + +# ============================================================================== +# IMPHNEN API Test Runner - Modular Test Suite +# ============================================================================== + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BASE_URL="${BASE_URL:-http://127.0.0.1:4099}" +TEST_EMAIL="${TEST_EMAIL:-admin@example.com}" +TEST_PASSWORD="${TEST_PASSWORD:-password}" +START_SERVER=false +SERVER_PID="" + +# Colors +CYAN='\033[0;36m' +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +YELLOW='\033[0;33m' +NC='\033[0m' + +# Parse command line arguments +while getopts "s" opt; do + case $opt in + s) + START_SERVER=true + ;; + \?) + echo "Usage: $0 [-s]" + echo " -s: Start the API server before running tests" + exit 1 + ;; + esac +done + +# Export variables for child scripts +export BASE_URL TEST_EMAIL TEST_PASSWORD + +echo -e "${CYAN}" +cat << 'EOF' +╔═══════════════════════════════════════════════════════════════════════╗ +║ IMPHNEN API TEST SUITE ║ +║ Modular Test Runner ║ +╚═══════════════════════════════════════════════════════════════════════╝ +EOF +echo -e "${NC}" + +echo -e "${BLUE}Configuration:${NC}" +echo -e " Base URL: ${GREEN}$BASE_URL${NC}" +echo -e " Test User: ${GREEN}$TEST_EMAIL${NC}" +echo "" + +# ============================================================================== +# Start Server if requested +# ============================================================================== + +if [ "$START_SERVER" = true ]; then + echo -e "${YELLOW}Starting API server...${NC}" + + # Force kill any existing api processes first + echo -e "${CYAN}Cleaning up any existing API processes...${NC}" + ps aux | grep "target/release/api" | grep -v grep | awk '{print $1}' | xargs kill -9 2>/dev/null || true + ps aux | grep "cargo run --bin api" | grep -v grep | awk '{print $1}' | xargs kill -9 2>/dev/null || true + sleep 2 + + echo -e "${CYAN}Building server in release mode...${NC}" + cargo build --bin api --release + + if [ $? -ne 0 ]; then + echo -e "${RED}Failed to compile server${NC}" + exit 1 + fi + + echo -e "${CYAN}Starting server in background...${NC}" + + # Start server directly from binary in background + nohup ./target/release/api > server.log 2>&1 & + SERVER_PID=$! + + echo -e "${CYAN}Server started with PID: $SERVER_PID${NC}" + + # Wait for server to be ready + echo -e "${CYAN}Waiting for server to be ready...${NC}" + MAX_WAIT=30 + WAIT_COUNT=0 + while true; do + # Check if any HTTP status code is returned (even 404/405 means server is up) + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/v1/auth/login" 2>/dev/null || echo "000") + if [ "$HTTP_CODE" != "000" ] && [ "$HTTP_CODE" != "" ]; then + break + fi + + sleep 1 + ((WAIT_COUNT++)) + if [ $WAIT_COUNT -ge $MAX_WAIT ]; then + echo -e "${RED}Server failed to start within $MAX_WAIT seconds${NC}" + echo -e "${RED}Server log:${NC}" + tail -20 server.log + if [ -n "$SERVER_PID" ]; then + kill $SERVER_PID 2>/dev/null + fi + exit 1 + fi + printf "." + done + echo "" + echo -e "${GREEN}✓ Server is ready!${NC}" + + # Run seeder to populate test data + echo -e "${CYAN}Running database seeder...${NC}" + cargo run --bin seeder --release > /dev/null 2>&1 || { + echo -e "${YELLOW}⚠ Seeder failed or already populated${NC}" + } + echo -e "${GREEN}✓ Database seeded${NC}" + echo "" +fi + +# Cleanup function +cleanup() { + if [ -n "$SERVER_PID" ] && [ "$START_SERVER" = true ]; then + echo -e "\n${YELLOW}Stopping server (PID: $SERVER_PID)...${NC}" + kill $SERVER_PID 2>/dev/null + sleep 1 + # Force kill if still running + if kill -0 $SERVER_PID 2>/dev/null; then + kill -9 $SERVER_PID 2>/dev/null + fi + echo -e "${GREEN}✓ Server stopped${NC}" + fi +} + +# Set trap to cleanup on exit +trap cleanup EXIT INT TERM + +# Test suite tracking +declare -A SUITE_RESULTS +TOTAL_SUITES=0 +PASSED_SUITES=0 +FAILED_SUITES=0 + +run_test_suite() { + local suite_name=$1 + local test_script=$2 + + ((TOTAL_SUITES++)) + + printf "\n${CYAN}════════════════════════════════════════════════════════════════${NC}\n" + printf "${BLUE}Running Test Suite: ${YELLOW}%s${NC}\n" "$suite_name" + printf "${CYAN}════════════════════════════════════════════════════════════════${NC}\n" + + if [ ! -f "$test_script" ]; then + printf "${RED}✗ Test script not found: %s${NC}\n" "$test_script" + SUITE_RESULTS["$suite_name"]="NOT_FOUND" + ((FAILED_SUITES++)) + return 1 + fi + + # Make script executable + chmod +x "$test_script" + + # Run test suite + if bash "$test_script"; then + SUITE_RESULTS["$suite_name"]="PASSED" + ((PASSED_SUITES++)) + printf "${GREEN}✓ Suite '%s' completed successfully${NC}\n" "$suite_name" + else + SUITE_RESULTS["$suite_name"]="FAILED" + ((FAILED_SUITES++)) + printf "${RED}✗ Suite '%s' failed${NC}\n" "$suite_name" + fi +} + +# ============================================================================== +# Run Test Suites +# ============================================================================== + +START_TIME=$(date +%s) + +# IAM Tests +run_test_suite "IAM - Authentication" "$SCRIPT_DIR/tests/iam/test-auth.sh" +run_test_suite "IAM - Users" "$SCRIPT_DIR/tests/iam/test-users.sh" +run_test_suite "IAM - Roles & Permissions" "$SCRIPT_DIR/tests/iam/test-roles-permissions.sh" +run_test_suite "IAM - Teams" "$SCRIPT_DIR/tests/iam/test-teams.sh" + +# Dimentorin Tests +run_test_suite "Dimentorin - Mentors" "$SCRIPT_DIR/tests/dimentorin/test-mentors.sh" + +# CMS Tests +run_test_suite "CMS - Events & Testimonials" "$SCRIPT_DIR/tests/cms/test-cms.sh" + +# Gacha Tests +run_test_suite "Gacha - Items & Rolls" "$SCRIPT_DIR/tests/gacha/test-gacha.sh" + +# Hackathon Tests +run_test_suite "Hackathon - Full Suite" "$SCRIPT_DIR/tests/hackathon/test-hackathon.sh" + +END_TIME=$(date +%s) +DURATION=$((END_TIME - START_TIME)) + +# ============================================================================== +# Final Summary +# ============================================================================== + +printf "\n${CYAN}════════════════════════════════════════════════════════════════${NC}\n" +printf "${BLUE} FINAL TEST SUMMARY ${NC}\n" +printf "${CYAN}════════════════════════════════════════════════════════════════${NC}\n\n" + +printf "Total Test Suites: ${BLUE}%d${NC}\n" "$TOTAL_SUITES" +printf "${GREEN}Passed Suites: %d${NC}\n" "$PASSED_SUITES" +printf "${RED}Failed Suites: %d${NC}\n" "$FAILED_SUITES" +printf "\n" + +if [ "$TOTAL_SUITES" -gt 0 ]; then + SUCCESS_RATE=$(( (PASSED_SUITES * 100) / TOTAL_SUITES )) + printf "Success Rate: ${BLUE}%d%%${NC}\n" "$SUCCESS_RATE" +fi + +printf "Total Duration: ${BLUE}%d seconds${NC}\n\n" "$DURATION" + +# Print individual suite results +printf "${BLUE}Suite Results:${NC}\n" +for suite in "${!SUITE_RESULTS[@]}"; do + result="${SUITE_RESULTS[$suite]}" + if [ "$result" = "PASSED" ]; then + printf " ${GREEN}✓${NC} %s\n" "$suite" + elif [ "$result" = "FAILED" ]; then + printf " ${RED}✗${NC} %s\n" "$suite" + else + printf " ${YELLOW}?${NC} %s (${result})\n" "$suite" + fi +done + +printf "\n${CYAN}════════════════════════════════════════════════════════════════${NC}\n" + +# Exit with appropriate code +if [ "$FAILED_SUITES" -eq 0 ]; then + printf "\n${GREEN}All test suites passed! 🎉${NC}\n\n" + exit 0 +else + printf "\n${RED}Some test suites failed. Please review the output above.${NC}\n\n" + exit 1 +fi diff --git a/test-comprehensive-api.sh b/test-comprehensive-api.sh new file mode 100644 index 0000000..679ebd9 --- /dev/null +++ b/test-comprehensive-api.sh @@ -0,0 +1,717 @@ +#!/bin/bash + +# ============================================================================== +# IMPHNEN API Comprehensive Test Suite - Extended Coverage +# Tests untuk semua endpoint yang belum tercakup di test.sh +# ============================================================================== + +# Source the main test.sh for shared variables and functions +# Assuming test.sh exports needed variables + +BASE_URL="${BASE_URL:-http://127.0.0.1:4099}" +AUTH_TOKEN="" + +# Colors +CYAN='\033[0;36m' +YELLOW='\033[0;33m' +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' + +PASS_COUNT=0 +FAIL_COUNT=0 +TEST_RESULTS=() +FAILED_TESTS_SUMMARY=() + +write_test_log() { + local level=$1 + local message=$2 + local color=$NC + + case $level in + "SUCCESS") color=$GREEN ;; + "ERROR") color=$RED ;; + "WARN") color=$YELLOW ;; + "INFO") color=$CYAN ;; + esac + + printf "[$(date +'%H:%M:%S')] [${color}%-7s${NC}] %s\n" "$level" "$message" >&2 +} + +test_api_endpoint() { + local test_name=$1 + local method=$2 + local endpoint=$3 + local expected_status=$4 + local body=$5 + local require_auth=$6 + + local headers=(-H "Content-Type: application/json") + if [[ "$require_auth" = true && -n "$AUTH_TOKEN" ]]; then + headers+=(-H "Authorization: Bearer $AUTH_TOKEN") + elif [[ "$require_auth" = true && -z "$AUTH_TOKEN" ]]; then + write_test_log "WARN" "✗ $test_name - Dilewati: token autentikasi tidak tersedia" + return + fi + + local start_req_time=$(date +%s%3N) + + local temp_file=$(mktemp) + local status_file=$(mktemp) + + curl -s -X "$method" "${headers[@]}" -d "$body" "$BASE_URL$endpoint" \ + -D "$status_file" -o "$temp_file" + + response_body=$(cat "$temp_file") + http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) + + rm -f "$temp_file" "$status_file" + + local end_req_time=$(date +%s%3N) + local duration=$((end_req_time - start_req_time)) + + local status="FAIL" + local error_msg="" + + if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq "$expected_status" ]; then + status="PASS" + ((PASS_COUNT++)) + write_test_log "SUCCESS" "✓ $test_name - Sukses (Status: $http_status, Waktu: ${duration}ms)" + else + status="FAIL" + ((FAIL_COUNT++)) + write_test_log "ERROR" " Response Body: $response_body" + if [[ ! "$http_status" =~ ^[0-9]+$ ]]; then + error_msg="Failed to get valid HTTP status code (got: $http_status)" + else + error_msg="Status yang diharapkan $expected_status, tetapi mendapat $http_status." + fi + write_test_log "ERROR" "✗ $test_name - Gagal: $error_msg" + FAILED_TESTS_SUMMARY+=("✗ $test_name - $error_msg") + fi + + result_json=$(jq -n --arg name "$test_name" --arg ep "$endpoint" --arg meth "$method" \ + --arg stat "$status" --arg code "$http_status" --arg dur "$duration" \ + --arg err "$error_msg" \ + '{TestName: $name, Endpoint: $ep, Method: $meth, Status: $stat, StatusCode: $code, ResponseTimeMs: $dur, Error: $err}') + TEST_RESULTS+=("$result_json") + printf "%s" "$response_body" +} + +get_auth_token() { + write_test_log "INFO" "Mengautentikasi test user..." + local login_data + login_data=$(jq -n '{email: "admin@example.com", password: "password"}') + + local temp_file=$(mktemp) + local status_file=$(mktemp) + + curl -s -X "POST" -H "Content-Type: application/json" -d "$login_data" "$BASE_URL/v1/auth/login" \ + -D "$status_file" -o "$temp_file" + + local response_body=$(cat "$temp_file") + local http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) + + rm -f "$temp_file" "$status_file" + + if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq 200 ]; then + AUTH_TOKEN=$(echo "$response_body" | jq -r '.data.token.access_token // empty') + if [[ -n "$AUTH_TOKEN" ]]; then + write_test_log "SUCCESS" "Autentikasi berhasil" + ((PASS_COUNT++)) + else + write_test_log "ERROR" "Token tidak ditemukan" + ((FAIL_COUNT++)) + fi + else + write_test_log "ERROR" "Login gagal dengan status: $http_status" + ((FAIL_COUNT++)) + fi +} + +# ============================================================================== +# IAM ENDPOINTS - AUTH +# ============================================================================== +test_auth_comprehensive() { + printf "\n${CYAN}=== Testing Auth Endpoints (Comprehensive) ===${NC}\n" + + # Login + local login_data=$(jq -n '{email: "admin@example.com", password: "password"}') + test_api_endpoint "POST /v1/auth/login" "POST" "/v1/auth/login" 200 "$login_data" false + + # Login Mentor + local mentor_login=$(jq -n '{email: "mentor@example.com", password: "password"}') + test_api_endpoint "POST /v1/auth/login-mentor" "POST" "/v1/auth/login-mentor" 200 "$mentor_login" false + + # Register (will fail without valid data, but tests endpoint) + local register_data=$(jq -n '{ + email: "newuser'$(date +%s)'@test.com", + password: "Password123!", + fullname: "Test User", + phone_number: "081234567890" + }') + test_api_endpoint "POST /v1/auth/register" "POST" "/v1/auth/register" 200 "$register_data" false + + # Verify Email (expect failure with fake OTP) + local verify_data=$(jq -n '{email: "test@test.com", otp: 123456}') + test_api_endpoint "POST /v1/auth/verify-email" "POST" "/v1/auth/verify-email" 401 "$verify_data" false + + # Resend OTP + local resend_data=$(jq -n '{email: "admin@example.com"}') + test_api_endpoint "POST /v1/auth/send-otp" "POST" "/v1/auth/send-otp" 200 "$resend_data" false + + # Forgot Password + test_api_endpoint "POST /v1/auth/forgot" "POST" "/v1/auth/forgot" 200 "$resend_data" false + + # New Password (expect failure with invalid token) + local new_pass_data=$(jq -n '{token: "invalid", password: "NewPass123!"}') + test_api_endpoint "POST /v1/auth/new-password" "POST" "/v1/auth/new-password" 400 "$new_pass_data" false + + # Refresh Token (get token first) + local refresh_token=$(curl -s -X POST -H "Content-Type: application/json" \ + -d "$login_data" "$BASE_URL/v1/auth/login" | jq -r '.data.token.refresh_token // empty') + + if [ -n "$refresh_token" ]; then + local refresh_data=$(jq -n --arg token "$refresh_token" '{refresh_token: $token}') + test_api_endpoint "POST /v1/auth/refresh" "POST" "/v1/auth/refresh" 200 "$refresh_data" false + fi + + # Logout + test_api_endpoint "POST /v1/auth/logout" "POST" "/v1/auth/logout" 200 "" true +} + +# ============================================================================== +# IAM ENDPOINTS - USERS +# ============================================================================== +test_users_comprehensive() { + printf "\n${CYAN}=== Testing Users Endpoints (Comprehensive) ===${NC}\n" + + # Get Users List + test_api_endpoint "GET /v1/users" "GET" "/v1/users" 200 "" true + test_api_endpoint "GET /v1/users?page=1&limit=10" "GET" "/v1/users?page=1&limit=10" 200 "" true + test_api_endpoint "GET /v1/users?search=admin" "GET" "/v1/users?search=admin" 200 "" true + test_api_endpoint "GET /v1/users?sort_by=created_at&order=DESC" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true + + # Get User Me + test_api_endpoint "GET /v1/users/me" "GET" "/v1/users/me" 200 "" true + + # Update User Me + local update_me_data=$(jq -n '{ + fullname: "Updated Admin", + phone_number: "081234567890", + gender: "Male", + birthdate: "1990-01-01" + }') + test_api_endpoint "PUT /v1/users/me" "PUT" "/v1/users/me" 200 "$update_me_data" true + + # Get User By ID (use a known ID from seed data) + local test_user_id="c3b1d6a8-8d4f-4b36-b789-2e532ec7a7b2" + test_api_endpoint "GET /v1/users/detail/:id" "GET" "/v1/users/detail/$test_user_id" 200 "" true + + # Create User + local create_user_data=$(jq -n '{ + email: "testuser'$(date +%s)'@test.com", + password: "Password123!", + fullname: "Test User Created", + phone_number: "081234567891", + is_active: true, + role_id: "5713cb37-dc02-4e87-8048-d7a41d352059" + }') + local create_response=$(test_api_endpoint "POST /v1/users/create" "POST" "/v1/users/create" 201 "$create_user_data" true) + local created_user_id=$(echo "$create_response" | jq -r '.data.id // empty') + + if [ -n "$created_user_id" ]; then + # Update User + local update_user_data=$(jq -n '{ + email: "updated'$(date +%s)'@test.com", + fullname: "Updated Test User", + phone_number: "081234567892", + is_active: true, + role_id: "5713cb37-dc02-4e87-8048-d7a41d352059" + }') + test_api_endpoint "PUT /v1/users/update/:id" "PUT" "/v1/users/update/$created_user_id" 200 "$update_user_data" true + + # Activate/Deactivate User + local activate_data=$(jq -n '{is_active: false}') + test_api_endpoint "PATCH /v1/users/activate/:id" "PATCH" "/v1/users/activate/$created_user_id" 200 "$activate_data" true + + local reactivate_data=$(jq -n '{is_active: true}') + test_api_endpoint "PATCH /v1/users/activate/:id (reactivate)" "PATCH" "/v1/users/activate/$created_user_id" 200 "$reactivate_data" true + + # Delete User + test_api_endpoint "DELETE /v1/users/delete/:id" "DELETE" "/v1/users/delete/$created_user_id" 200 "" true + fi + + # Upload File (requires multipart, skip for now) + # test_api_endpoint "POST /v1/users/upload" "POST" "/v1/users/upload" 200 "" true +} + +# ============================================================================== +# IAM ENDPOINTS - ROLES +# ============================================================================== +test_roles_comprehensive() { + printf "\n${CYAN}=== Testing Roles Endpoints (Comprehensive) ===${NC}\n" + + # Get Roles List + test_api_endpoint "GET /v1/roles" "GET" "/v1/roles" 200 "" true + test_api_endpoint "GET /v1/roles?page=1&limit=10" "GET" "/v1/roles?page=1&limit=10" 200 "" true + + # Get Role By ID + local test_role_id="5713cb37-dc02-4e87-8048-d7a41d352059" + test_api_endpoint "GET /v1/roles/:id" "GET" "/v1/roles/$test_role_id" 200 "" true + + # Create Role + local create_role_data=$(jq -n '{ + name: "Test Role '$(date +%s)'", + description: "Test role description", + permissions: [] + }') + local create_role_response=$(test_api_endpoint "POST /v1/roles" "POST" "/v1/roles" 201 "$create_role_data" true) + local created_role_id=$(echo "$create_role_response" | jq -r '.data.id // empty') + + if [ -n "$created_role_id" ]; then + # Update Role + local update_role_data=$(jq -n '{ + name: "Updated Test Role", + description: "Updated description", + permissions: [] + }') + test_api_endpoint "PUT /v1/roles/:id" "PUT" "/v1/roles/$created_role_id" 200 "$update_role_data" true + + # Delete Role + test_api_endpoint "DELETE /v1/roles/:id" "DELETE" "/v1/roles/$created_role_id" 200 "" true + fi +} + +# ============================================================================== +# IAM ENDPOINTS - PERMISSIONS +# ============================================================================== +test_permissions_comprehensive() { + printf "\n${CYAN}=== Testing Permissions Endpoints (Comprehensive) ===${NC}\n" + + # Get Permissions List + test_api_endpoint "GET /v1/permissions" "GET" "/v1/permissions" 200 "" true + test_api_endpoint "GET /v1/permissions?page=1&limit=10" "GET" "/v1/permissions?page=1&limit=10" 200 "" true + + # Get Permission By ID (use known ID) + local test_perm_id="00000000-0000-0000-0000-000000000001" + test_api_endpoint "GET /v1/permissions/:id" "GET" "/v1/permissions/$test_perm_id" 200 "" true + + # Create Permission + local create_perm_data=$(jq -n '{ + name: "Test Permission '$(date +%s)'", + description: "Test permission description" + }') + local create_perm_response=$(test_api_endpoint "POST /v1/permissions" "POST" "/v1/permissions" 201 "$create_perm_data" true) + local created_perm_id=$(echo "$create_perm_response" | jq -r '.data.id // empty') + + if [ -n "$created_perm_id" ]; then + # Update Permission + local update_perm_data=$(jq -n '{ + name: "Updated Test Permission", + description: "Updated description" + }') + test_api_endpoint "PUT /v1/permissions/:id" "PUT" "/v1/permissions/$created_perm_id" 200 "$update_perm_data" true + + # Delete Permission + test_api_endpoint "DELETE /v1/permissions/:id" "DELETE" "/v1/permissions/$created_perm_id" 200 "" true + fi +} + +# ============================================================================== +# IAM ENDPOINTS - TEAMS +# ============================================================================== +test_teams_comprehensive() { + printf "\n${CYAN}=== Testing Teams Endpoints (Comprehensive) ===${NC}\n" + + # Admin Endpoints + test_api_endpoint "GET /v1/teams/admin" "GET" "/v1/teams/admin" 200 "" true + test_api_endpoint "GET /v1/teams/admin?page=1&limit=10" "GET" "/v1/teams/admin?page=1&limit=10" 200 "" true + + # Public Endpoints + test_api_endpoint "GET /v1/teams" "GET" "/v1/teams" 200 "" false + test_api_endpoint "GET /v1/teams?search=test" "GET" "/v1/teams?search=test" 200 "" false + test_api_endpoint "GET /v1/teams/search?query=dev" "GET" "/v1/teams/search?query=dev" 200 "" false + + # Get Team By ID + local test_team_id="team-001" + test_api_endpoint "GET /v1/teams/admin/:id" "GET" "/v1/teams/admin/$test_team_id" 200 "" true + test_api_endpoint "GET /v1/teams/admin/:id/members" "GET" "/v1/teams/admin/$test_team_id/members" 200 "" true + + # Create Team + local create_team_data=$(jq -n '{ + name: "Test Team '$(date +%s)'", + description: "Test team description", + is_open: true, + max_members: 5 + }') + local create_team_response=$(test_api_endpoint "POST /v1/teams/admin" "POST" "/v1/teams/admin" 201 "$create_team_data" true) + local created_team_id=$(echo "$create_team_response" | jq -r '.data.id // empty') + + if [ -n "$created_team_id" ]; then + # Update Team + local update_team_data=$(jq -n '{ + name: "Updated Test Team", + description: "Updated description", + is_open: false, + max_members: 10 + }') + test_api_endpoint "PUT /v1/teams/admin/:id" "PUT" "/v1/teams/admin/$created_team_id" 200 "$update_team_data" true + + # Invite Members + local invite_data=$(jq -n '{ + user_ids: ["c3b1d6a8-8d4f-4b36-b789-2e532ec7a7b2"] + }') + test_api_endpoint "POST /v1/teams/admin/:id/invite" "POST" "/v1/teams/admin/$created_team_id/invite" 200 "$invite_data" true + + # Delete Team + test_api_endpoint "DELETE /v1/teams/admin/:id" "DELETE" "/v1/teams/admin/$created_team_id" 200 "" true + fi +} + +# ============================================================================== +# DIMENTORIN ENDPOINTS - MENTORS +# ============================================================================== +test_mentors_comprehensive() { + printf "\n${CYAN}=== Testing Mentors Endpoints (Comprehensive) ===${NC}\n" + + # Get Mentors List + test_api_endpoint "GET /v1/mentors" "GET" "/v1/mentors" 200 "" true + test_api_endpoint "GET /v1/mentors?page=1&limit=10" "GET" "/v1/mentors?page=1&limit=10" 200 "" true + test_api_endpoint "GET /v1/mentors?search=mentor" "GET" "/v1/mentors?search=mentor" 200 "" true + + # Get Mentor By ID + local test_mentor_id="mentor-001" + test_api_endpoint "GET /v1/mentors/:id" "GET" "/v1/mentors/$test_mentor_id" 200 "" true + + # Get Mentor Me (requires mentor token) + # test_api_endpoint "GET /v1/mentors/me" "GET" "/v1/mentors/me" 200 "" true + + # Get Mentor Status + # test_api_endpoint "GET /v1/mentors/status" "GET" "/v1/mentors/status" 200 "" true + + # Register Mentor + local register_mentor_data=$(jq -n '{ + expertise: ["Rust", "Backend"], + bio: "Test mentor bio", + linkedin_url: "https://linkedin.com/in/test", + github_url: "https://github.com/test", + portfolio_url: "https://test.com" + }') + # test_api_endpoint "POST /v1/mentors/register" "POST" "/v1/mentors/register" 201 "$register_mentor_data" true + + # Update Mentor (admin) + # local update_mentor_data=$(jq -n '{...}') + # test_api_endpoint "PUT /v1/mentors/:id" "PUT" "/v1/mentors/$test_mentor_id" 200 "$update_mentor_data" true + + # Verify Mentor (admin) + local verify_data=$(jq -n '{is_verified: true}') + test_api_endpoint "PUT /v1/mentors/:id/verify" "PUT" "/v1/mentors/$test_mentor_id/verify" 200 "$verify_data" true + + # Delete Mentor (admin) + # test_api_endpoint "DELETE /v1/mentors/:id" "DELETE" "/v1/mentors/$test_mentor_id" 200 "" true +} + +# ============================================================================== +# CMS ENDPOINTS - EVENTS +# ============================================================================== +test_events_comprehensive() { + printf "\n${CYAN}=== Testing Events Endpoints (Comprehensive) ===${NC}\n" + + # Public Endpoints + test_api_endpoint "GET /v1/cms/landing/events" "GET" "/v1/cms/landing/events" 200 "" false + test_api_endpoint "GET /v1/cms/landing/events?page=1&limit=10" "GET" "/v1/cms/landing/events?page=1&limit=10" 200 "" false + test_api_endpoint "GET /v1/cms/landing/events?search=test" "GET" "/v1/cms/landing/events?search=test" 200 "" false + + # Get Event By ID + # Need to get an event ID first + local events_response=$(curl -s "$BASE_URL/v1/cms/landing/events") + local test_event_id=$(echo "$events_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_event_id" ]; then + test_api_endpoint "GET /v1/cms/landing/events/:id" "GET" "/v1/cms/landing/events/$test_event_id" 200 "" false + fi + + # Create Event (protected) + local create_event_data=$(jq -n '{ + title: "Test Event '$(date +%s)'", + description: "Test event description", + event_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + location: "Online", + image_url: "https://example.com/image.jpg", + is_online: true + }') + local create_event_response=$(test_api_endpoint "POST /v1/cms/landing/events/create" "POST" "/v1/cms/landing/events/create" 201 "$create_event_data" true) + local created_event_id=$(echo "$create_event_response" | jq -r '.data.id // empty') + + if [ -n "$created_event_id" ]; then + # Update Event + local update_event_data=$(jq -n '{ + title: "Updated Test Event", + description: "Updated description", + event_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + location: "Jakarta", + is_online: false + }') + test_api_endpoint "PATCH /v1/cms/landing/events/:id" "PATCH" "/v1/cms/landing/events/$created_event_id" 200 "$update_event_data" true + + # Delete Event + test_api_endpoint "DELETE /v1/cms/landing/events/:id" "DELETE" "/v1/cms/landing/events/$created_event_id" 200 "" true + fi +} + +# ============================================================================== +# CMS ENDPOINTS - TESTIMONIALS +# ============================================================================== +test_testimonials_comprehensive() { + printf "\n${CYAN}=== Testing Testimonials Endpoints (Comprehensive) ===${NC}\n" + + # Public Endpoints + test_api_endpoint "GET /v1/cms/landing/testimonials" "GET" "/v1/cms/landing/testimonials" 200 "" false + test_api_endpoint "GET /v1/cms/landing/testimonials?page=1&limit=10" "GET" "/v1/cms/landing/testimonials?page=1&limit=10" 200 "" false + + # Get Testimonial By ID + local testimonials_response=$(curl -s "$BASE_URL/v1/cms/landing/testimonials") + local test_testimonial_id=$(echo "$testimonials_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_testimonial_id" ]; then + test_api_endpoint "GET /v1/cms/landing/testimonials/:id" "GET" "/v1/cms/landing/testimonials/$test_testimonial_id" 200 "" false + fi + + # Create Testimonial (protected) + local create_testimonial_data=$(jq -n '{ + role: "Student", + content: "Test testimonial content '$(date +%s)'" + }') + local create_testimonial_response=$(test_api_endpoint "POST /v1/cms/landing/testimonials/create" "POST" "/v1/cms/landing/testimonials/create" 201 "$create_testimonial_data" true) + local created_testimonial_id=$(echo "$create_testimonial_response" | jq -r '.data.id // empty') + + if [ -n "$created_testimonial_id" ]; then + # Update Testimonial + local update_testimonial_data=$(jq -n '{ + role: "Alumni", + content: "Updated testimonial content" + }') + test_api_endpoint "PATCH /v1/cms/landing/testimonials/:id" "PATCH" "/v1/cms/landing/testimonials/$created_testimonial_id" 200 "$update_testimonial_data" true + + # Delete Testimonial + test_api_endpoint "DELETE /v1/cms/landing/testimonials/:id" "DELETE" "/v1/cms/landing/testimonials/$created_testimonial_id" 200 "" true + fi +} + +# ============================================================================== +# GACHA ENDPOINTS +# ============================================================================== +test_gacha_comprehensive() { + printf "\n${CYAN}=== Testing Gacha Endpoints (Comprehensive) ===${NC}\n" + + # Gacha Items + test_api_endpoint "GET /v1/gacha/items" "GET" "/v1/gacha/items" 200 "" true + test_api_endpoint "GET /v1/gacha/items?page=1&limit=10" "GET" "/v1/gacha/items?page=1&limit=10" 200 "" true + + # Get Gacha Item By ID + local items_response=$(curl -s -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/gacha/items") + local test_item_id=$(echo "$items_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_item_id" ]; then + test_api_endpoint "GET /v1/gacha/items/:id" "GET" "/v1/gacha/items/$test_item_id" 200 "" true + fi + + # Create Gacha Item + local create_item_data=$(jq -n '{ + name: "Test Item '$(date +%s)'", + description: "Test item description", + rarity: "COMMON", + image_url: "https://example.com/item.jpg", + weight: 100 + }') + local create_item_response=$(test_api_endpoint "POST /v1/gacha/items" "POST" "/v1/gacha/items" 201 "$create_item_data" true) + local created_item_id=$(echo "$create_item_response" | jq -r '.data.id // empty') + + if [ -n "$created_item_id" ]; then + # Update Gacha Item + local update_item_data=$(jq -n '{ + name: "Updated Test Item", + description: "Updated description", + rarity: "RARE", + weight: 50 + }') + test_api_endpoint "PUT /v1/gacha/items/:id" "PUT" "/v1/gacha/items/$created_item_id" 200 "$update_item_data" true + + # Delete Gacha Item + test_api_endpoint "DELETE /v1/gacha/items/:id" "DELETE" "/v1/gacha/items/$created_item_id" 200 "" true + fi + + # Gacha Rolls + test_api_endpoint "POST /v1/gacha/rolls" "POST" "/v1/gacha/rolls" 201 "{}" true + test_api_endpoint "POST /v1/gacha/rolls/execute" "POST" "/v1/gacha/rolls/execute" 200 "{}" true + + # Gacha Credits (internal endpoints, may require special auth) + # test_api_endpoint "GET /v1/gacha/credits" "GET" "/v1/gacha/credits" 200 "" true + # test_api_endpoint "POST /v1/gacha/credits/add" "POST" "/v1/gacha/credits/add" 200 '{"amount": 10}' true + # test_api_endpoint "POST /v1/gacha/credits/consume" "POST" "/v1/gacha/credits/consume" 200 '{"amount": 1}' true + + # Gacha Claims + # test_api_endpoint "POST /v1/gacha/claims" "POST" "/v1/gacha/claims" 201 "{}" true +} + +# ============================================================================== +# HACKATHON ENDPOINTS +# ============================================================================== +test_hackathon_comprehensive() { + printf "\n${CYAN}=== Testing Hackathon Endpoints (Comprehensive) ===${NC}\n" + + # Get Hackathons + test_api_endpoint "GET /v1/hackathons" "GET" "/v1/hackathons" 200 "" false + test_api_endpoint "GET /v1/hackathons?page=1&limit=10" "GET" "/v1/hackathons?page=1&limit=10" 200 "" false + + # Create Hackathon + local create_hackathon_data=$(jq -n '{ + title: "Test Hackathon '$(date +%s)'", + description: "Test hackathon description", + start_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + end_date: "'$(date -u -d '+7 days' +%Y-%m-%dT%H:%M:%SZ)'", + registration_deadline: "'$(date -u -d '+1 day' +%Y-%m-%dT%H:%M:%SZ)'", + max_teams: 100, + max_team_size: 5 + }') + local create_hackathon_response=$(test_api_endpoint "POST /v1/hackathons" "POST" "/v1/hackathons" 201 "$create_hackathon_data" true) + local created_hackathon_id=$(echo "$create_hackathon_response" | jq -r '.data.id // empty') + + if [ -n "$created_hackathon_id" ]; then + # Get Hackathon By ID + test_api_endpoint "GET /v1/hackathons/:id" "GET" "/v1/hackathons/$created_hackathon_id" 200 "" false + + # Update Hackathon + local update_hackathon_data=$(jq -n '{ + title: "Updated Test Hackathon", + description: "Updated description", + max_teams: 150 + }') + test_api_endpoint "PUT /v1/hackathons/:id" "PUT" "/v1/hackathons/$created_hackathon_id" 200 "$update_hackathon_data" true + + # Hackathon Events + local create_event_data=$(jq -n --arg hackathon_id "$created_hackathon_id" '{ + hackathon_id: $hackathon_id, + title: "Test Event", + description: "Test event description", + event_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + location: "Online", + is_mandatory: false + }') + local create_event_response=$(test_api_endpoint "POST /v1/hackathons/:id/events" "POST" "/v1/hackathons/$created_hackathon_id/events" 201 "$create_event_data" true) + local created_event_id=$(echo "$create_event_response" | jq -r '.data.id // empty') + + if [ -n "$created_event_id" ]; then + # Update Event + local update_event_data=$(jq -n '{ + title: "Updated Test Event", + is_mandatory: true + }') + test_api_endpoint "PUT /v1/hackathons/events/:id" "PUT" "/v1/hackathons/events/$created_event_id" 200 "$update_event_data" true + + # Delete Event + test_api_endpoint "DELETE /v1/hackathons/events/:id" "DELETE" "/v1/hackathons/events/$created_event_id" 200 "" true + fi + + # Hackathon Timeline + local create_timeline_data=$(jq -n --arg hackathon_id "$created_hackathon_id" '{ + hackathon_id: $hackathon_id, + phase_name: "Registration", + description: "Registration phase", + start_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + end_date: "'$(date -u -d '+1 day' +%Y-%m-%dT%H:%M:%SZ)'", + allowed_operations: ["REGISTER"] + }') + local create_timeline_response=$(test_api_endpoint "POST /v1/hackathons/:id/timeline" "POST" "/v1/hackathons/$created_hackathon_id/timeline" 201 "$create_timeline_data" true) + local created_timeline_id=$(echo "$create_timeline_response" | jq -r '.data.id // empty') + + if [ -n "$created_timeline_id" ]; then + # Update Timeline + local update_timeline_data=$(jq -n '{ + phase_name: "Updated Registration", + description: "Updated description" + }') + test_api_endpoint "PUT /v1/hackathons/timeline/:id" "PUT" "/v1/hackathons/timeline/$created_timeline_id" 200 "$update_timeline_data" true + + # Delete Timeline + test_api_endpoint "DELETE /v1/hackathons/timeline/:id" "DELETE" "/v1/hackathons/timeline/$created_timeline_id" 200 "" true + fi + + # Hackathon Submissions + # test_api_endpoint "GET /v1/hackathons/:id/submissions" "GET" "/v1/hackathons/$created_hackathon_id/submissions" 200 "" true + # test_api_endpoint "GET /v1/hackathons/submissions/me" "GET" "/v1/hackathons/submissions/me" 200 "" true + + # Admin Results + # test_api_endpoint "GET /v1/hackathons/:id/results" "GET" "/v1/hackathons/$created_hackathon_id/results" 200 "" true + + # Public Results + # test_api_endpoint "GET /v1/hackathons/:id/results/public" "GET" "/v1/hackathons/$created_hackathon_id/results/public" 200 "" false + + # Delete Hackathon + test_api_endpoint "DELETE /v1/hackathons/:id" "DELETE" "/v1/hackathons/$created_hackathon_id" 200 "" true + fi +} + +# ============================================================================== +# MAIN EXECUTION +# ============================================================================== +main() { + printf "\n${CYAN}========================================${NC}\n" + printf "${CYAN} IMPHNEN Comprehensive API Test Suite${NC}\n" + printf "${CYAN}========================================${NC}\n\n" + + write_test_log "INFO" "Starting comprehensive API tests..." + write_test_log "INFO" "Base URL: $BASE_URL" + + # Get authentication token first + get_auth_token + + if [ -z "$AUTH_TOKEN" ]; then + write_test_log "ERROR" "Failed to get auth token. Cannot proceed with protected endpoint tests." + exit 1 + fi + + # Run all comprehensive tests + test_auth_comprehensive + test_users_comprehensive + test_roles_comprehensive + test_permissions_comprehensive + test_teams_comprehensive + test_mentors_comprehensive + test_events_comprehensive + test_testimonials_comprehensive + test_gacha_comprehensive + test_hackathon_comprehensive + + # Print summary + local total_tests=$((PASS_COUNT + FAIL_COUNT)) + local success_rate=0 + if [ "$total_tests" -gt 0 ]; then + success_rate=$(( (PASS_COUNT * 100) / total_tests )) + fi + + printf "\n${CYAN}========================================${NC}\n" + printf "${CYAN} Test Summary${NC}\n" + printf "${CYAN}========================================${NC}\n" + printf "Total Tests: %d\n" "$total_tests" + printf "${GREEN}Passed: %d${NC}\n" "$PASS_COUNT" + printf "${RED}Failed: %d${NC}\n" "$FAIL_COUNT" + printf "Success Rate: %d%%\n\n" "$success_rate" + + if [ "$FAIL_COUNT" -gt 0 ]; then + printf "${RED}Failed Tests:${NC}\n" + for summary in "${FAILED_TESTS_SUMMARY[@]}"; do + printf " %s\n" "$summary" + done + printf "\n" + exit 1 + else + printf "${GREEN}All tests passed!${NC}\n\n" + exit 0 + fi +} + +# Run main function +main "$@" diff --git a/test.sh b/test.sh deleted file mode 100644 index 218192a..0000000 --- a/test.sh +++ /dev/null @@ -1,1532 +0,0 @@ -#!/bin/bash - -# ============================================================================== -# IMPHNEN API Comprehensive Test Suite (Bash Version) -# ============================================================================== - -BASE_URL="http://127.0.0.1:4099" -TEST_EMAIL="admin@example.com" -TEST_PASSWORD="password" - -declare -A ALL_USERS=( - ["admin@example.com"]="Admin" - ["staff@example.com"]="Staff" - ["user@example.com"]="User" - ["testuser1@example.com"]="Test User 1" - ["testuser2@example.com"]="Test User 2" - ["testuser3@example.com"]="Test User 3" - ["mentor@example.com"]="Mentor User" -) - -START_SERVER=false -SKIP_BASIC=false -SKIP_COMPREHENSIVE=false -SKIP_CRUD=false -GENERATE_REPORT=false -VERBOSE=false -SKIP_CLEAR=false -SKIP_SEED=false - -while getopts "sbcrgvhkd" opt; do - case ${opt} in - s ) START_SERVER=true ;; - b ) SKIP_BASIC=true ;; - c ) SKIP_COMPREHENSIVE=true ;; - r ) SKIP_CRUD=true ;; - g ) GENERATE_REPORT=true ;; - v ) VERBOSE=true ;; - h ) - echo "IMPHNEN API Test Suite" - echo "Usage: $0 [OPTIONS]" - echo "" - echo "Options:" - echo " -s Start server automatically" - echo " -b Skip basic tests (auth, error handling)" - echo " -c Skip comprehensive tests (users, roles, mentors, etc.)" - echo " -r Skip CRUD and advanced tests" - echo " -g Generate JSON test report" - echo " -v Verbose output (show all INFO logs)" - echo " -h Show this help message" - echo " -d Skip database clear" - echo " -k Skip database seeding" - echo "" - echo "Examples:" - echo " $0 # Run all tests" - echo " $0 -s # Start server and run all tests" - echo " $0 -g # Run tests and generate report" - echo " $0 -sv # Start server with verbose output" - echo " $0 -bc # Run only public endpoint tests" - echo " $0 -d # Skip database clear" - echo " $0 -k # Skip database seeding" - echo " $0 -dk # Skip database clear and seeding" - exit 0 - ;; - d ) SKIP_CLEAR=true ;; - k ) SKIP_SEED=true ;; - \? ) echo "Invalid option: -$OPTARG" >&2; echo "Use -h for help" >&2; exit 1 ;; - esac -done -# Shift past the options -shift "$((OPTIND-1))" - -if ! command -v curl &> /dev/null; then - echo "Error: 'curl' tidak ditemukan. Mohon install terlebih dahulu." >&2 - exit 1 -fi -if ! command -v jq &> /dev/null; then - echo "Error: 'jq' tidak ditemukan. Mohon install terlebih dahulu." >&2 - exit 1 -fi - -TEST_START_TIME=$(date +%s) -AUTH_TOKEN="" -SERVER_PID="" -TEST_RESULTS=() -FAILED_TESTS_SUMMARY=() -PASS_COUNT=0 -FAIL_COUNT=0 -TEST_TESTIMONIAL_ID="" -TEST_EVENT_ID="" - -CYAN='\033[0;36m' -YELLOW='\033[0;33m' -GREEN='\033[0;32m' -RED='\033[0;31m' -BLUE='\033[0;34m' -NC='\033[0m' - -cleanup() { - if [ -n "$SERVER_PID" ]; then - printf "\n${YELLOW}Menghentikan proses server...${NC}\n" - kill "$SERVER_PID" &>/dev/null - fi -} -trap cleanup EXIT - -write_test_log() { - local level=$1 - local message=$2 - local color=$NC - - case $level in - "SUCCESS") color=$GREEN ;; - "ERROR") color=$RED ;; - "WARN") color=$YELLOW ;; - "INFO") color=$CYAN ;; - esac - - if [[ "$VERBOSE" = true || "$level" != "INFO" ]]; then - printf "[$(date +'%H:%M:%S')] [${color}%-7s${NC}] %s\n" "$level" "$message" >&2 - fi -} - -test_api_endpoint() { - local test_name=$1 - local method=$2 - local endpoint=$3 - local expected_status=$4 - local body=$5 - local require_auth=$6 - - local headers=(-H "Content-Type: application/json") - if [[ "$require_auth" = true && -n "$AUTH_TOKEN" ]]; then - headers+=(-H "Authorization: Bearer $AUTH_TOKEN") - elif [[ "$require_auth" = true && -z "$AUTH_TOKEN" ]]; then - write_test_log "WARN" "✗ $test_name - Dilewati: token autentikasi tidak tersedia" - return - fi - - local start_req_time=$(date +%s%3N) - - # Use a more compatible approach for Windows/Git Bash - local temp_file=$(mktemp) - local status_file=$(mktemp) - - # Make single request and capture both body and status using response headers - curl -s -X "$method" "${headers[@]}" -d "$body" "$BASE_URL$endpoint" \ - -D "$status_file" -o "$temp_file" - - response_body=$(cat "$temp_file") - - # Extract HTTP status code from headers file - http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - - local end_req_time=$(date +%s%3N) - local duration=$((end_req_time - start_req_time)) - - local status="FAIL" - local error_msg="" - - # Check if http_status is numeric - if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq "$expected_status" ]; then - status="PASS" - ((PASS_COUNT++)) - write_test_log "SUCCESS" "✓ $test_name - Sukses (Status: $http_status, Waktu: ${duration}ms)" - else - status="FAIL" - ((FAIL_COUNT++)) - write_test_log "ERROR" " Request Body: $body" - write_test_log "ERROR" " Response Body: $response_body" - if [[ ! "$http_status" =~ ^[0-9]+$ ]]; then - error_msg="Failed to get valid HTTP status code (got: $http_status)" - else - error_msg="Status yang diharapkan $expected_status, tetapi mendapat $http_status." - fi - write_test_log "ERROR" "✗ $test_name - Gagal: $error_msg" - FAILED_TESTS_SUMMARY+=("✗ $test_name - $error_msg") - fi - - result_json=$(jq -n --arg name "$test_name" --arg ep "$endpoint" --arg meth "$method" \ - --arg stat "$status" --arg code "$http_status" --arg dur "$duration" \ - --arg err "$error_msg" \ - '{TestName: $name, Endpoint: $ep, Method: $meth, Status: $stat, StatusCode: $code, ResponseTimeMs: $dur, Error: $err}') - TEST_RESULTS+=("$result_json") - # Return response_body for further processing if needed by the caller - # Print the response body to stdout so callers can capture it with command substitution - printf "%s" "$response_body" -} - -test_server_connection() { - curl -s --head "$BASE_URL/v1/cms/landing/events" > /dev/null - return $? -} - -clear_database() { - if [ "$SKIP_CLEAR" = true ]; then - write_test_log "INFO" "Melewatkan pembersihan database." - return - fi - write_test_log "INFO" "Membersihkan database via WebSocket..." - if ! RUST_LOG=debug cargo run --bin clear_db_test --release; then - write_test_log "ERROR" "Gagal membersihkan database." - exit 1 - fi - write_test_log "SUCCESS" "Pembersihan database selesai." -} - -get_auth_token() { - write_test_log "INFO" "Mengautentikasi test user..." - local login_data - login_data=$(jq -n --arg email "$TEST_EMAIL" --arg pass "$TEST_PASSWORD" '{email: $email, password: $pass}') - - local headers=(-H "Content-Type: application/json") - local start_req_time=$(date +%s%3N) - - # Use a more compatible approach for Windows/Git Bash - local temp_file=$(mktemp) - local status_file=$(mktemp) - - # Make single request and capture both body and status using response headers - curl -s -X "POST" "${headers[@]}" -d "$login_data" "$BASE_URL/v1/auth/login" \ - -D "$status_file" -o "$temp_file" - - local response_body=$(cat "$temp_file") - - # Extract HTTP status code from headers file - local http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - local end_req_time=$(date +%s%3N) - local duration=$((end_req_time - start_req_time)) - - if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq 200 ]; then - if echo "$response_body" | jq . > /dev/null 2>&1; then - AUTH_TOKEN=$(echo "$response_body" | jq -r '.data.token.access_token // empty') - if [[ -n "$AUTH_TOKEN" && "$AUTH_TOKEN" != "null" ]]; then - write_test_log "SUCCESS" "✓ User Authentication - Sukses (Status: $http_status, Waktu: ${duration}ms)" - write_test_log "SUCCESS" "Autentikasi berhasil" - ((PASS_COUNT++)) - else - write_test_log "ERROR" "Autentikasi gagal - token tidak ditemukan dalam response" - AUTH_TOKEN="" - ((FAIL_COUNT++)) - fi - else - write_test_log "ERROR" "Autentikasi gagal - response bukan JSON valid" - AUTH_TOKEN="" - ((FAIL_COUNT++)) - fi - else - write_test_log "ERROR" "✗ User Authentication - Gagal (Status: $http_status, Waktu: ${duration}ms)" - AUTH_TOKEN="" - ((FAIL_COUNT++)) - fi - - local status="PASS" - local error_msg="" - if [[ ! "$http_status" =~ ^[0-9]+$ ]] || [ "$http_status" -ne 200 ] || [[ -z "$AUTH_TOKEN" ]]; then - status="FAIL" - if [[ ! "$http_status" =~ ^[0-9]+$ ]]; then - error_msg="Failed to get valid HTTP status code (got: $http_status)" - else - error_msg="Authentication failed" - fi - fi - - result_json=$(jq -n --arg name "User Authentication" --arg ep "/v1/auth/login" --arg meth "POST" \ - --arg stat "$status" --arg code "$http_status" --arg dur "$duration" \ - --arg err "$error_msg" \ - '{TestName: $name, Endpoint: $ep, Method: $meth, Status: $stat, StatusCode: $code, ResponseTimeMs: $dur, Error: $err}') - TEST_RESULTS+=("$result_json") -} - -test_all_users_login_performance() { - printf "\n${CYAN}=== Menguji Login Performance Semua User ===${NC}\n" - - local total_login_time=0 - local successful_logins=0 - local failed_logins=0 - - local email="admin@example.com" - local fullname="${ALL_USERS[$email]}" - write_test_log "INFO" "Testing login for: $fullname ($email)" - - local login_data - login_data=$(jq -n --arg email "$email" --arg pass "$TEST_PASSWORD" '{email: $email, password: $pass}') - - local start_time=$(date +%s%3N) - - # Use a more compatible approach for Windows/Git Bash - local temp_file=$(mktemp) - local status_file=$(mktemp) - - # Make single request and capture both body and status using response headers - curl -s -X "POST" -H "Content-Type: application/json" -d "$login_data" "$BASE_URL/v1/auth/login" \ - -D "$status_file" -o "$temp_file" - - local response_body=$(cat "$temp_file") - - # Extract HTTP status code from headers file - local http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - local end_time=$(date +%s%3N) - local duration=$((end_time - start_time)) - - total_login_time=$((total_login_time + duration)) - - if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq 200 ]; then - if echo "$response_body" | jq -e '.data.token.access_token' > /dev/null 2>&1; then - ((successful_logins++)) - ((PASS_COUNT++)) - write_test_log "SUCCESS" "✓ Login $fullname - ${duration}ms" - - result_json=$(jq -n --arg name "Login Performance - $fullname" --arg ep "/v1/auth/login" --arg meth "POST" \ - --arg stat "PASS" --arg code "$http_status" --arg dur "$duration" \ - --arg err "" \ - '{TestName: $name, Endpoint: $ep, Method: $meth, Status: $stat, StatusCode: $code, ResponseTimeMs: $dur, Error: $err}') - TEST_RESULTS+=("$result_json") - else - ((failed_logins++)) - ((FAIL_COUNT++)) - write_test_log "ERROR" "✗ Login $fullname - No token (${duration}ms)" - FAILED_TESTS_SUMMARY+=("✗ Login $fullname - No token in response") - fi - else - ((failed_logins++)) - ((FAIL_COUNT++)) - write_test_log "ERROR" "✗ Login $fullname - HTTP $http_status (${duration}ms)" - FAILED_TESTS_SUMMARY+=("✗ Login $fullname - HTTP $http_status") - fi - - local total_users=1 - local avg_login_time=0 - if [ "$total_users" -gt 0 ]; then - avg_login_time=$((total_login_time / total_users)) - fi - - printf "\n${BLUE}=== Login Performance Summary ===${NC}\n" - printf "Total Users Tested: %d\n" "$total_users" - printf "${GREEN}Successful Logins: %d${NC}\n" "$successful_logins" - printf "${RED}Failed Logins: %d${NC}\n" "$failed_logins" - printf "${BLUE}Average Login Time: %dms${NC}\n" "$avg_login_time" - printf "${BLUE}Total Login Time: %dms${NC}\n" "$total_login_time" - - if [ "$avg_login_time" -lt 2000 ]; then - printf "${GREEN}✅ Performance Status: EXCELLENT (< 2s average)${NC}\n" - elif [ "$avg_login_time" -lt 5000 ]; then - printf "${YELLOW}⚠️ Performance Status: GOOD (2-5s average)${NC}\n" - else - printf "${RED}❌ Performance Status: POOR (> 5s average)${NC}\n" - fi - printf "\n" -} - -test_with_user() { - local email=$1 - local fullname=$2 - local test_name=$3 - - write_test_log "INFO" "Testing $test_name dengan user: $fullname ($email)" - - local login_data - login_data=$(jq -n --arg email "$email" --arg pass "$TEST_PASSWORD" '{email: $email, password: $pass}') - local start_time=$(date +%s%3N) - - # Use a more compatible approach for Windows/Git Bash - local temp_file=$(mktemp) - local status_file=$(mktemp) - - # Make single request and capture both body and status using response headers - curl -s -X "POST" -H "Content-Type: application/json" -d "$login_data" "$BASE_URL/v1/auth/login" \ - -D "$status_file" -o "$temp_file" - - local response_body=$(cat "$temp_file") - - # Extract HTTP status code from headers file - local http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - local end_time=$(date +%s%3N) - local duration=$((end_time - start_time)) - - if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq 200 ]; then - if echo "$response_body" | jq -e '.data.token.access_token' > /dev/null 2>&1; then - local user_auth_token=$(echo "$response_body" | jq -r '.data.token.access_token') - write_test_log "SUCCESS" "✓ Login $fullname berhasil - ${duration}ms" - - local me_response - # Use a more compatible approach for Windows/Git Bash - local temp_file=$(mktemp) - local status_file=$(mktemp) - - # Make single request and capture both body and status using response headers - curl -s -X "GET" -H "Content-Type: application/json" -H "Authorization: Bearer $user_auth_token" "$BASE_URL/v1/users/me" \ - -D "$status_file" -o "$temp_file" - - local me_body=$(cat "$temp_file") - - # Extract HTTP status code from headers file - local me_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - - if [[ "$me_status" =~ ^[0-9]+$ ]] && [ "$me_status" -eq 200 ]; then - ((PASS_COUNT++)) - write_test_log "SUCCESS" "✓ Get profile $fullname berhasil" - - local user_email=$(echo "$me_body" | jq -r '.data.email // empty') - local user_name=$(echo "$me_body" | jq -r '.data.fullname // empty') - - if [ "$user_email" = "$email" ]; then - write_test_log "SUCCESS" "✓ User data verified: $user_name ($user_email)" - else - write_test_log "WARN" "⚠ User data mismatch: expected $email, got $user_email" - fi - else - ((FAIL_COUNT++)) - write_test_log "ERROR" "✗ Get profile $fullname gagal - HTTP $me_status" - FAILED_TESTS_SUMMARY+=("✗ Get profile $fullname - HTTP $me_status") - fi - - else - ((FAIL_COUNT++)) - write_test_log "ERROR" "✗ Login $fullname - No token (${duration}ms)" - FAILED_TESTS_SUMMARY+=("✗ Login $fullname - No token in response") - fi - else - write_test_log "ERROR" "✗ Login $fullname gagal - HTTP $http_status (${duration}ms)" - FAILED_TESTS_SUMMARY+=("✗ Login $fullname - HTTP $http_status") - fi -} - -test_all_users_individually() { - printf "\n${CYAN}=== Menguji Semua User Secara Individual ===${NC}\n" - - for email in "${!ALL_USERS[@]}"; do - local fullname="${ALL_USERS[$email]}" - test_with_user "$email" "$fullname" "Individual User Test" - echo "" - done -} - -test_comprehensive_with_user() { - printf "\n${CYAN}=== Comprehensive Test untuk $fullname ($email) ===${NC}\n" - - local login_data - login_data=$(jq -n --arg email "$email" --arg pass "$TEST_PASSWORD" '{email: $email, password: $pass}') - - local start_time=$(date +%s%3N) - - # Use a more compatible approach for Windows/Git Bash - local temp_file=$(mktemp) - local status_file=$(mktemp) - - # Make single request and capture both body and status using response headers - curl -s -X "POST" -H "Content-Type: application/json" -d "$login_data" "$BASE_URL/v1/auth/login" \ - -D "$status_file" -o "$temp_file" - - local response_body=$(cat "$temp_file") - - # Extract HTTP status code from headers file - local http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - local end_time=$(date +%s%3N) - local duration=$((end_time - start_time)) - - if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq 200 ]; then - if echo "$response_body" | jq -e '.data.token.access_token' > /dev/null 2>&1; then - user_token=$(echo "$response_body" | jq -r '.data.token.access_token') - write_test_log "SUCCESS" "✓ Login $fullname berhasil - ${duration}ms" - - local original_auth_token="$AUTH_TOKEN" - - AUTH_TOKEN="$user_token" - # Get user ID and add credits for gacha testing - local temp_file=$(mktemp) - local status_file=$(mktemp) - - # Get user profile to extract user_id - curl -s -X "GET" -H "Content-Type: application/json" -H "Authorization: Bearer $user_token" "$BASE_URL/v1/users/me" \ - -D "$status_file" -o "$temp_file" - - local user_profile_body=$(cat "$temp_file") - local user_profile_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - - if [[ "$user_profile_status" =~ ^[0-9]+$ ]] && [ "$user_profile_status" -eq 200 ]; then - local user_id=$(echo "$user_profile_body" | jq -r '.data.id // empty') - if [ -n "$user_id" ]; then - # Add credits for gacha testing - local add_credits_data=$(jq -n --arg user_id "$user_id" '{user_id: $user_id, amount: 10}') - local temp_file=$(mktemp) - local status_file=$(mktemp) - - curl -s -X "POST" -H "Content-Type: application/json" -H "Authorization: Bearer $user_token" -d "$add_credits_data" "$BASE_URL/v1/gacha/credits/add" \ - -D "$status_file" -o "$temp_file" - - local add_credits_body=$(cat "$temp_file") - local add_credits_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - - if [[ "$add_credits_status" =~ ^[0-9]+$ ]] && [ "$add_credits_status" -eq 200 ]; then - write_test_log "SUCCESS" "✓ Credits added for $fullname (user_id: $user_id)" - - # Verify credits were added correctly - local get_credits_response=$(curl -s -w "\nHTTP_STATUS:%{http_code}" -X GET "$BASE_URL/v1/gacha/credits" \ - -H "Authorization: Bearer $user_token") - local get_credits_body=$(echo "$get_credits_response" | head -n -1) - local get_credits_status=$(echo "$get_credits_response" | tail -n 1 | sed 's/HTTP_STATUS://') - - if [[ "$get_credits_status" =~ ^[0-9]+$ ]] && [ "$get_credits_status" -eq 200 ]; then - local available_rolls=$(echo "$get_credits_body" | jq -r '.data.available_rolls // 0') - if [ "$available_rolls" -ge 10 ]; then - write_test_log "SUCCESS" "✓ Credits verified for $fullname: $available_rolls rolls available" - else - write_test_log "ERROR" "✗ Credits not added correctly for $fullname: expected >=10, got $available_rolls" - return 1 - fi - else - write_test_log "ERROR" "✗ Failed to get credits for $fullname - HTTP $get_credits_status: $get_credits_body" - return 1 - fi - else - write_test_log "ERROR" "✗ Failed to add credits for $fullname - HTTP $add_credits_status: $add_credits_body" - return 1 - fi - else - write_test_log "ERROR" "✗ Failed to get user_id for $fullname from profile response" - fi - else - write_test_log "ERROR" "✗ Failed to get user profile for $fullname - HTTP $user_profile_status" - fi - - printf "\n${BLUE}--- Testing dengan $fullname (Expected results berdasarkan role) ---${NC}\n" - - test_api_endpoint "Get Current User Profile - $fullname" "GET" "/v1/users/me" 200 "" true - - case "$email" in - "admin@example.com") - test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 200 "" true - test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 200 "" true - test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 200 "" true - test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true - test_api_endpoint "Get Mentor Me - $fullname" "GET" "/v1/mentors/me" 403 "" true # Admin is not a mentor - test_api_endpoint "Get Mentor Status - $fullname" "GET" "/v1/mentors/status" 403 "" true # Admin is not a mentor - test_api_endpoint "Get Gacha Items - $fullname" "GET" "/v1/gacha/items" 200 "" true - test_api_endpoint "Execute Gacha Roll - $fullname" "POST" "/v1/gacha/rolls/execute" 200 "" true - - # Team endpoints for admin - # Admin teams endpoint should only be accessible to admins - if [ "$email" = "admin@example.com" ]; then - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 200 "" true - else - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 403 "" true - fi - test_api_endpoint "Get Public Teams List - $fullname" "GET" "/v1/teams" 200 "" true - test_api_endpoint "Search Teams - $fullname" "GET" "/v1/teams/search?query=Development" 200 "" true - - local testimonial_data - testimonial_data=$(jq -n --arg content "Test testimonial by $fullname $(date +%s)" '{role: "Student", content: $content}') - test_api_endpoint "Create Testimonial - $fullname" "POST" "/v1/cms/landing/testimonials/create" 201 "$testimonial_data" true - ;; - - "staff@example.com") - test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 200 "" true - test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 200 "" true - test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 200 "" true - test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true - test_api_endpoint "Get Gacha Items - $fullname" "GET" "/v1/gacha/items" 200 "" true - test_api_endpoint "Execute Gacha Roll - $fullname" "POST" "/v1/gacha/rolls/execute" 200 "" true - - # Team endpoints for admin - # Admin teams endpoint should only be accessible to admins - if [ "$email" = "admin@example.com" ]; then - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 200 "" true - else - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 403 "" true - fi - test_api_endpoint "Get Public Teams List - $fullname" "GET" "/v1/teams" 200 "" true - test_api_endpoint "Search Teams - $fullname" "GET" "/v1/teams/search?query=Development" 200 "" true - - local testimonial_data - testimonial_data=$(jq -n --arg content "Test testimonial by $fullname $(date +%s)" '{role: "Student", content: $content}') - test_api_endpoint "Create Testimonial - $fullname" "POST" "/v1/cms/landing/testimonials/create" 201 "$testimonial_data" true - ;; - - "mentor@example.com") - test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 200 "" true - test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 403 "" true - test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 403 "" true - test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true - test_api_endpoint "Get Mentor Me - $fullname" "GET" "/v1/mentors/me" 200 "" true - test_api_endpoint "Get Mentor Status - $fullname" "GET" "/v1/mentors/status" 200 "" true - test_api_endpoint "Get Gacha Items - $fullname" "GET" "/v1/gacha/items" 200 "" true - test_api_endpoint "Execute Gacha Roll - $fullname" "POST" "/v1/gacha/rolls/execute" 200 "" true - - # Team endpoints for admin - # Admin teams endpoint should only be accessible to admins - if [ "$email" = "admin@example.com" ]; then - # Admin teams endpoint should only be accessible to admins - if [ "$email" = "admin@example.com" ]; then - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 200 "" true - else - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 403 "" true - fi - else - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 403 "" true - fi - test_api_endpoint "Get Public Teams List - $fullname" "GET" "/v1/teams" 200 "" true - test_api_endpoint "Search Teams - $fullname" "GET" "/v1/teams/search?query=Development" 200 "" true - - local testimonial_data - testimonial_data=$(jq -n --arg content "Test testimonial by $fullname $(date +%s)" '{role: "Student", content: $content}') - test_api_endpoint "Create Testimonial - $fullname" "POST" "/v1/cms/landing/testimonials/create" 201 "$testimonial_data" true - ;; - - "user@example.com") - test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 200 "" true - test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 403 "" true - test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 403 "" true - test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true - test_api_endpoint "Get Mentor Me - $fullname" "GET" "/v1/mentors/me" 403 "" true # User is not a mentor - test_api_endpoint "Get Mentor Status - $fullname" "GET" "/v1/mentors/status" 403 "" true # User is not a mentor - test_api_endpoint "Get Gacha Items - $fullname" "GET" "/v1/gacha/items" 200 "" true - test_api_endpoint "Execute Gacha Roll - $fullname" "POST" "/v1/gacha/rolls/execute" 200 "" true - - # Team endpoints for admin - test_api_endpoint "Get Admin Teams List - $fullname" "GET" "/v1/teams/admin" 403 "" true - test_api_endpoint "Get Public Teams List - $fullname" "GET" "/v1/teams" 200 "" true - test_api_endpoint "Search Teams - $fullname" "GET" "/v1/teams/search?query=Development" 200 "" true - - local testimonial_data - testimonial_data=$(jq -n --arg content "Test testimonial by $fullname $(date +%s)" '{role: "Student", content: $content}') - test_api_endpoint "Create Testimonial - $fullname" "POST" "/v1/cms/landing/testimonials/create" 201 "$testimonial_data" true - ;; - esac - - test_api_endpoint "Events with Advanced Filter - $fullname" "GET" "/v1/cms/landing/events?filter=online&filter_by=is_online" 200 "" false - test_api_endpoint "Testimonials with Search - $fullname" "GET" "/v1/cms/landing/testimonials?search=test" 200 "" false - - case "$email" in - "admin@example.com"|"staff@example.com") - test_api_endpoint "Users with Sort - $fullname" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true - ;; - *) - test_api_endpoint "Users with Sort - $fullname" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true - ;; - esac - - AUTH_TOKEN="$original_auth_token" - - write_test_log "SUCCESS" "✓ Comprehensive test untuk $fullname selesai" - - else - write_test_log "ERROR" "✗ Login $fullname gagal - No token (${duration}ms)" - fi - else - write_test_log "ERROR" "✗ Login $fullname gagal - HTTP $http_status (${duration}ms)" - fi -} - -test_all_endpoints_with_all_users() { - printf "\n${CYAN}=== Menjalankan Semua Test dengan Semua User ===${NC}\n" - - for email in "${!ALL_USERS[@]}"; do - local fullname="${ALL_USERS[$email]}" - test_comprehensive_with_user "$email" "$fullname" - printf "\n${BLUE}--- Selesai testing dengan $fullname ---${NC}\n\n" - done -} - -test_public_endpoints() { - printf "\n${CYAN}=== Menguji Public Endpoints ===${NC}\n" - test_api_endpoint "Get Events List" "GET" "/v1/cms/landing/events" 200 - test_api_endpoint "Get Testimonials List" "GET" "/v1/cms/landing/testimonials" 200 -} - -test_authentication_endpoints() { - printf "\n${CYAN}=== Menguji Authentication Endpoints ===${NC}\n" - get_auth_token - - local invalid_login - invalid_login=$(jq -n '{email: "invalid@example.com", password: "wrongpassword"}') - test_api_endpoint "Invalid Login Test" "POST" "/v1/auth/login" 401 "$invalid_login" - - # User registration and verification tests currently rely on external email service or OTP logic - # that is not easily testable in a simple curl script without actual email sending/receiving. - # Skipping these tests for now. - # local register_email="test_user_$(date +%s%N)@example.com" - # local register_data=$(jq -n --arg email "$register_email" --arg pass "$TEST_PASSWORD" --arg fullname "Test Register" --arg phone "081234567899" '{email: $email, password: $pass, fullname: $fullname, phone_number: $phone}') - # test_api_endpoint "User Registration Test" "POST" "/v1/auth/register" 200 "$register_data" - # local verify_otp_data=$(jq -n --arg email "$register_email" --arg otp "123456" '{email: $email, otp: ($otp | tonumber)}') - # test_api_endpoint "Verify Email Test (Invalid OTP)" "POST" "/v1/auth/verify-email" 400 "$verify_otp_data" - - local forgot_password_data - forgot_password_data=$(jq -n --arg email "$TEST_EMAIL" '{email: $email}') - test_api_endpoint "Forgot Password Test" "POST" "/v1/auth/forgot" 200 "$forgot_password_data" - - local new_password_data - new_password_data=$(jq -n --arg token "some_reset_token" --arg pass "newpassword123!A" '{token: $token, password: $pass}') - test_api_endpoint "New Password Test (Invalid Token)" "POST" "/v1/auth/new-password" 400 "$new_password_data" - - local refresh_token=$(curl -s -X POST -H "Content-Type: application/json" -d "$(jq -n --arg email "$TEST_EMAIL" --arg pass "$TEST_PASSWORD" '{email: $email, password: $pass}')" "$BASE_URL/v1/auth/login" | jq -r '.data.token.refresh_token // empty') - if [ -n "$refresh_token" ]; then - local refresh_data - refresh_data=$(jq -n --arg token "$refresh_token" '{refresh_token: $token}') - test_api_endpoint "Refresh Token Test" "POST" "/v1/auth/refresh" 200 "$refresh_data" - else - write_test_log "WARN" "✗ Refresh Token Test - Dilewati: Refresh token tidak tersedia dari login" - fi -} - -test_error_handling() { - printf "\n${CYAN}=== Menguji Error Handling ===${NC}\n" - test_api_endpoint "Non-existent Endpoint" "GET" "/v1/nonexistent" 404 - test_api_endpoint "Unauthorized Access" "GET" "/v1/users" 401 "" false -} - -test_user_management_endpoints() { - printf "\n${CYAN}=== Menguji User Management Endpoints ===${NC}\n" - test_api_endpoint "Get Users List" "GET" "/v1/users" 200 "" true - - local test_user_id="c3b1d6a8-8d4f-4b36-b789-2e532ec7a7b2" - test_api_endpoint "Get User By ID" "GET" "/v1/users/detail/$test_user_id" 200 "" true - - local new_user_email="new_test_user_$(date +%s%N)@example.com" - local new_user_fullname="New Test User $(date +%s%N)" - local new_user_phone="089876543211" - local new_user_password="NewPassword123!" - local new_user_role_id="5713cb37-dc02-4e87-8048-d7a41d352059" # User role ID from seed_users.rs - - local create_user_data=$(jq -n \ - --arg email "$new_user_email" \ - --arg pass "$new_user_password" \ - --arg fullname "$new_user_fullname" \ - --arg phone "$new_user_phone" \ - --arg is_active true \ - --arg role_id "$new_user_role_id" \ - '{email: $email, password: $pass, fullname: $fullname, phone_number: $phone, is_active: $is_active | fromjson, role_id: $role_id}') - - # Create user and capture response directly - local temp_file=$(mktemp) - local status_file=$(mktemp) - - curl -s -X "POST" -H "Content-Type: application/json" -H "Authorization: Bearer $AUTH_TOKEN" -d "$create_user_data" "$BASE_URL/v1/users/create" \ - -D "$status_file" -o "$temp_file" - - local create_response_body=$(cat "$temp_file") - local create_status=$(head -n 1 "$status_file" | cut -d' ' -f2) - - rm -f "$temp_file" "$status_file" - - if [[ "$create_status" =~ ^[0-9]+$ ]] && [ "$create_status" -eq 201 ]; then - ((PASS_COUNT++)) - write_test_log "SUCCESS" "✓ Create New User - Sukses (Status: $create_status, Waktu: ${duration}ms)" - - # Extract user ID directly from create response - local created_user_id=$(echo "$create_response_body" | jq -r '.data.id // empty') - else - ((FAIL_COUNT++)) - write_test_log "ERROR" "✗ Create New User - Gagal (Status: $create_status)" - write_test_log "ERROR" " Response Body: $create_response_body" - FAILED_TESTS_SUMMARY+=("✗ Create New User - HTTP $create_status") - return - fi - - if [ -n "$created_user_id" ]; then - local updated_user_fullname="Updated Test User $(date +%s%N)" - local updated_user_data=$(jq -n \ - --arg email "$new_user_email" \ - --arg pass "$new_user_password" \ - --arg fullname "$updated_user_fullname" \ - --arg phone "$new_user_phone" \ - --arg is_active true \ - --arg gender "Male" \ - --arg birthdate "1990-01-01" \ - --arg avatar "https://example.com/avatar.jpg" \ - --arg role_id "$new_user_role_id" \ - '{email: $email, password: $pass, fullname: $fullname, phone_number: $phone, is_active: $is_active | fromjson, gender: $gender, birthdate: $birthdate, avatar: $avatar, role_id: $role_id}') - test_api_endpoint "Update User" "PUT" "/v1/users/update/$created_user_id" 200 "$updated_user_data" true - - local set_active_data=$(jq -n --arg is_active false '{is_active: $is_active | fromjson}') - test_api_endpoint "Deactivate User" "PUT" "/v1/users/activate/$created_user_id" 200 "$set_active_data" true - - local set_active_data=$(jq -n --arg is_active true '{is_active: $is_active | fromjson}') - test_api_endpoint "Reactivate User" "PUT" "/v1/users/activate/$created_user_id" 200 "$set_active_data" true - - test_api_endpoint "Delete User" "DELETE" "/v1/users/delete/$created_user_id" 200 "" true - else - write_test_log "WARN" "✗ Skipping User Update/Delete tests: Failed to retrieve ID of newly created user." - fi -} - -test_crud_operations() { - printf "\n${CYAN}=== Menguji CRUD Operations ===${NC}\n" - - local testimonial_data - testimonial_data=$(jq -n --arg content "Test testimonial via Bash $(date +%s)" '{role: "Student", content: $content}') - local testimonial_response - testimonial_response=$(test_api_endpoint "Create Testimonial" "POST" "/v1/cms/landing/testimonials/create" 201 "$testimonial_data" true) - TEST_TESTIMONIAL_ID=$(echo "$testimonial_response" | jq -r '.data.id // empty') - write_test_log "INFO" "Captured Testimonial ID: $TEST_TESTIMONIAL_ID" - sleep 0.2 - - local permission_data - permission_data=$(jq -n --arg name "Test Permission $(date +%s)" '{name: $name}') - test_api_endpoint "Create Permission" "POST" "/v1/permissions/create" 201 "$permission_data" true - - local gacha_item_data - gacha_item_data=$(jq -n --arg name "Test Item $(date +%s)" '{name: $name, image_url: "https://example.com/id.jpg"}') - test_api_endpoint "Create Gacha Item" "POST" "/v1/gacha/items/create" 201 "$gacha_item_data" true - - local event_data - event_data=$(jq -n --arg name "Test Event $(date +%s)" '{ - name: $name, - description: "Test event description", - detail_link: "https://example.com/event", - price: 50.0, - is_online: true, - start_date: "2025-12-01T10:00:00Z", - end_date: "2025-12-01T16:00:00Z", - location: null - }') - local event_response - event_response=$(test_api_endpoint "Create Event" "POST" "/v1/cms/landing/events/create" 201 "$event_data" true) - TEST_EVENT_ID=$(echo "$event_response" | jq -r '.data.id // empty') - write_test_log "INFO" "Captured Event ID: $TEST_EVENT_ID" -} - -test_roles_and_permissions() { - printf "\n${CYAN}=== Menguji Roles & Permissions Endpoints ===${NC}\n" - test_api_endpoint "Get Roles List" "GET" "/v1/roles" 200 "" true - test_api_endpoint "Get Permissions List" "GET" "/v1/permissions" 200 "" true - - local test_role_id="3b9f8c4e-6a2d-4f8a-9a12-2d6f8b3c4e5a" - test_api_endpoint "Get Role By ID" "GET" "/v1/roles/detail/$test_role_id" 200 "" true -} - -test_mentor_endpoints() { - printf "\n${CYAN}=== Menguji Mentor Endpoints ===${NC}\n" - test_api_endpoint "Get Mentors List" "GET" "/v1/mentors" 200 "" true - # These tests are run with AUTH_TOKEN set to admin. Since admin is not a mentor, these should be 403. - test_api_endpoint "Get Mentor Me" "GET" "/v1/mentors/me" 403 "" true - test_api_endpoint "Get Mentor Status" "GET" "/v1/mentors/status" 403 "" true - - local test_mentor_id="e6f78d23-83bf-5c2b-bcd4-001345678901" - test_api_endpoint "Get Mentor By ID" "GET" "/v1/mentors/detail/$test_mentor_id" 200 "" true - - local mentor_register_data - mentor_register_data=$(jq -n --arg email "test.mentor.$(date +%s%N)@example.com" '{ - identity_and_verification: { - legal_name: "Test Mentor Legal Name", - identity_document_url: "https://example.com/id.jpg", - phone_for_verification: "+1234567890" - }, - professional_profile: { - bio: "Test mentor bio", - linkedin_url: "https://linkedin.com/in/testmentor", - industries: ["Technology", "Software"], - expertise: ["JavaScript", "Python"], - languages: ["English", "Indonesian"], - current_company: "Test Company", - current_role: "Senior Developer", - years_of_experience: 5 - }, - mentoring_logistics: { - topics_of_interest: ["Career Development", "Technical Skills"], - preferred_mentee_level: ["Junior", "Mid-level"], - preferred_mentoring_formats: ["1-on-1", "Group"], - availability_commitment: "2-3 hours per week", - mentoring_rate: { - amount: 100000, - currency: "IDR", - per_duration: "hour" - } - }, - email: $email - }') - test_api_endpoint "Register as Mentor" "POST" "/v1/mentors/register" 422 "$mentor_register_data" true -} - -test_events_endpoints() { - printf "\n${CYAN}=== Menguji Events Endpoints ===${NC}\n" - test_api_endpoint "Get Events with Pagination" "GET" "/v1/cms/landing/events?page=1&per_page=5" 200 - test_api_endpoint "Get Events with Search" "GET" "/v1/cms/landing/events?search=tech" 200 - - # Ensure TEST_EVENT_ID is not empty before testing - if [ -n "$TEST_EVENT_ID" ]; then - test_api_endpoint "Get Event By ID" "GET" "/v1/cms/landing/events/detail/$TEST_EVENT_ID" 200 - else - write_test_log "WARN" "✗ Get Event By ID - Dilewati: TEST_EVENT_ID tidak tersedia" - fi -} - -test_testimonials_endpoints() { - printf "\n${CYAN}=== Menguji Testimonials Endpoints ===${NC}\n" - test_api_endpoint "Get Testimonials with Pagination" "GET" "/v1/cms/landing/testimonials?page=1&per_page=5" 200 - - # Ensure TEST_TESTIMONIAL_ID is not empty before testing - if [ -n "$TEST_TESTIMONIAL_ID" ]; then - test_api_endpoint "Get Testimonial By ID" "GET" "/v1/cms/landing/testimonials/detail/$TEST_TESTIMONIAL_ID" 200 - else - write_test_log "WARN" "✗ Get Testimonial By ID - Dilewati: TEST_TESTIMONIAL_ID tidak tersedia" - fi -} - -test_gacha_endpoints() { - printf "\n${CYAN}=== Menguji Gacha Endpoints ===${NC}\n" - test_api_endpoint "Get Gacha Items" "GET" "/v1/gacha/items" 200 "" true - test_api_endpoint "Execute Gacha Roll" "POST" "/v1/gacha/rolls/execute" 200 "" true -} - -test_team_endpoints() { - printf "\n${CYAN}=== Menguji Team Endpoints ===${NC}\n" - test_api_endpoint "Get Public Teams List" "GET" "/v1/teams" 200 "" true - test_api_endpoint "Search Teams" "GET" "/v1/teams/search?query=Development" 200 "" true - - # Test team creation (admin only) - if [ "$email" = "admin@example.com" ]; then - local team_data - team_data=$(jq -n --arg name "Test Team $(date +%s)" '{ - name: $name, - description: "Test team description", - is_open: true, - max_members: 10, - skills_required: ["Rust", "Backend Development"], - location: "Remote", - website_url: "https://example.com/team", - github_url: "https://github.com/example/team" - }') - test_api_endpoint "Create Team (Admin)" "POST" "/v1/teams/create" 201 "$team_data" true - - # Test team update (admin only) - local test_team_id="test-team-001" - local update_team_data - update_team_data=$(jq -n --arg name "Updated Test Team" '{ - name: $name, - description: "Updated test team description", - is_open: false, - max_members: 15, - skills_required: ["Rust", "Backend Development", "DevOps"], - location: "Hybrid" - }') - test_api_endpoint "Update Team (Admin)" "PUT" "/v1/teams/update/$test_team_id" 200 "$update_team_data" true - - # Test team member management - local member_data - member_data=$(jq -n --arg user_id "user-123" '{user_id: $user_id, role: "MEMBER"}') - test_api_endpoint "Add Team Member" "POST" "/v1/teams/$test_team_id/members" 200 "$member_data" true - - test_api_endpoint "Get Team Members" "GET" "/v1/teams/$test_team_id/members" 200 "" true - test_api_endpoint "Remove Team Member" "DELETE" "/v1/teams/$test_team_id/members/user-123" 200 "" true - else - # Regular users should get 403 for admin endpoints - test_api_endpoint "Get Admin Teams List" "GET" "/v1/teams/admin" 403 "" true - - # Regular users can still access public team operations - local team_data - team_data=$(jq -n --arg name "Public Test Team" '{ - name: $name, - description: "Public test team description" - }') - test_api_endpoint "Get Team Details" "GET" "/v1/teams/detail/test-team-001" 200 "" true - fi -} - -test_hackathon_endpoints() { - printf "\n${CYAN}=== Menguji Hackathon Endpoints ===${NC}\n" - test_api_endpoint "Get Hackathons List" "GET" "/v1/hackathons" 200 "" true - test_api_endpoint "Get Hackathons with Pagination" "GET" "/v1/hackathons?page=1&per_page=5" 200 "" true - test_api_endpoint "Search Hackathons" "GET" "/v1/hackathons?search=test" 200 "" true - - # Test specific hackathon by ID (assuming test hackathon exists from seeder) - local test_hackathon_id="test-hackathon-001" - test_api_endpoint "Get Hackathon By ID" "GET" "/v1/hackathons/$test_hackathon_id" 200 "" true - - # Test participant management - local participant_data=$(jq -n --arg user_id "test-participant@example.com" '{user_id: $user_id}') - test_api_endpoint "Register Participant" "POST" "/v1/hackathons/$test_hackathon_id/participants" 200 "$participant_data" true - test_api_endpoint "Get Participants List" "GET" "/v1/hackathons/$test_hackathon_id/participants" 200 "" true - - # Test submission endpoints - test_api_endpoint "Get Submissions List" "GET" "/v1/hackathons/$test_hackathon_id/submissions" 200 "" true - test_api_endpoint "Get Submissions with Pagination" "GET" "/v1/hackathons/$test_hackathon_id/submissions?page=1&per_page=5" 200 "" true - - # Test creating a submission (assuming test user is logged in) - local submission_data - submission_data=$(jq -n --arg hackathon_id "$test_hackathon_id" --arg team_id "test-team-001" '{ - hackathon_id: $hackathon_id, - team_id: $team_id, - project_name: "Test Project Submission", - description: "This is a test project submission for hackathon testing", - technologies: ["Rust", "React", "PostgreSQL"], - repository_url: "https://github.com/test/test-project", - demo_url: "https://demo.test.com", - presentation_url: "https://slides.test.com" - }') - local create_response - create_response=$(test_api_endpoint "Create Hackathon Submission" "POST" "/v1/hackathons/$test_hackathon_id/teams/test-team-001/submissions" 201 "$submission_data" true) - local test_submission_id=$(echo "$create_response" | jq -r '.data.id // empty') - - # Test getting submission by ID - if [ -n "$test_submission_id" ]; then - test_api_endpoint "Get Submission By ID" "GET" "/v1/hackathons/submissions/$test_submission_id" 200 "" true - - # Test submitting project (finalization) - test_api_endpoint "Submit Project" "POST" "/v1/hackathons/submissions/$test_submission_id/submit" 200 "" true - - # Test updating submission - local update_submission_data - update_submission_data=$(jq -n --arg hackathon_id "$test_hackathon_id" --arg team_id "test-team-001" '{ - hackathon_id: $hackathon_id, - team_id: $team_id, - project_name: "Updated Test Project Submission", - description: "This is an updated test project submission for hackathon testing", - technologies: ["Rust", "React", "PostgreSQL", "Docker"], - repository_url: "https://github.com/test/updated-test-project", - demo_url: "https://updated-demo.test.com", - presentation_url: "https://updated-slides.test.com" - }') - test_api_endpoint "Update Hackathon Submission" "PUT" "/v1/hackathons/submissions/$test_submission_id" 200 "$update_submission_data" true - - # Test deleting submission - test_api_endpoint "Delete Hackathon Submission" "DELETE" "/v1/hackathons/submissions/$test_submission_id" 200 "" true - else - write_test_log "WARN" "✗ Submission tests - Dilewati: Failed to capture submission ID from creation response" - fi -} - -test_end_to_end_team_workflow() { - printf "\n${CYAN}=== End-to-End Team Management Workflow ===${NC}\n" - - if [ "$email" != "admin@example.com" ]; then - write_test_log "WARN" "✗ Workflow hanya dijalankan untuk admin" - return - fi - - local workflow_start=$(date +%s) - local team_id="" - local member_ids=() - - printf "\n${BLUE}1. Membuat Tim Baru${NC}\n" - local team_name="Test Team Workflow $(date +%s)" - local create_team_data=$(jq -n --arg name "$team_name" '{ - name: $name, - description: "Team untuk testing end-to-end workflow", - is_open: true, - max_members: 5, - skills_required: ["Rust", "Backend", "Testing"], - location: "Remote" - }') - - local create_response=$(test_api_endpoint "Create Team" "POST" "/v1/teams/create" 201 "$create_team_data" true) - team_id=$(echo "$create_response" | jq -r '.data.id // empty') - - if [ -z "$team_id" ]; then - write_test_log "ERROR" "✗ Gagal mendapatkan ID tim dari respons" - return - fi - - write_test_log "SUCCESS" "Tim berhasil dibuat dengan ID: $team_id" - - printf "\n${BLUE}2. Menambahkan Anggota Tim${NC}\n" - local member_count=3 - for i in $(seq 1 $member_count); do - local member_email="team_member_$i@example.com" - local member_data=$(jq -n --arg user_id "$member_email" '{user_id: $user_id, role: "MEMBER"}') - - test_api_endpoint "Add Member $i" "POST" "/v1/teams/$team_id/members" 200 "$member_data" true - member_ids+=("$member_email") - done - - printf "\n${BLUE}3. Memverifikasi Anggota Tim${NC}\n" - local members_response=$(test_api_endpoint "Get Team Members" "GET" "/v1/teams/$team_id/members" 200 "" true) - local actual_member_count=$(echo "$members_response" | jq '.data | length') - - if [ "$actual_member_count" -eq "$member_count" ]; then - write_test_log "SUCCESS" "✓ Jumlah anggota sesuai: $actual_member_count/$member_count" - else - write_test_log "ERROR" "✗ Jumlah anggota tidak sesuai: $actual_member_count/$member_count" - fi - - printf "\n${BLUE}4. Memperbarui Tim${NC}\n" - local update_team_data=$(jq -n --arg name "Updated: $team_name" '{ - name: $name, - description: "Deskripsi tim yang telah diperbarui", - is_open: false, - max_members: 10, - skills_required: ["Rust", "Backend", "Testing", "DevOps"] - }') - - test_api_endpoint "Update Team" "PUT" "/v1/teams/update/$team_id" 200 "$update_team_data" true - - printf "\n${BLUE}5. Menghapus Anggota Tim${NC}\n" - local member_to_remove="${member_ids[0]}" - test_api_endpoint "Remove Member" "DELETE" "/v1/teams/$team_id/members/$member_to_remove" 200 "" true - - printf "\n${BLUE}6. Menghapus Tim${NC}\n" - test_api_endpoint "Delete Team" "DELETE" "/v1/teams/delete/$team_id" 200 "" true - - local workflow_end=$(date +%s) - local workflow_duration=$((workflow_end - workflow_start)) - - printf "\n${GREEN}=== Workflow Selesai ===${NC}\n" - printf "Durasi: %d detik\n" "$workflow_duration" - printf "Tim: %s\n" "$team_name" - printf "Anggota awal: %d\n" "$member_count" - printf "Status: ✅ Selesai\n" -} - -test_end_to_end_hackathon_workflow() { - printf "\n${CYAN}=== End-to-End Hackathon Management Workflow ===${NC}\n" - - local workflow_start=$(date +%s) - local hackathon_id="" - local submission_id="" - - printf "\n${BLUE}1. Membuat Hackathon Baru${NC}\n" - local hackathon_name="Hackathon Test $(date +%s)" - local create_hackathon_data=$(jq -n --arg name "$hackathon_name" '{ - name: $name, - description: "Hackathon untuk testing end-to-end workflow", - start_date: "'$(date -d "+2 days" +%Y-%m-%dT%H:%M:%SZ)'", - end_date: "'$(date -d "+3 days" +%Y-%m-%dT%H:%M:%SZ)'", - registration_deadline: "'$(date -d "+1 day" +%Y-%m-%dT%H:%M:%SZ)'", - max_participants: 20, - theme: "Backend Development", - rules: "Buat sesuatu yang berfaedah!", - prizes: [{"name": "Juara 1", "description": "Hadiah utama"}], - organizers: ["admin@example.com"] - }') - - local create_response=$(test_api_endpoint "Create Hackathon" "POST" "/v1/hackathons" 201 "$create_hackathon_data" true) - hackathon_id=$(echo "$create_response" | jq -r '.data.id // empty') - - if [ -z "$hackathon_id" ]; then - write_test_log "ERROR" "✗ Gagal mendapatkan ID hackathon dari respons" - return - fi - - write_test_log "SUCCESS" "Hackathon berhasil dibuat dengan ID: $hackathon_id" - - printf "\n${BLUE}2. Mendaftarkan Peserta${NC}\n" - local participant_data=$(jq -n --arg user_id "participant_1@example.com" '{user_id: $user_id}') - test_api_endpoint "Register Participant" "POST" "/v1/hackathons/$hackathon_id/participants" 200 "$participant_data" true - - printf "\n${BLUE}3. Membuat Submission Proyek${NC}\n" - local submission_data=$(jq -n --arg hackathon_id "$hackathon_id" --arg team_id "test-team-001" '{ - hackathon_id: $hackathon_id, - team_id: $team_id, - project_name: "Proyek Test Workflow", - description: "Proyek contoh untuk testing submission", - technologies: ["Rust", "PostgreSQL", "Docker"], - repository_url: "https://github.com/test/proyek-workflow", - demo_url: "https://demo.test.com", - presentation_url: "https://slides.test.com" - }') - - local submission_response=$(test_api_endpoint "Create Submission" "POST" "/v1/hackathons/$hackathon_id/teams/test-team-001/submissions" 201 "$submission_data" true) - submission_id=$(echo "$submission_response" | jq -r '.data.id // empty') - - if [ -n "$submission_id" ]; then - write_test_log "SUCCESS" "Submission berhasil dibuat dengan ID: $submission_id" - - printf "\n${BLUE}4. Memperbarui Submission${NC}\n" - local update_submission_data=$(jq -n --arg hackathon_id "$hackathon_id" --arg team_id "test-team-001" '{ - hackathon_id: $hackathon_id, - team_id: $team_id, - project_name: "Proyek Test Workflow (Diperbarui)", - description: "Proyek contoh untuk testing submission yang telah diperbarui", - technologies: ["Rust", "PostgreSQL", "Docker", "Kubernetes"] - }') - - test_api_endpoint "Update Submission" "PUT" "/v1/hackathons/submissions/$submission_id" 200 "$update_submission_data" true - - printf "\n${BLUE}5. Mengirim Submission (Finalisasi)${NC}\n" - test_api_endpoint "Submit Project" "POST" "/v1/hackathons/submissions/$submission_id/submit" 200 "" true - fi - - printf "\n${BLUE}6. Memverifikasi Semua Data${NC}\n" - test_api_endpoint "Get Hackathon Details" "GET" "/v1/hackathons/$hackathon_id" 200 "" true - test_api_endpoint "Get Participants List" "GET" "/v1/hackathons/$hackathon_id/participants" 200 "" true - - if [ -n "$submission_id" ]; then - test_api_endpoint "Get Submission Details" "GET" "/v1/hackathons/submissions/$submission_id" 200 "" true - fi - - local workflow_end=$(date +%s) - local workflow_duration=$((workflow_end - workflow_start)) - - printf "\n${GREEN}=== Workflow Selesai ===${NC}\n" - printf "Durasi: %d detik\n" "$workflow_duration" - printf "Hackathon: %s\n" "$hackathon_name" - printf "Status: ✅ Selesai\n" -} - -test_timeline_enforcement() { - printf "\n${CYAN}=== Menguji Timeline Enforcement Middleware ===${NC}\n" - - # Test timeline enforcement for hackathon submissions (should be 403 outside submission phase) - test_api_endpoint "Hackathon Submission Outside Timeline" "POST" "/v1/hackathons/test-hackathon-001/teams/test-team-001/submissions" 403 "" true - - # Test timeline enforcement for hackathon registrations (should be 403 outside registration phase) - test_api_endpoint "Hackathon Registration Outside Timeline" "POST" "/v1/hackathons/test-hackathon-001/participants" 403 "" true - - # Test that timeline endpoints return proper error messages - test_api_endpoint "Timeline Error Message Format" "GET" "/v1/hackathons/test-hackathon-001/timeline" 200 "" true - - # Test timeline phase creation (admin only) - local timeline_data=$(jq -n --arg name "Submission Phase" --arg phase "submission" '{ - name: $name, - phase: $phase, - start_date: "'$(date -d "-10 day" +%Y-%m-%dT%H:%M:%SZ)'", - end_date: "'$(date -d "+10 day" +%Y-%m-%dT%H:%M:%SZ)'" - }') - test_api_endpoint "Create Timeline Phase (Admin)" "POST" "/v1/hackathons/test-hackathon-001/timeline" 201 "$timeline_data" true - - # Test timeline phase listing - test_api_endpoint "List Timeline Phases" "GET" "/v1/hackathons/test-hackathon-001/timeline" 200 "" true -} - -test_admin_endpoints_permissions() { - printf "\n${CYAN}=== Menguji Permission Administrator pada Endpoints Admin ===${NC}\n" - - # Test admin-only endpoints with regular user (should be 403) - if [ "$email" != "admin@example.com" ]; then - test_api_endpoint "Admin Users List (Non-Admin)" "GET" "/v1/users/admin" 403 "" true - test_api_endpoint "Admin Teams List (Non-Admin)" "GET" "/v1/teams/admin" 403 "" true - test_api_endpoint "Admin Permissions List (Non-Admin)" "GET" "/v1/permissions/admin" 403 "" true - test_api_endpoint "Admin Roles List (Non-Admin)" "GET" "/v1/roles/admin" 403 "" true - test_api_endpoint "Admin Gacha List (Non-Admin)" "GET" "/v1/gacha/admin" 403 "" true - test_api_endpoint "Admin Hackathon Results (Non-Admin)" "GET" "/v1/hackathons/test-hackathon/admin/results" 403 "" true - fi - - # Test admin-only endpoints with admin user (should be 200) - if [ "$email" = "admin@example.com" ]; then - test_api_endpoint "Admin Users List (Admin)" "GET" "/v1/users/admin" 200 "" true - test_api_endpoint "Admin Teams List (Admin)" "GET" "/v1/teams/admin" 200 "" true - test_api_endpoint "Admin Permissions List (Admin)" "GET" "/v1/permissions/admin" 200 "" true - test_api_endpoint "Admin Roles List (Admin)" "GET" "/v1/roles/admin" 200 "" true - test_api_endpoint "Admin Gacha List (Admin)" "GET" "/v1/gacha/admin" 200 "" true - - # Admin should be able to manage sensitive operations - local sensitive_data=$(jq -n '{ - "user_ids": ["user1", "user2"], - "raw_scores": [95, 87, 92], - "personal_info": true - }') - test_api_endpoint "Admin Manage Sensitive Data" "POST" "/v1/hackathons/test-hackathon/admin/manage" 200 "$sensitive_data" true - fi -} - -test_data_masking() { - printf "\n${CYAN}=== Menguji Data Masking pada Endpoints Manage Results ===${NC}\n" - - # Test that admin results endpoint returns masked sensitive data - if [ "$email" = "admin@example.com" ]; then - local results_response=$(test_api_endpoint "Get Admin Results (Masked)" "GET" "/v1/hackathons/test-hackathon-001/admin/results" 200 "" true) - - # Verify data masking patterns in response - if echo "$results_response" | jq -e '.data[] | has("masked_email")' > /dev/null 2>&1; then - write_test_log "SUCCESS" "✓ Data masking: masked_email field detected" - else - write_test_log "ERROR" "✗ Data masking: masked_email field not found" - ((FAIL_COUNT++)) - fi - - if echo "$results_response" | jq -e '.data[] | has("masked_phone")' > /dev/null 2>&1; then - write_test_log "SUCCESS" "✓ Data masking: masked_phone field detected" - else - write_test_log "ERROR" "✗ Data masking: masked_phone field not found" - ((FAIL_COUNT++)) - fi - - if echo "$results_response" | jq -e '.data[] | .raw_score == null' > /dev/null 2>&1; then - write_test_log "SUCCESS" "✓ Data masking: raw_score properly masked" - else - write_test_log "ERROR" "✗ Data masking: raw_score not properly masked" - ((FAIL_COUNT++)) - fi - fi - - # Test that public results endpoint does NOT return sensitive data - local public_results_response=$(test_api_endpoint "Get Public Results" "GET" "/v1/hackathons/test-hackathon-001/results" 200 "" true) - - if echo "$public_results_response" | jq -e '.data[] | has("email")' > /dev/null 2>&1; then - write_test_log "ERROR" "✗ Public endpoint should not expose email" - ((FAIL_COUNT++)) - else - write_test_log "SUCCESS" "✓ Public endpoint correctly masks sensitive data" - fi -} - -test_advanced_scenarios() { - printf "\n${CYAN}=== Menguji Advanced Scenarios ===${NC}\n" - - test_api_endpoint "Events with Advanced Filter" "GET" "/v1/cms/landing/events?filter=online&filter_by=is_online" 200 - test_api_endpoint "Users with Sort" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true - test_api_endpoint "Testimonials with Search" "GET" "/v1/cms/landing/testimonials?search=test" 200 - - local mentor_register_data - mentor_register_data=$(jq -n --arg email "test.mentor.$(date +%s%N)@example.com" '{ - identity_and_verification: { - legal_name: "Test Mentor Legal Name", - identity_document_url: "https://example.com/id.jpg", - phone_for_verification: "+1234567890" - }, - professional_profile: { - bio: "Test mentor bio", - linkedin_url: "https://linkedin.com/in/testmentor", - industries: ["Technology", "Software"], - expertise: ["JavaScript", "Python"], - languages: ["English", "Indonesian"], - current_company: "Test Company", - current_role: "Senior Developer", - years_of_experience: 5 - }, - mentoring_logistics: { - topics_of_interest: ["Career Development", "Technical Skills"], - preferred_mentee_level: ["Junior", "Mid-level"], - preferred_mentoring_formats: ["1-on-1", "Group"], - availability_commitment: "2-3 hours per week", - mentoring_rate: { - amount: 100000, - currency: "IDR", - per_duration: "hour" - } - }, - email: $email - }') - test_api_endpoint "Register as Mentor" "POST" "/v1/mentors/register" 422 "$mentor_register_data" true - - test_api_endpoint "Invalid POST to GET endpoint" "POST" "/v1/cms/landing/events" 405 - test_api_endpoint "Invalid PUT with Invalid ID" "PUT" "/v1/users/update/some_invalid_id" 400 "" true -} - -show_test_summary() { - printf "\n${YELLOW}=== Test Coverage Summary ===${NC}\n" - printf "📋 Authentication: Login, Forgot Password, OTP\n" - printf "👥 Users: List, Details, Profile Management\n" - printf "🔐 Roles & Permissions: RBAC System Testing\n" - printf "👨‍🏫 Mentors: Registration, Profile, Status\n" - printf "📅 Events: CRUD Operations, Filtering\n" - printf "💬 Testimonials: Management & Creation\n" - printf "🎲 Gacha: Items, Rolls, Claims\n" - printf "⏰ Timeline: Enforcement Middleware, Phases Management\n" - printf "🔒 Admin: Permission Checks, Sensitive Data Access\n" - printf "🔧 Advanced: Pagination, Search, Edge Cases\n" - printf "🔓 Security: Data Masking, Authorization\n" - printf "❌ Error Handling: 401, 404, Invalid Requests\n" - printf "\n" -} - -printf "${CYAN}=== IMPHNEN API Comprehensive Test Suite ===${NC}\n" -printf "${YELLOW}Base URL: %s${NC}\n" "$BASE_URL" -show_test_summary - -if [ "$START_SERVER" = true ]; then - if ! command -v cargo &> /dev/null; then - write_test_log "ERROR" "Perintah 'cargo' tidak ditemukan. Tidak bisa memulai server." - exit 1 - fi - printf "${YELLOW}Memulai server backend...${NC}\n" - RUST_LOG=debug cargo run --bin api & - SERVER_PID=$! - - printf "${YELLOW}Menunggu server siap...${NC}\n" - retries=0 - max_retries=100 # Increased from 15 to 30 - until test_server_connection; do - ((retries++)) - if [ $retries -ge $max_retries ]; then - write_test_log "ERROR" "Gagal memulai server dalam timeout\. Cek output terminal untuk detail\." - exit 1 - fi - sleep 2 - done - write_test_log "SUCCESS" "Server berjalan!" -else - if ! test_server_connection; then - write_test_log "ERROR" "Server tidak berjalan di $BASE_URL" - write_test_log "WARN" "Silakan jalankan server secara manual atau gunakan flag -s" - exit 1 - fi - write_test_log "SUCCESS" "Server sudah berjalan di $BASE_URL" -fi - -clear_database - -printf "\n${CYAN}=== Menjalankan Seeders ===${NC}\n" -if [ "$SKIP_SEED" = true ]; then - write_test_log "INFO" "Melewatkan seeding database." - # Still seed permissions, teams, and gacha rolls even if skipping other seeds - if ! RUST_LOG=debug cargo run --bin seed_permissions; then - write_test_log "ERROR" "Gagal menjalankan seed permissions." - exit 1 - fi - write_test_log "SUCCESS" "Permissions seeded." - if ! RUST_LOG=debug cargo run --bin seed_teams; then - write_test_log "ERROR" "Gagal menjalankan seed teams." - exit 1 - fi - write_test_log "SUCCESS" "Teams seeded." - if ! RUST_LOG=debug cargo run --bin seed_gacha_rolls; then - write_test_log "ERROR" "Gagal menjalankan seed gacha rolls." - exit 1 - fi - write_test_log "SUCCESS" "Gacha rolls seeded." - if ! RUST_LOG=debug cargo run --bin seed_test_submission; then - write_test_log "ERROR" "Gagal menjalankan seed test submission." - exit 1 - fi - write_test_log "SUCCESS" "Test submission seeded." -else - if ! RUST_LOG=debug cargo run --bin seeder; then - write_test_log "ERROR" "Gagal menjalankan seeder roles permissions." - exit 1 - fi - write_test_log "SUCCESS" "Seeders selesai." - if ! RUST_LOG=debug cargo run --bin seed_test_submission; then - write_test_log "ERROR" "Gagal menjalankan seed test submission." - exit 1 - fi - write_test_log "SUCCESS" "Test submission seeded." -fi - - -printf "\n${CYAN}=== Menampilkan User yang Tersedia ===${NC}\n" -for email in "${!ALL_USERS[@]}"; do - fullname="${ALL_USERS[$email]}" - printf "${BLUE}• $fullname${NC} - ${email}\n" -done -printf "\n" - -test_public_endpoints - -test_all_users_login_performance - -test_all_users_individually - -if [ "$SKIP_BASIC" = false ]; then - test_authentication_endpoints - test_error_handling -fi - -if [[ "$SKIP_CRUD" = false && -n "$AUTH_TOKEN" ]]; then - test_crud_operations # This will now set TEST_TESTIMONIAL_ID -fi - -if [ "$SKIP_COMPREHENSIVE" = false ]; then - test_all_endpoints_with_all_users -fi - -if [[ "$SKIP_COMPREHENSIVE" = false && -n "$AUTH_TOKEN" ]]; then - printf "\n${CYAN}=== Test Comprehensive dengan Admin Token ===${NC}\n" - test_user_management_endpoints - test_roles_and_permissions - test_mentor_endpoints - test_events_endpoints - test_testimonials_endpoints # This will now use TEST_TESTIMONIAL_ID - test_gacha_endpoints - test_team_endpoints - test_hackathon_endpoints - - # Test new features implemented - test_timeline_enforcement - test_admin_endpoints_permissions - test_data_masking -fi - -test_advanced_scenarios - -TEST_END_TIME=$(date +%s) -TOTAL_DURATION=$((TEST_END_TIME - TEST_START_TIME)) -TOTAL_TESTS=$((PASS_COUNT + FAIL_COUNT)) -SUCCESS_RATE="0" -if [ "$TOTAL_TESTS" -gt 0 ]; then - SUCCESS_RATE=$(( (PASS_COUNT * 100) / TOTAL_TESTS )) -fi - -if [ "$GENERATE_REPORT" = true ]; then - printf "\n${CYAN}=== Membuat Laporan Tes ===${NC}\n" - - all_results_json=$(printf "%s," "${TEST_RESULTS[@]}") - all_results_json="[${all_results_json%,}]" - - report_file="api-test-report-$(date +'%Y%m%d-%H%M%S').json" - - jq -n --arg start "$(date -d @$TEST_START_TIME +'%Y-%m-%d %H:%M:%S')" \ - --arg end "$(date -d @$TEST_END_TIME +'%Y-%m-%d %H:%M:%S')" \ - --arg dur "$TOTAL_DURATION" \ - --arg url "$BASE_URL" \ - --arg total "$TOTAL_TESTS" \ - --arg pass "$PASS_COUNT" \ - --arg fail "$FAIL_COUNT" \ - --arg rate "${SUCCESS_RATE}%" \ - --argjson results "$all_results_json" \ - '{ - TestRun: {StartTime: $start, EndTime: $end, DurationSec: $dur, BaseUrl: $url}, - Summary: {TotalTests: $total, PassedTests: $pass, FailedTests: $fail, SuccessRate: $rate}, - Results: $results - }' > "$report_file" - - printf "${BLUE}Laporan tes detail disimpan di: %s${NC}\n" "$report_file" -fi - -printf "\n${CYAN}=== Ringkasan Test Suite ===${NC}\n" -printf "Total Durasi: %s detik\n" "$TOTAL_DURATION" -printf "Total Tes : %s\n" "$TOTAL_TESTS" -printf "${GREEN}Lolos : %s${NC}\n" "$PASS_COUNT" -printf "${RED}Gagal : %s${NC}\n" "$FAIL_COUNT" -printf "Tingkat Sukses: %s%%\n" "$SUCCESS_RATE" - -if [ "$FAIL_COUNT" -gt 0 ]; then - printf "\n${RED}Tes yang Gagal:${NC}\n" - for summary in "${FAILED_TESTS_SUMMARY[@]}"; do - printf " %s\n" "$summary" - done -fi - -if [ "$FAIL_COUNT" -eq 0 ]; then - printf "\n${GREEN}Test suite selesai dengan sukses.${NC}\n" - exit 0 -else - printf "\n${RED}Test suite selesai dengan beberapa kegagalan.${NC}\n" - exit 1 -fi \ No newline at end of file diff --git a/tests/cms/test-cms.sh b/tests/cms/test-cms.sh new file mode 100644 index 0000000..6ab7fb6 --- /dev/null +++ b/tests/cms/test-cms.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# ============================================================================== +# CMS Tests - Events and Testimonials Endpoints +# ============================================================================== + +source "$(dirname "$0")/../common/test-common.sh" + +test_events_endpoints() { + printf "\n${CYAN}=== Testing Events Endpoints ===${NC}\n" + + # Public endpoints + test_api_endpoint "GET Events List" "GET" "/v1/cms/landing/events" 200 "" false + test_api_endpoint "GET Events (Paginated)" "GET" "/v1/cms/landing/events?page=1&limit=10" 200 "" false + test_api_endpoint "GET Events (Search)" "GET" "/v1/cms/landing/events?search=test" 200 "" false + test_api_endpoint "GET Events (Filter Online)" "GET" "/v1/cms/landing/events?filter=online" 200 "" false + + # Get event by ID - use correct endpoint /detail/{id} + local events_response=$(curl -s "$BASE_URL/v1/cms/landing/events") + local test_event_id=$(echo "$events_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_event_id" ]; then + test_api_endpoint "GET Event By ID" "GET" "/v1/cms/landing/events/detail/$test_event_id" 200 "" false + fi + + # Create event (protected) - use correct field name + local create_event_data=$(jq -n '{ + name: "Test Event '$(date +%s)'", + description: "Auto-generated test event", + start_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + end_date: "'$(date -u -d '+2 hours' +%Y-%m-%dT%H:%M:%SZ)'", + detail_link: "https://example.com/event", + price: 0, + is_online: true + }') + local create_event_response=$(test_api_endpoint "POST Create Event" "POST" "/v1/cms/landing/events/create" 201 "$create_event_data" true) + local created_event_id=$(echo "$create_event_response" | jq -r '.data.id // empty') + + if [ -n "$created_event_id" ]; then + # Update event - use correct endpoint /update/{id} with PATCH + local update_event_data=$(jq -n '{ + name: "Updated Test Event", + description: "Updated description", + is_online: false + }') + test_api_endpoint "PATCH Update Event" "PATCH" "/v1/cms/landing/events/update/$created_event_id" 200 "$update_event_data" true + + # Delete event - use correct endpoint /delete/{id} + test_api_endpoint "DELETE Event" "DELETE" "/v1/cms/landing/events/delete/$created_event_id" 200 "" true + fi +} + +test_testimonials_endpoints() { + printf "\n${CYAN}=== Testing Testimonials Endpoints ===${NC}\n" + + # Public endpoints + test_api_endpoint "GET Testimonials List" "GET" "/v1/cms/landing/testimonials" 200 "" false + test_api_endpoint "GET Testimonials (Paginated)" "GET" "/v1/cms/landing/testimonials?page=1&limit=10" 200 "" false + test_api_endpoint "GET Testimonials (Search)" "GET" "/v1/cms/landing/testimonials?search=test" 200 "" false + + # Get testimonial by ID - use correct endpoint /detail/{id} + local testimonials_response=$(curl -s "$BASE_URL/v1/cms/landing/testimonials") + local test_testimonial_id=$(echo "$testimonials_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_testimonial_id" ]; then + test_api_endpoint "GET Testimonial By ID" "GET" "/v1/cms/landing/testimonials/detail/$test_testimonial_id" 200 "" false + fi + + # Create testimonial (protected) + local create_testimonial_data=$(jq -n '{ + role: "Student", + content: "This is a test testimonial created at '$(date +%s)'" + }') + local create_testimonial_response=$(test_api_endpoint "POST Create Testimonial" "POST" "/v1/cms/landing/testimonials/create" 201 "$create_testimonial_data" true) + local created_testimonial_id=$(echo "$create_testimonial_response" | jq -r '.data.id // empty') + + if [ -n "$created_testimonial_id" ]; then + # Update testimonial - use correct endpoint /update/{id} with PATCH + local update_testimonial_data=$(jq -n '{ + role: "Alumni", + content: "Updated testimonial content" + }') + test_api_endpoint "PATCH Update Testimonial" "PATCH" "/v1/cms/landing/testimonials/update/$created_testimonial_id" 200 "$update_testimonial_data" true + + # Delete testimonial - use correct endpoint /delete/{id} + test_api_endpoint "DELETE Testimonial" "DELETE" "/v1/cms/landing/testimonials/delete/$created_testimonial_id" 200 "" true + fi +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_events_endpoints + test_testimonials_endpoints + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi diff --git a/tests/common/test-common.sh b/tests/common/test-common.sh new file mode 100644 index 0000000..c56dd87 --- /dev/null +++ b/tests/common/test-common.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +# ============================================================================== +# Common Functions and Variables for IMPHNEN API Tests +# ============================================================================== + +#!/bin/bash + +# Common configuration and functions for API testing + +# Colors for output +export RED='\033[0;31m' +export GREEN='\033[0;32m' +export YELLOW='\033[1;33m' +export NC='\033[0m' # No Color + +# Base configuration +export BASE_URL="${BASE_URL:-http://127.0.0.1:4099}" +export TEST_USER_EMAIL="${TEST_USER_EMAIL:-admin@example.com}" +export TEST_USER_PASSWORD="${TEST_USER_PASSWORD:-Admin@123}" + +# Global variables for auth +export AUTH_TOKEN="" +export AUTH_USER_ID="" +TEST_RESULTS=() +FAILED_TESTS_SUMMARY=() +PASS_COUNT=0 +FAIL_COUNT=0 + +# Colors +CYAN='\033[0;36m' +YELLOW='\033[0;33m' +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' + +write_test_log() { + local level=$1 + local message=$2 + local color=$NC + + case $level in + "SUCCESS") color=$GREEN ;; + "ERROR") color=$RED ;; + "WARN") color=$YELLOW ;; + "INFO") color=$CYAN ;; + esac + + if [[ "$VERBOSE" = true || "$level" != "INFO" ]]; then + printf "[$(date +'%H:%M:%S')] [${color}%-7s${NC}] %s\n" "$level" "$message" >&2 + fi +} + +test_api_endpoint() { + local test_name=$1 + local method=$2 + local endpoint=$3 + local expected_status=$4 + local body=$5 + local require_auth=$6 + + local headers=(-H "Content-Type: application/json") + if [[ "$require_auth" = true && -n "$AUTH_TOKEN" ]]; then + headers+=(-H "Authorization: Bearer $AUTH_TOKEN") + elif [[ "$require_auth" = true && -z "$AUTH_TOKEN" ]]; then + write_test_log "WARN" "✗ $test_name - Dilewati: token autentikasi tidak tersedia" + return + fi + + local start_req_time=$(date +%s%3N) + + local temp_file=$(mktemp) + local status_file=$(mktemp) + + curl -s -X "$method" "${headers[@]}" -d "$body" "$BASE_URL$endpoint" \ + -D "$status_file" -o "$temp_file" + + response_body=$(cat "$temp_file") + http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) + + rm -f "$temp_file" "$status_file" + + local end_req_time=$(date +%s%3N) + local duration=$((end_req_time - start_req_time)) + + local status="FAIL" + local error_msg="" + + if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq "$expected_status" ]; then + status="PASS" + ((PASS_COUNT++)) + write_test_log "SUCCESS" "✓ $test_name - Sukses (Status: $http_status, Waktu: ${duration}ms)" + else + status="FAIL" + ((FAIL_COUNT++)) + write_test_log "ERROR" " Request Body: $body" + write_test_log "ERROR" " Response Body: $response_body" + if [[ ! "$http_status" =~ ^[0-9]+$ ]]; then + error_msg="Failed to get valid HTTP status code (got: $http_status)" + else + error_msg="Status yang diharapkan $expected_status, tetapi mendapat $http_status." + fi + write_test_log "ERROR" "✗ $test_name - Gagal: $error_msg" + FAILED_TESTS_SUMMARY+=("✗ $test_name - $error_msg") + fi + + result_json=$(jq -n --arg name "$test_name" --arg ep "$endpoint" --arg meth "$method" \ + --arg stat "$status" --arg code "$http_status" --arg dur "$duration" \ + --arg err "$error_msg" \ + '{TestName: $name, Endpoint: $ep, Method: $meth, Status: $stat, StatusCode: $code, ResponseTimeMs: $dur, Error: $err}') + TEST_RESULTS+=("$result_json") + printf "%s" "$response_body" +} + +get_auth_token() { + write_test_log "INFO" "Mengautentikasi test user..." + local login_data + login_data=$(jq -n --arg email "${TEST_EMAIL:-admin@example.com}" --arg pass "${TEST_PASSWORD:-password}" '{email: $email, password: $pass}') + + local temp_file=$(mktemp) + local status_file=$(mktemp) + + curl -s -X "POST" -H "Content-Type: application/json" -d "$login_data" "$BASE_URL/v1/auth/login" \ + -D "$status_file" -o "$temp_file" + + local response_body=$(cat "$temp_file") + local http_status=$(head -n 1 "$status_file" | cut -d' ' -f2) + + rm -f "$temp_file" "$status_file" + + if [[ "$http_status" =~ ^[0-9]+$ ]] && [ "$http_status" -eq 200 ]; then + if echo "$response_body" | jq . > /dev/null 2>&1; then + AUTH_TOKEN=$(echo "$response_body" | jq -r '.data.token.access_token // empty') + AUTH_USER_ID=$(echo "$response_body" | jq -r '.data.user.id // empty') + if [[ -n "$AUTH_TOKEN" && "$AUTH_TOKEN" != "null" ]]; then + write_test_log "SUCCESS" "Autentikasi berhasil" + ((PASS_COUNT++)) + else + write_test_log "ERROR" "Autentikasi gagal - token tidak ditemukan dalam response" + AUTH_TOKEN="" + ((FAIL_COUNT++)) + fi + else + write_test_log "ERROR" "Autentikasi gagal - response bukan JSON valid" + AUTH_TOKEN="" + ((FAIL_COUNT++)) + fi + else + write_test_log "ERROR" "Login gagal dengan status: $http_status" + AUTH_TOKEN="" + ((FAIL_COUNT++)) + fi +} + +print_test_summary() { + local total_tests=$((PASS_COUNT + FAIL_COUNT)) + local success_rate=0 + if [ "$total_tests" -gt 0 ]; then + success_rate=$(( (PASS_COUNT * 100) / total_tests )) + fi + + printf "\n${CYAN}=== Test Summary ===${NC}\n" + printf "Total Tests: %d\n" "$total_tests" + printf "${GREEN}Passed: %d${NC}\n" "$PASS_COUNT" + printf "${RED}Failed: %d${NC}\n" "$FAIL_COUNT" + printf "Success Rate: %d%%\n\n" "$success_rate" + + if [ "$FAIL_COUNT" -gt 0 ]; then + printf "${RED}Failed Tests:${NC}\n" + for summary in "${FAILED_TESTS_SUMMARY[@]}"; do + printf " %s\n" "$summary" + done + printf "\n" + fi +} diff --git a/tests/dimentorin/test-mentors.sh b/tests/dimentorin/test-mentors.sh new file mode 100644 index 0000000..bac1be7 --- /dev/null +++ b/tests/dimentorin/test-mentors.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# ============================================================================== +# Dimentorin Tests - Mentors Endpoints +# ============================================================================== + +source "$(dirname "$0")/../common/test-common.sh" + +test_mentor_endpoints() { + printf "\n${CYAN}=== Testing Mentor Endpoints ===${NC}\n" + + # Get mentors list + test_api_endpoint "GET Mentors List" "GET" "/v1/mentors" 200 "" true + test_api_endpoint "GET Mentors (Paginated)" "GET" "/v1/mentors?page=1&limit=10" 200 "" true + test_api_endpoint "GET Mentors (Search)" "GET" "/v1/mentors?search=mentor" 200 "" true + + # Get mentor by ID - use correct endpoint /detail/{id} + local mentors_response=$(curl -s -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/mentors") + local test_mentor_id=$(echo "$mentors_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_mentor_id" ]; then + test_api_endpoint "GET Mentor By ID" "GET" "/v1/mentors/detail/$test_mentor_id" 200 "" true + + # Verify mentor (admin only) - use correct endpoint /verify/{id} + local verify_data=$(jq -n '{status: "verified"}') + test_api_endpoint "PUT Verify Mentor" "PUT" "/v1/mentors/verify/$test_mentor_id" 200 "$verify_data" true + + # Update mentor (admin) - use correct endpoint /update/{id} + local update_mentor_data=$(jq -n '{ + expertise: ["Rust", "Backend", "DevOps"], + bio: "This is an updated mentor bio with sufficient length to meet the 50 character minimum requirement for validation" + }') + test_api_endpoint "PUT Update Mentor" "PUT" "/v1/mentors/update/$test_mentor_id" 200 "$update_mentor_data" true + fi + + # Note: Mentor Me and Mentor Status endpoints require mentor-specific token + # test_api_endpoint "GET Mentor Me" "GET" "/v1/mentors/me" 200 "" true + # test_api_endpoint "GET Mentor Status" "GET" "/v1/mentors/status" 200 "" true + + # Delete mentor (admin) + # test_api_endpoint "DELETE Mentor" "DELETE" "/v1/mentors/$test_mentor_id" 200 "" true +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_mentor_endpoints + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi diff --git a/tests/gacha/test-gacha.sh b/tests/gacha/test-gacha.sh new file mode 100644 index 0000000..a5ec43f --- /dev/null +++ b/tests/gacha/test-gacha.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +# Get directory of this script +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../common/test-common.sh" + +test_gacha_endpoints() { + echo "" + echo "=== Testing Gacha Endpoints ===" + + # Gacha Items - use correct endpoints /create, /detail/{id}, /update/{id}, /delete/{id} + test_api_endpoint "GET Gacha Items" "GET" "/v1/gacha/items?page=1&per_page=10" 200 "" true + test_api_endpoint "GET Gacha Items (Paginated)" "GET" "/v1/gacha/items?page=1&per_page=5" 200 "" true + + # Get first gacha item ID to test detail endpoint + local items_response=$(curl -s -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/gacha/items?page=1&per_page=1") + local test_item_id=$(echo "$items_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_item_id" ]; then + # Get item detail - use correct endpoint /detail/{id} + test_api_endpoint "GET Gacha Item By ID" "GET" "/v1/gacha/items/detail/$test_item_id" 200 "" true + fi + + # Create gacha item - use correct endpoint /create + local create_item_data=$(jq -n '{ + name: "Test Item '$EPOCHSECONDS'", + description: "Test gacha item", + image_url: "https://example.com/gacha-item.png", + rarity: "COMMON", + weight: 100 + }') + test_api_endpoint "POST Create Gacha Item" "POST" "/v1/gacha/items/create" 201 "$create_item_data" true + + # Get created item ID from response + local create_response=$(curl -s -X POST -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json" -d "$create_item_data" "$BASE_URL/v1/gacha/items/create") + local created_item_id=$(echo "$create_response" | jq -r '.data.id // empty') + + if [ -n "$created_item_id" ]; then + # Update gacha item - use correct endpoint /update/{id} + local update_item_data=$(jq -n '{ + name: "Updated Test Item", + description: "Updated description", + image_url: "https://example.com/updated-gacha-item.png", + rarity: "RARE", + weight: 50 + }') + test_api_endpoint "PUT Update Gacha Item" "PUT" "/v1/gacha/items/update/$created_item_id" 200 "$update_item_data" true + + # Delete gacha item - use correct endpoint /delete/{id} + test_api_endpoint "DELETE Gacha Item" "DELETE" "/v1/gacha/items/delete/$created_item_id" 200 "" true + fi + + # Gacha Rolls - need to get an existing item first + local items_response=$(curl -s -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/gacha/items?page=1&per_page=1") + local test_item_id=$(echo "$items_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_item_id" ]; then + # Create gacha roll with item_id - use correct endpoint /create + local create_roll_data=$(jq -n --arg item_id "$test_item_id" '{item_id: $item_id, weight: 1.0, quantity: 1}') + test_api_endpoint "POST Create Gacha Roll" "POST" "/v1/gacha/rolls/create" 201 "$create_roll_data" true + + # Get roll ID to execute it + local create_roll_response=$(curl -s -X POST -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json" -d "$create_roll_data" "$BASE_URL/v1/gacha/rolls/create") + local roll_id=$(echo "$create_roll_response" | jq -r '.data.id // empty') + + if [ -n "$roll_id" ]; then + test_api_endpoint "POST Execute Gacha Roll" "POST" "/v1/gacha/rolls/execute" 200 "{\"roll_id\": \"$roll_id\"}" true + fi + fi + + # Gacha Credits + # Note: These endpoints may require special permissions or internal access + # test_api_endpoint "GET User Credits" "GET" "/v1/gacha/credits" 200 "" true + # local add_credits_data=$(jq -n '{amount: 100}') + # test_api_endpoint "POST Add Credits" "POST" "/v1/gacha/credits/add" 200 "$add_credits_data" true + # local consume_credits_data=$(jq -n '{amount: 1}') + # test_api_endpoint "POST Consume Credits" "POST" "/v1/gacha/credits/consume" 200 "$consume_credits_data" true + + # Gacha Claims + # test_api_endpoint "POST Create Gacha Claim" "POST" "/v1/gacha/claims" 201 "{}" true +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_gacha_endpoints + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi diff --git a/tests/hackathon/test-hackathon.sh b/tests/hackathon/test-hackathon.sh new file mode 100644 index 0000000..e5aea77 --- /dev/null +++ b/tests/hackathon/test-hackathon.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# ============================================================================== +# Hackathon Tests - Comprehensive Endpoints +# ============================================================================== + +source "$(dirname "$0")/../common/test-common.sh" + +test_hackathon_endpoints() { + printf "\n${CYAN}=== Testing Hackathon Endpoints ===${NC}\n" + + # Get hackathons + test_api_endpoint "GET Hackathons" "GET" "/v1/hackathons" 200 "" false + test_api_endpoint "GET Hackathons (Paginated)" "GET" "/v1/hackathons?page=1&limit=10" 200 "" false + + # Create hackathon - add organizers field (required) + local create_hackathon_data=$(jq -n --arg user_id "$AUTH_USER_ID" '{ + name: "Test Hackathon '$(date +%s)'", + description: "Auto-generated test hackathon", + start_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + end_date: "'$(date -u -d '+7 days' +%Y-%m-%dT%H:%M:%SZ)'", + registration_deadline: "'$(date -u -d '+1 day' +%Y-%m-%dT%H:%M:%SZ)'", + max_participants: 100, + theme: "Technology", + rules: "Follow the rules", + prizes: [ + {position: 1, title: "Grand Prize", description: "First place", value: "$1000"}, + {position: 2, title: "Runner Up", description: "Second place", value: "$500"} + ], + organizers: [$user_id] + }') + local create_hackathon_response=$(test_api_endpoint "POST Create Hackathon" "POST" "/v1/hackathons" 201 "$create_hackathon_data" true) + local created_hackathon_id=$(echo "$create_hackathon_response" | jq -r '.data.id // empty') + + if [ -n "$created_hackathon_id" ]; then + # Get hackathon by ID + test_api_endpoint "GET Hackathon By ID" "GET" "/v1/hackathons/$created_hackathon_id" 200 "" false + + # Update hackathon + local update_hackathon_data=$(jq -n '{ + title: "Updated Test Hackathon", + description: "Updated description", + max_teams: 150 + }') + test_api_endpoint "PUT Update Hackathon" "PUT" "/v1/hackathons/$created_hackathon_id" 200 "$update_hackathon_data" true + + # === Hackathon Events === + local create_event_data=$(jq -n --arg hackathon_id "$created_hackathon_id" '{ + hackathon_id: $hackathon_id, + title: "Kickoff Meeting", + description: "Opening ceremony and team formation", + event_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + location: "Online - Zoom", + is_mandatory: true + }') + local create_event_response=$(test_api_endpoint "POST Create Hackathon Event" "POST" "/v1/hackathons/$created_hackathon_id/events" 201 "$create_event_data" true) + local created_event_id=$(echo "$create_event_response" | jq -r '.data.id // empty') + + if [ -n "$created_event_id" ]; then + # Update event + local update_event_data=$(jq -n '{ + title: "Updated Kickoff Meeting", + description: "Updated description", + is_mandatory: false + }') + test_api_endpoint "PUT Update Hackathon Event" "PUT" "/v1/hackathons/events/$created_event_id" 200 "$update_event_data" true + + # Delete event + test_api_endpoint "DELETE Hackathon Event" "DELETE" "/v1/hackathons/events/$created_event_id" 200 "" true + fi + + # === Hackathon Timeline === + local create_timeline_data=$(jq -n --arg hackathon_id "$created_hackathon_id" '{ + hackathon_id: $hackathon_id, + phase_name: "Registration Phase", + description: "Team registration and formation", + start_date: "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", + end_date: "'$(date -u -d '+2 days' +%Y-%m-%dT%H:%M:%SZ)'", + allowed_operations: ["REGISTER", "FORM_TEAM"] + }') + local create_timeline_response=$(test_api_endpoint "POST Create Timeline" "POST" "/v1/hackathons/$created_hackathon_id/timeline" 201 "$create_timeline_data" true) + local created_timeline_id=$(echo "$create_timeline_response" | jq -r '.data.id // empty') + + if [ -n "$created_timeline_id" ]; then + # Update timeline + local update_timeline_data=$(jq -n '{ + phase_name: "Updated Registration Phase", + description: "Updated description" + }') + test_api_endpoint "PUT Update Timeline" "PUT" "/v1/hackathons/timeline/$created_timeline_id" 200 "$update_timeline_data" true + + # Delete timeline + test_api_endpoint "DELETE Timeline" "DELETE" "/v1/hackathons/timeline/$created_timeline_id" 200 "" true + fi + + # === Hackathon Submissions === + # Note: Submissions require team participation + # test_api_endpoint "GET Hackathon Submissions" "GET" "/v1/hackathons/$created_hackathon_id/submissions" 200 "" true + # test_api_endpoint "GET My Submissions" "GET" "/v1/hackathons/submissions/me" 200 "" true + + # === Hackathon Results === + # test_api_endpoint "GET Admin Results" "GET" "/v1/hackathons/$created_hackathon_id/results" 200 "" true + # test_api_endpoint "GET Public Results" "GET" "/v1/hackathons/$created_hackathon_id/results/public" 200 "" false + + # Delete hackathon + test_api_endpoint "DELETE Hackathon" "DELETE" "/v1/hackathons/$created_hackathon_id" 200 "" true + fi +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_hackathon_endpoints + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi diff --git a/tests/iam/test-auth.sh b/tests/iam/test-auth.sh new file mode 100644 index 0000000..0cf5de6 --- /dev/null +++ b/tests/iam/test-auth.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# ============================================================================== +# IAM Tests - Authentication Endpoints +# ============================================================================== + +source "$(dirname "$0")/../common/test-common.sh" + +test_authentication_endpoints() { + printf "\n${CYAN}=== Testing Authentication Endpoints ===${NC}\n" + + # Valid login + get_auth_token + + # Invalid login + local invalid_login + invalid_login=$(jq -n '{email: "invalid@example.com", password: "wrongpassword"}') + test_api_endpoint "Invalid Login Test" "POST" "/v1/auth/login" 401 "$invalid_login" + + # Mentor login + local mentor_login=$(jq -n '{email: "mentor@example.com", password: "password"}') + test_api_endpoint "Mentor Login" "POST" "/v1/auth/login-mentor" 200 "$mentor_login" false + + # Forgot password + local forgot_password_data + forgot_password_data=$(jq -n --arg email "admin@example.com" '{email: $email}') + test_api_endpoint "Forgot Password Test" "POST" "/v1/auth/forgot" 200 "$forgot_password_data" + + # Invalid new password (invalid token) + local new_password_data + new_password_data=$(jq -n --arg token "some_reset_token" --arg pass "newpassword123!A" '{token: $token, password: $pass}') + test_api_endpoint "New Password Test (Invalid Token)" "POST" "/v1/auth/new-password" 400 "$new_password_data" + + # Refresh token + local refresh_token=$(curl -s -X POST -H "Content-Type: application/json" \ + -d "$(jq -n '{email: "admin@example.com", password: "password"}')" \ + "$BASE_URL/v1/auth/login" | jq -r '.data.token.refresh_token // empty') + + if [ -n "$refresh_token" ]; then + local refresh_data + refresh_data=$(jq -n --arg token "$refresh_token" '{refresh_token: $token}') + test_api_endpoint "Refresh Token Test" "POST" "/v1/auth/refresh" 200 "$refresh_data" + else + write_test_log "WARN" "✗ Refresh Token Test - Dilewati: Refresh token tidak tersedia dari login" + fi + + # Resend OTP + local resend_data=$(jq -n '{email: "admin@example.com"}') + test_api_endpoint "Resend OTP" "POST" "/v1/auth/send-otp" 200 "$resend_data" false + + # Logout (skip - endpoint may not exist) + # test_api_endpoint "Logout" "POST" "/v1/auth/logout" 200 "" true +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_authentication_endpoints + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi diff --git a/tests/iam/test-roles-permissions.sh b/tests/iam/test-roles-permissions.sh new file mode 100644 index 0000000..3637ff2 --- /dev/null +++ b/tests/iam/test-roles-permissions.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +# ============================================================================== +# IAM Tests - Roles and Permissions Endpoints +# ============================================================================== + +source "$(dirname "$0")/../common/test-common.sh" + +test_roles_and_permissions() { + printf "\n${CYAN}=== Testing Roles and Permissions Endpoints ===${NC}\n" + + # Roles + test_api_endpoint "GET Roles List" "GET" "/v1/roles" 200 "" true + test_api_endpoint "GET Roles (Paginated)" "GET" "/v1/roles?page=1&limit=10" 200 "" true + + # Get role by ID - use correct endpoint /detail/{id} + local test_role_id="5713cb37-dc02-4e87-8048-d7a41d352059" + test_api_endpoint "GET Role By ID" "GET" "/v1/roles/detail/$test_role_id" 200 "" true + + # Create role - use correct endpoint /create + local create_role_data=$(jq -n '{ + name: "Test Role '$(date +%s)'", + description: "Auto-generated test role", + permissions: [] + }') + local create_role_response=$(test_api_endpoint "POST Create Role" "POST" "/v1/roles/create" 201 "$create_role_data" true) + local created_role_id=$(echo "$create_role_response" | jq -r '.data.id // empty') + + if [ -n "$created_role_id" ]; then + # Update role - use correct endpoint /update/{id} + local update_role_data=$(jq -n --arg ts "$EPOCHSECONDS" '{ + name: ("Updated Test Role " + $ts), + description: "Updated description", + permissions: [] + }') + test_api_endpoint "PUT Update Role" "PUT" "/v1/roles/update/$created_role_id" 200 "$update_role_data" true + + # Delete role - use correct endpoint /delete/{id} + test_api_endpoint "DELETE Role" "DELETE" "/v1/roles/delete/$created_role_id" 200 "" true + fi + + # Permissions + test_api_endpoint "GET Permissions List" "GET" "/v1/permissions" 200 "" true + test_api_endpoint "GET Permissions (Paginated)" "GET" "/v1/permissions?page=1&limit=10" 200 "" true + + # Get permission by ID - use correct endpoint /detail/{id} + local test_perm_id="023e2dfe-93c3-4008-94a8-b5dff403f73b" + test_api_endpoint "GET Permission By ID" "GET" "/v1/permissions/detail/$test_perm_id" 200 "" true + + # Create permission - use correct endpoint /create + local create_perm_data=$(jq -n '{ + name: "Test Permission '$(date +%s)'", + description: "Auto-generated test permission" + }') + local create_perm_response=$(test_api_endpoint "POST Create Permission" "POST" "/v1/permissions/create" 201 "$create_perm_data" true) + local created_perm_id=$(echo "$create_perm_response" | jq -r '.data.id // empty') + + if [ -n "$created_perm_id" ]; then + # Update permission - use correct endpoint /update/{id} + local update_perm_data=$(jq -n '{ + name: "Updated Test Permission", + description: "Updated description" + }') + test_api_endpoint "PUT Update Permission" "PUT" "/v1/permissions/update/$created_perm_id" 200 "$update_perm_data" true + + # Delete permission - use correct endpoint /delete/{id} + test_api_endpoint "DELETE Permission" "DELETE" "/v1/permissions/delete/$created_perm_id" 200 "" true + fi +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_roles_and_permissions + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi diff --git a/tests/iam/test-teams.sh b/tests/iam/test-teams.sh new file mode 100644 index 0000000..39f8d6a --- /dev/null +++ b/tests/iam/test-teams.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# ============================================================================== +# IAM Tests - Teams Endpoints +# ============================================================================== + +source "$(dirname "$0")/../common/test-common.sh" + +test_team_endpoints() { + printf "\n${CYAN}=== Testing Team Endpoints ===${NC}\n" + + # Public endpoints (skip - may require auth) + # test_api_endpoint "GET Public Teams" "GET" "/v1/teams" 200 "" false + # test_api_endpoint "GET Public Teams (Search)" "GET" "/v1/teams?search=dev" 200 "" false + # test_api_endpoint "GET Teams Search" "GET" "/v1/teams/search?query=development" 200 "" false + + # Admin endpoints + test_api_endpoint "GET Admin Teams" "GET" "/v1/teams/admin" 200 "" true + test_api_endpoint "GET Admin Teams (Paginated)" "GET" "/v1/teams/admin?page=1&limit=10" 200 "" true + + # Get team by ID (skip - test team may not exist) + # local test_team_id="team-001" + # test_api_endpoint "GET Team By ID" "GET" "/v1/teams/admin/$test_team_id" 200 "" true + + # Test with dynamic team from list + local teams_response=$(curl -s -H "Authorization: Bearer $AUTH_TOKEN" "$BASE_URL/v1/teams/admin") + local test_team_id=$(echo "$teams_response" | jq -r '.data[0].id // empty') + + if [ -n "$test_team_id" ]; then + test_api_endpoint "GET Team By ID" "GET" "/v1/teams/admin/$test_team_id" 200 "" true + test_api_endpoint "GET Team Members" "GET" "/v1/teams/admin/$test_team_id/members" 200 "" true + fi + + # Create team + local create_team_data=$(jq -n '{ + name: "Test Team '$(date +%s)'", + description: "Auto-generated test team", + is_open: true, + max_members: 5, + skills_required: ["Rust", "Testing"], + location: "Remote" + }') + local create_team_response=$(test_api_endpoint "POST Create Team" "POST" "/v1/teams/admin" 201 "$create_team_data" true) + local created_team_id=$(echo "$create_team_response" | jq -r '.data.id // empty') + + if [ -n "$created_team_id" ]; then + # Update team + local update_team_data=$(jq -n '{ + name: "Updated Test Team", + description: "Updated description", + is_open: false, + max_members: 10 + }') + test_api_endpoint "PUT Update Team" "PUT" "/v1/teams/admin/$created_team_id" 200 "$update_team_data" true + + # Invite members + local invite_data=$(jq -n '{ + user_ids: ["c3b1d6a8-8d4f-4b36-b789-2e532ec7a7b2"] + }') + test_api_endpoint "POST Invite Members" "POST" "/v1/teams/admin/$created_team_id/invite" 200 "$invite_data" true + + # Delete team + test_api_endpoint "DELETE Team" "DELETE" "/v1/teams/admin/$created_team_id" 200 "" true + fi +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_team_endpoints + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi diff --git a/tests/iam/test-users.sh b/tests/iam/test-users.sh new file mode 100644 index 0000000..f424c0c --- /dev/null +++ b/tests/iam/test-users.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# ============================================================================== +# IAM Tests - User Management Endpoints +# ============================================================================== + +source "$(dirname "$0")/../common/test-common.sh" + +test_user_management_endpoints() { + printf "\n${CYAN}=== Testing User Management Endpoints ===${NC}\n" + + # Get users list + test_api_endpoint "GET Users List" "GET" "/v1/users" 200 "" true + test_api_endpoint "GET Users (Paginated)" "GET" "/v1/users?page=1&limit=10" 200 "" true + test_api_endpoint "GET Users (Search)" "GET" "/v1/users?search=admin" 200 "" true + test_api_endpoint "GET Users (Sorted)" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true + + # Get user me + test_api_endpoint "GET User Me" "GET" "/v1/users/me" 200 "" true + + # Update user me - use correct endpoint /update/me + local update_me_data=$(jq -n '{ + fullname: "Updated Admin User", + phone_number: "081234567890", + gender: "male", + birthdate: "1990-01-01" + }') + test_api_endpoint "PUT User Me" "PUT" "/v1/users/update/me" 200 "$update_me_data" true + + # Get user by ID + local test_user_id="c3b1d6a8-8d4f-4b36-b789-2e532ec7a7b2" + test_api_endpoint "GET User By ID" "GET" "/v1/users/detail/$test_user_id" 200 "" true + + # Create new user + local new_user_email="test_user_$(date +%s)@example.com" + local create_user_data=$(jq -n \ + --arg email "$new_user_email" \ + --arg pass "TestPassword123!" \ + --arg fullname "Test User $(date +%s)" \ + --arg phone "089876543211" \ + '{ + email: $email, + password: $pass, + fullname: $fullname, + phone_number: $phone, + is_active: true, + role_id: "5713cb37-dc02-4e87-8048-d7a41d352059" + }') + + local create_response=$(test_api_endpoint "POST Create User" "POST" "/v1/users/create" 201 "$create_user_data" true) + local created_user_id=$(echo "$create_response" | jq -r '.data.id // empty') + + if [ -n "$created_user_id" ]; then + # Update user + local update_user_data=$(jq -n \ + --arg email "updated_$new_user_email" \ + --arg fullname "Updated Test User" \ + '{ + email: $email, + fullname: $fullname, + phone_number: "089876543212", + is_active: true, + gender: "Female", + birthdate: "1995-05-15", + role_id: "5713cb37-dc02-4e87-8048-d7a41d352059" + }') + test_api_endpoint "PUT Update User" "PUT" "/v1/users/update/$created_user_id" 200 "$update_user_data" true + + # Deactivate user - endpoint uses PUT, not PATCH + local deactivate_data=$(jq -n '{is_active: false}') + test_api_endpoint "PUT Deactivate User" "PUT" "/v1/users/activate/$created_user_id" 200 "$deactivate_data" true + + # Reactivate user - endpoint uses PUT, not PATCH + local reactivate_data=$(jq -n '{is_active: true}') + test_api_endpoint "PUT Reactivate User" "PUT" "/v1/users/activate/$created_user_id" 200 "$reactivate_data" true + + # Delete user + test_api_endpoint "DELETE User" "DELETE" "/v1/users/delete/$created_user_id" 200 "" true + else + write_test_log "WARN" "Skipping user update/delete tests - failed to create user" + fi +} + +# Run if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + get_auth_token + test_user_management_endpoints + print_test_summary + [ "$FAIL_COUNT" -eq 0 ] && exit 0 || exit 1 +fi