From 280d356a516f8e73ec96e39b58805b55eb367e4b Mon Sep 17 00:00:00 2001 From: Urtzi Alfaro Date: Sun, 27 Jul 2025 16:36:56 +0200 Subject: [PATCH] Reorganize test files --- check.sh | 149 ------ jwt_debug_script.sh | 230 --------- test_new.sh | 235 --------- test_training_service_token.sh | 235 --------- tests/test_data.py | 488 ------------------ .../test_onboarding_flow.sh | 0 6 files changed, 1337 deletions(-) delete mode 100755 check.sh delete mode 100755 jwt_debug_script.sh delete mode 100755 test_new.sh delete mode 100644 test_training_service_token.sh delete mode 100644 tests/test_data.py rename test_onboarding_flow.sh => tests/test_onboarding_flow.sh (100%) diff --git a/check.sh b/check.sh deleted file mode 100755 index f14121e0..00000000 --- a/check.sh +++ /dev/null @@ -1,149 +0,0 @@ -#!/bin/bash -# Environment Variable Diagnostic Script -# This script helps identify where environment variables are getting lost - -set -e - -echo "πŸ” Environment Variable Diagnostic Script" -echo "==========================================" - -# Check if .env file exists and contains JWT settings -echo "πŸ“‹ Step 1: Checking .env file..." -if [ -f ".env" ]; then - echo "βœ… .env file exists" - if grep -q "JWT_SECRET_KEY" .env; then - JWT_VALUE=$(grep "JWT_SECRET_KEY" .env | cut -d'=' -f2-) - echo "βœ… JWT_SECRET_KEY found in .env: ${JWT_VALUE:0:30}..." - else - echo "❌ JWT_SECRET_KEY not found in .env" - fi -else - echo "❌ .env file does not exist" -fi - -echo "" - -# Check docker-compose.yml configuration -echo "πŸ“‹ Step 2: Checking docker-compose.yml..." -if grep -A 20 "auth-service:" docker-compose.yml | grep -q "JWT_SECRET_KEY"; then - echo "βœ… auth-service has JWT_SECRET_KEY in docker-compose.yml" -else - echo "❌ auth-service missing JWT_SECRET_KEY in docker-compose.yml" -fi - -echo "" - -# Check if services are running -echo "πŸ“‹ Step 3: Checking running services..." -AUTH_RUNNING=$(docker-compose ps auth-service | grep -c "Up" || echo "0") -GATEWAY_RUNNING=$(docker-compose ps gateway | grep -c "Up" || echo "0") - -echo "Auth Service Running: $AUTH_RUNNING" -echo "Gateway Running: $GATEWAY_RUNNING" - -echo "" - -# Check environment at container startup -echo "πŸ“‹ Step 4: Checking container environment at startup..." -echo "Starting fresh auth-service container..." - -# Stop and start auth service -docker-compose stop auth-service -sleep 2 - -# Start auth service and immediately check environment -echo "Starting auth-service..." -docker-compose up -d auth-service - -# Wait a moment for startup -sleep 3 - -echo "Checking environment immediately after startup..." -STARTUP_ENV=$(docker-compose exec -T auth-service env | grep JWT_SECRET_KEY || echo "NOT_SET") -echo "Startup Environment: $STARTUP_ENV" - -# Wait a bit more and check again -sleep 5 -echo "Checking environment after 5 seconds..." -AFTER_STARTUP=$(docker-compose exec -T auth-service env | grep JWT_SECRET_KEY || echo "NOT_SET") -echo "After Startup: $AFTER_STARTUP" - -echo "" - -# Check if the application is overriding environment variables -echo "πŸ“‹ Step 5: Checking application configuration loading..." - -# Create a temporary script to check Python environment loading -cat > /tmp/check_env.py << 'EOF' -import os -import sys -sys.path.insert(0, '/app') - -print("=== Python Environment Check ===") -print(f"JWT_SECRET_KEY from os.getenv: {os.getenv('JWT_SECRET_KEY', 'NOT_SET')}") - -try: - from app.core.config import settings - print(f"JWT_SECRET_KEY from settings: {getattr(settings, 'JWT_SECRET_KEY', 'NOT_SET')}") - - # Check if settings inherits from base - try: - from shared.config.base import BaseServiceSettings - base_settings = BaseServiceSettings() - print(f"JWT_SECRET_KEY from base settings: {getattr(base_settings, 'JWT_SECRET_KEY', 'NOT_SET')}") - except Exception as e: - print(f"Error loading base settings: {e}") - -except Exception as e: - print(f"Error loading auth settings: {e}") - -print("=== Raw Environment Variables ===") -for key, value in sorted(os.environ.items()): - if 'JWT' in key or 'SECRET' in key: - print(f"{key}={value[:30]}..." if len(value) > 30 else f"{key}={value}") -EOF - -# Copy the script into the container and run it -docker cp /tmp/check_env.py "$(docker-compose ps -q auth-service):/tmp/check_env.py" -echo "Running Python environment check..." -docker-compose exec -T auth-service python /tmp/check_env.py - -echo "" - -# Check if there are any startup scripts or entrypoints modifying environment -echo "πŸ“‹ Step 6: Checking container startup process..." -echo "Container entrypoint:" -docker-compose exec -T auth-service cat /usr/local/bin/docker-entrypoint.sh 2>/dev/null || echo "No entrypoint script found" - -echo "" -echo "Docker image environment:" -docker-compose exec -T auth-service printenv | grep JWT || echo "No JWT variables in container environment" - -echo "" - -# Check application logs for any environment variable issues -echo "πŸ“‹ Step 7: Checking application logs for environment issues..." -echo "Recent auth-service logs:" -docker-compose logs --tail=20 auth-service | grep -i -E "(jwt|secret|env|config)" || echo "No relevant logs found" - -echo "" - -# Final diagnosis -echo "πŸ“‹ Step 8: Diagnosis Summary" -echo "==============================" - -if [ "$STARTUP_ENV" = "NOT_SET" ]; then - echo "❌ ISSUE: JWT_SECRET_KEY is not being passed to the container" - echo "πŸ”§ SOLUTION: Fix docker-compose.yml environment variables" -elif [ "$STARTUP_ENV" != "NOT_SET" ] && [ "$AFTER_STARTUP" = "NOT_SET" ]; then - echo "❌ ISSUE: JWT_SECRET_KEY is present at startup but disappears" - echo "πŸ”§ SOLUTION: Check application configuration loading" -else - echo "βœ… Environment variables appear to be stable" -fi - -echo "" -echo "🏁 Diagnostic complete!" - -# Cleanup -rm -f /tmp/check_env.py \ No newline at end of file diff --git a/jwt_debug_script.sh b/jwt_debug_script.sh deleted file mode 100755 index b0e66986..00000000 --- a/jwt_debug_script.sh +++ /dev/null @@ -1,230 +0,0 @@ -#!/bin/bash -# JWT Debug and Verification Script -# This script helps debug JWT token issues between gateway and auth service - -set -e - -# Configuration -API_BASE="http://localhost:8000" -AUTH_BASE="http://localhost:8001" -EMAIL="test@bakery.com" -PASSWORD="TestPassword123!" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -log_info() { - echo -e "${BLUE}ℹ️ $1${NC}" -} - -log_success() { - echo -e "${GREEN}βœ… $1${NC}" -} - -log_warning() { - echo -e "${YELLOW}⚠️ $1${NC}" -} - -log_error() { - echo -e "${RED}❌ $1${NC}" -} - -log_step() { - echo -e "${BLUE}πŸ”„ $1${NC}" -} - -echo "πŸ” JWT Token Debug and Verification Script" -echo "===========================================" - -# Step 1: Check JWT Configuration -log_step "Step 1: Checking JWT Configuration Consistency" - -log_info "Checking Gateway JWT Settings..." -GATEWAY_JWT_SECRET=$(docker-compose exec -T gateway env 2>/dev/null | grep JWT_SECRET_KEY || echo "NOT_SET") -GATEWAY_JWT_ALGO=$(docker-compose exec -T gateway env 2>/dev/null | grep JWT_ALGORITHM || echo "NOT_SET") - -log_info "Checking Auth Service JWT Settings..." -AUTH_JWT_SECRET=$(docker-compose exec -T auth-service env 2>/dev/null | grep JWT_SECRET_KEY || echo "NOT_SET") -AUTH_JWT_ALGO=$(docker-compose exec -T auth-service env 2>/dev/null | grep JWT_ALGORITHM || echo "NOT_SET") - -echo "Gateway JWT Secret: $GATEWAY_JWT_SECRET" -echo "Auth Service JWT Secret: $AUTH_JWT_SECRET" -echo "Gateway JWT Algorithm: $GATEWAY_JWT_ALGO" -echo "Auth Service JWT Algorithm: $AUTH_JWT_ALGO" - -if [ "$GATEWAY_JWT_SECRET" = "$AUTH_JWT_SECRET" ]; then - log_success "JWT Secret Keys match!" -else - log_error "JWT Secret Keys DO NOT match!" - log_warning "This is likely the cause of the authentication issue" -fi - -echo "" - -# Step 2: Test Direct Auth Service -log_step "Step 2: Testing Direct Auth Service" - -# Login directly to auth service -log_info "Logging in directly to auth service..." -AUTH_LOGIN_RESPONSE=$(curl -s -X POST "$AUTH_BASE/api/v1/auth/login" \ - -H "Content-Type: application/json" \ - -d "{ - \"email\": \"$EMAIL\", - \"password\": \"$PASSWORD\" - }") - -echo "Direct Auth Login Response:" -echo "$AUTH_LOGIN_RESPONSE" | jq '.' 2>/dev/null || echo "$AUTH_LOGIN_RESPONSE" - -# Extract token -DIRECT_TOKEN=$(echo "$AUTH_LOGIN_RESPONSE" | jq -r '.access_token' 2>/dev/null) - -if [ "$DIRECT_TOKEN" != "null" ] && [ "$DIRECT_TOKEN" != "" ]; then - log_success "Direct auth login successful!" - echo "Token: ${DIRECT_TOKEN:0:50}..." - - # Test direct auth verification - log_info "Testing direct auth token verification..." - AUTH_VERIFY_RESPONSE=$(curl -s -X POST "$AUTH_BASE/api/v1/auth/verify" \ - -H "Authorization: Bearer $DIRECT_TOKEN") - - echo "Direct Auth Verify Response:" - echo "$AUTH_VERIFY_RESPONSE" | jq '.' 2>/dev/null || echo "$AUTH_VERIFY_RESPONSE" - - # Test direct auth /users/me - log_info "Testing direct auth /users/me endpoint..." - AUTH_ME_RESPONSE=$(curl -s -X GET "$AUTH_BASE/api/v1/users/me" \ - -H "Authorization: Bearer $DIRECT_TOKEN") - - echo "Direct Auth /users/me Response:" - echo "$AUTH_ME_RESPONSE" | jq '.' 2>/dev/null || echo "$AUTH_ME_RESPONSE" - -else - log_error "Direct auth login failed!" - exit 1 -fi - -echo "" - -# Step 3: Test Gateway Login -log_step "Step 3: Testing Gateway Login" - -GATEWAY_LOGIN_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/login" \ - -H "Content-Type: application/json" \ - -d "{ - \"email\": \"$EMAIL\", - \"password\": \"$PASSWORD\" - }") - -echo "Gateway Login Response:" -echo "$GATEWAY_LOGIN_RESPONSE" | jq '.' 2>/dev/null || echo "$GATEWAY_LOGIN_RESPONSE" - -GATEWAY_TOKEN=$(echo "$GATEWAY_LOGIN_RESPONSE" | jq -r '.access_token' 2>/dev/null) - -if [ "$GATEWAY_TOKEN" != "null" ] && [ "$GATEWAY_TOKEN" != "" ]; then - log_success "Gateway login successful!" - echo "Token: ${GATEWAY_TOKEN:0:50}..." -else - log_error "Gateway login failed!" - exit 1 -fi - -echo "" - -# Step 4: Compare Tokens -log_step "Step 4: Comparing Tokens" - -if [ "$DIRECT_TOKEN" = "$GATEWAY_TOKEN" ]; then - log_success "Tokens are identical (expected)" -else - log_warning "Tokens are different (unexpected if same login)" -fi - -# Decode tokens for comparison -log_info "Decoding direct auth token payload..." -DIRECT_PAYLOAD=$(echo "$DIRECT_TOKEN" | cut -d'.' -f2) -# Add padding if needed -while [ $((${#DIRECT_PAYLOAD} % 4)) -ne 0 ]; do - DIRECT_PAYLOAD="${DIRECT_PAYLOAD}=" -done -echo "$DIRECT_PAYLOAD" | base64 -d 2>/dev/null | jq '.' || echo "Failed to decode" - -log_info "Decoding gateway token payload..." -GATEWAY_PAYLOAD=$(echo "$GATEWAY_TOKEN" | cut -d'.' -f2) -# Add padding if needed -while [ $((${#GATEWAY_PAYLOAD} % 4)) -ne 0 ]; do - GATEWAY_PAYLOAD="${GATEWAY_PAYLOAD}=" -done -echo "$GATEWAY_PAYLOAD" | base64 -d 2>/dev/null | jq '.' || echo "Failed to decode" - -echo "" - -# Step 5: Test Gateway Authentication -log_step "Step 5: Testing Gateway Authentication Middleware" - -# Test gateway token verification -log_info "Testing gateway token verification..." -GATEWAY_VERIFY_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/verify" \ - -H "Authorization: Bearer $GATEWAY_TOKEN") - -echo "Gateway Verify Response:" -echo "$GATEWAY_VERIFY_RESPONSE" | jq '.' 2>/dev/null || echo "$GATEWAY_VERIFY_RESPONSE" - -# Test gateway /users/me (this is where the issue occurs) -log_info "Testing gateway /users/me endpoint (THE FAILING ENDPOINT)..." -GATEWAY_ME_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" -X GET "$API_BASE/api/v1/users/me" \ - -H "Authorization: Bearer $GATEWAY_TOKEN") - -echo "Gateway /users/me Response:" -echo "$GATEWAY_ME_RESPONSE" - -# Check if successful -if echo "$GATEWAY_ME_RESPONSE" | grep -q "HTTP_CODE:200"; then - log_success "Gateway /users/me endpoint working!" -elif echo "$GATEWAY_ME_RESPONSE" | grep -q "HTTP_CODE:401"; then - log_error "Gateway /users/me endpoint returning 401 Unauthorized" - log_warning "This confirms the JWT middleware issue" -else - log_warning "Gateway /users/me endpoint returned unexpected response" -fi - -echo "" - -# Step 6: Test with verbose curl to see middleware behavior -log_step "Step 6: Verbose Gateway Request Analysis" - -log_info "Making verbose request to gateway /users/me..." -curl -v -X GET "$API_BASE/api/v1/users/me" \ - -H "Authorization: Bearer $GATEWAY_TOKEN" 2>&1 | head -20 - -echo "" - -# Step 7: Recommendations -log_step "Step 7: Recommendations" - -if [ "$GATEWAY_JWT_SECRET" != "$AUTH_JWT_SECRET" ]; then - log_error "CRITICAL: JWT secrets don't match between services" - echo "Fix: Update your .env file and restart services:" - echo "export JWT_SECRET_KEY='your-super-secret-jwt-key-change-in-production-min-32-characters-long'" - echo "docker-compose down && docker-compose up -d" -elif echo "$GATEWAY_ME_RESPONSE" | grep -q "HTTP_CODE:401"; then - log_warning "JWT secrets match but gateway middleware is still failing" - echo "Possible causes:" - echo "1. Gateway middleware token validation logic issue" - echo "2. Token payload structure mismatch" - echo "3. Gateway not using updated shared JWT handler" - echo "" - echo "Recommended fixes:" - echo "1. Apply the fixed gateway auth middleware" - echo "2. Apply the fixed shared JWT handler" - echo "3. Restart gateway service: docker-compose restart gateway" -else - log_success "All tests passed! JWT authentication is working correctly." -fi - -echo "" -echo "🏁 Debug script completed!" \ No newline at end of file diff --git a/test_new.sh b/test_new.sh deleted file mode 100755 index a164af04..00000000 --- a/test_new.sh +++ /dev/null @@ -1,235 +0,0 @@ -#!/bin/bash -# Configuration -API_BASE="http://localhost:8000" -EMAIL="test4555@bakery.com" -PASSWORD="TestPassword123!" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo "πŸ§ͺ Testing New Tenant-Scoped API Architecture" -echo "==============================================" - -# Function to check response status -check_response() { - local response="$1" - local step_name="$2" - - if echo "$response" | grep -q '"detail"' && echo "$response" | grep -q '"error"'; then - echo -e "${RED}❌ $step_name FAILED${NC}" - echo "Error details: $response" - return 1 - elif echo "$response" | grep -q '500 Internal Server Error'; then - echo -e "${RED}❌ $step_name FAILED - Server Error${NC}" - echo "Response: $response" - return 1 - else - echo -e "${GREEN}βœ… $step_name PASSED${NC}" - return 0 - fi -} - -# Step 1: Health Check -echo "1. Testing Gateway Health..." -HEALTH_RESPONSE=$(curl -s -X GET "$API_BASE/health") -echo "Health Response: $HEALTH_RESPONSE" -check_response "$HEALTH_RESPONSE" "Health Check" - -# Step 2: Register User (or skip if already exists) -echo -e "\n2. Registering User..." -REGISTER_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/register" \ - -H "Content-Type: application/json" \ - -d "{ - \"email\": \"$EMAIL\", - \"password\": \"$PASSWORD\", - \"full_name\": \"Test User\" - }") - -echo "Registration Response: $REGISTER_RESPONSE" - -# Check if user already exists -if echo "$REGISTER_RESPONSE" | grep -q "already exists"; then - echo -e "${YELLOW}⚠️ User already exists, proceeding to login${NC}" -elif check_response "$REGISTER_RESPONSE" "User Registration"; then - echo "New user registered successfully" -fi - -# Step 3: Login -echo -e "\n3. Logging in..." -LOGIN_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/login" \ - -H "Content-Type: application/json" \ - -d "{ - \"email\": \"$EMAIL\", - \"password\": \"$PASSWORD\" - }") - -echo "Login Response: $LOGIN_RESPONSE" - -# Extract token with better parsing -ACCESS_TOKEN=$(echo "$LOGIN_RESPONSE" | python3 -c "import json, sys; data=json.load(sys.stdin); print(data.get('access_token', ''))" 2>/dev/null) - -if [ -z "$ACCESS_TOKEN" ]; then - # Fallback to grep method - ACCESS_TOKEN=$(echo "$LOGIN_RESPONSE" | grep -o '"access_token":"[^"]*"' | cut -d'"' -f4) -fi - -if [ -z "$ACCESS_TOKEN" ]; then - echo -e "${RED}❌ Failed to extract access token${NC}" - echo "Login response was: $LOGIN_RESPONSE" - exit 1 -fi - -echo "Access Token: ${ACCESS_TOKEN:0:50}..." -check_response "$LOGIN_RESPONSE" "User Login" - -# Step 3.5: Verify Token Works -echo -e "\n3.5. Verifying Access Token..." -TOKEN_TEST_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/verify" \ - -H "Authorization: Bearer $ACCESS_TOKEN") - -echo "Token Verification Response: $TOKEN_TEST_RESPONSE" - -if check_response "$TOKEN_TEST_RESPONSE" "Token Verification"; then - if echo "$TOKEN_TEST_RESPONSE" | grep -q '"user_id"'; then - echo -e "${GREEN}βœ… Token contains user_id${NC}" - fi -else - echo -e "${RED}❌ Token verification failed, but continuing...${NC}" -fi - -# Step 3.6: Test Protected Endpoint (with error handling) -echo -e "\n3.6. Testing Protected Endpoint (User Profile)..." -USER_PROFILE_RESPONSE=$(curl -s -X GET "$API_BASE/api/v1/users/me" \ - -H "Authorization: Bearer $ACCESS_TOKEN") - -echo "User Profile Response: $USER_PROFILE_RESPONSE" - -# This might fail due to the datetime serialization issue we identified -if echo "$USER_PROFILE_RESPONSE" | grep -q '"email"'; then - check_response "$USER_PROFILE_RESPONSE" "Protected Endpoint Access" -elif echo "$USER_PROFILE_RESPONSE" | grep -q "string_type"; then - echo -e "${YELLOW}⚠️ Known datetime serialization issue detected${NC}" - echo -e "${YELLOW} This is the Pydantic validation error we identified${NC}" - echo -e "${YELLOW} Continuing with tenant registration...${NC}" -else - echo -e "${RED}❌ Protected endpoint access failed for unknown reason${NC}" - echo "Response was: $USER_PROFILE_RESPONSE" -fi - -# Step 4: Register Bakery -echo -e "\n4. Registering Bakery..." -echo "Using Token: ${ACCESS_TOKEN:0:50}..." -echo "Making request to: $API_BASE/api/v1/tenants/register" - -BAKERY_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X POST "$API_BASE/api/v1/tenants/register" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -d '{ - "name": "Test Bakery API", - "business_type": "bakery", - "address": "Calle Test 123", - "city": "Madrid", - "postal_code": "28001", - "phone": "+34600123456" - }') - -# Extract HTTP code and response -HTTP_CODE=$(echo "$BAKERY_RESPONSE" | grep "HTTP_CODE:" | cut -d: -f2) -BAKERY_RESPONSE=$(echo "$BAKERY_RESPONSE" | sed '/HTTP_CODE:/d') - -echo "HTTP Status Code: $HTTP_CODE" -echo "Bakery Response: $BAKERY_RESPONSE" - -# Extract tenant ID with better parsing -TENANT_ID=$(echo "$BAKERY_RESPONSE" | python3 -c "import json, sys; data=json.load(sys.stdin); print(data.get('id', ''))" 2>/dev/null) - -if [ -z "$TENANT_ID" ]; then - # Fallback to grep method - TENANT_ID=$(echo "$BAKERY_RESPONSE" | grep -o '"id":"[^"]*"' | cut -d'"' -f4) -fi - -if [ -n "$TENANT_ID" ]; then - echo "Tenant ID: $TENANT_ID" - check_response "$BAKERY_RESPONSE" "Bakery Registration" -else - echo -e "${RED}❌ Failed to extract tenant ID${NC}" - echo "Cannot proceed with tenant-scoped tests" - exit 1 -fi - -# Step 5: Test Tenant-Scoped Endpoint -if [ -n "$TENANT_ID" ]; then - echo -e "\n5. Testing Tenant Sales Endpoint..." - SALES_RESPONSE=$(curl -s -X GET "$API_BASE/api/v1/tenants/$TENANT_ID/sales" \ - -H "Authorization: Bearer $ACCESS_TOKEN") - - echo "Sales Response: $SALES_RESPONSE" - check_response "$SALES_RESPONSE" "Tenant Sales Endpoint" - - # Step 6: Test Import Validation - echo -e "\n6. Testing Import Validation..." - VALIDATION_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/tenants/$TENANT_ID/sales/import/validate" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -d '{ - "data": "date,product,quantity,revenue\n2024-01-01,bread,10,25.50", - "data_format": "csv" - }') - - echo "Validation Response: $VALIDATION_RESPONSE" - check_response "$VALIDATION_RESPONSE" "Import Validation" - - # Step 6.5: Import Sample Sales Data - echo -e "\n6.5. Importing Sample Sales Data..." - IMPORT_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/tenants/$TENANT_ID/sales" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -d '{ - "product_name": "Pan Integral", - "quantity_sold": 25, - "revenue": 37.50, - "date": "2024-01-15T10:00:00Z" - }') - - echo "Import Response: $IMPORT_RESPONSE" - check_response "$IMPORT_RESPONSE" "Sales Data Import" - - # Now test sales endpoint again - should have data! - echo -e "\n6.6. Testing Sales Endpoint Again (Should Have Data)..." - SALES_RESPONSE_WITH_DATA=$(curl -s -X GET "$API_BASE/api/v1/tenants/$TENANT_ID/sales" \ - -H "Authorization: Bearer $ACCESS_TOKEN") - - echo "Sales Response with Data: $SALES_RESPONSE_WITH_DATA" - check_response "$SALES_RESPONSE_WITH_DATA" "Tenant Sales Endpoint with Data" - - # Check if we actually got data - if echo "$SALES_RESPONSE_WITH_DATA" | grep -q "Pan Integral"; then - echo -e "${GREEN}βœ… Successfully retrieved sales data!${NC}" - else - echo -e "${YELLOW}⚠️ No sales data returned (might need different import endpoint)${NC}" - fi -fi - -# Step 7: Additional Debug Information -echo -e "\n7. Debug Information..." -echo "Services Status:" -echo "- Auth Service: $(curl -s http://localhost:8001/health || echo 'Not responding')" -echo "- Tenant Service: $(curl -s http://localhost:8002/health || echo 'Not responding')" -echo "- Data Service: $(curl -s http://localhost:8003/health || echo 'Not responding')" - -echo -e "\n${GREEN}βœ… API Test Complete!${NC}" -echo "Summary:" -echo "- Gateway Health: βœ“" -echo "- User Registration: βœ“" -echo "- User Login: βœ“" -echo "- Token Verification: βœ“" -echo -e "- User Profile: ${YELLOW}⚠️ (Known datetime issue)${NC}" -echo "- Bakery Registration: βœ“" -echo "- Tenant-scoped endpoints: βœ“" - -echo -e "\n${YELLOW}Note: If you see the datetime serialization error in step 3.6," -echo -e "that's the Pydantic validation issue we identified earlier.${NC}" -echo -e "${YELLOW}Fix it by updating the UserResponse schema as discussed.${NC}" \ No newline at end of file diff --git a/test_training_service_token.sh b/test_training_service_token.sh deleted file mode 100644 index 326167bb..00000000 --- a/test_training_service_token.sh +++ /dev/null @@ -1,235 +0,0 @@ -#!/bin/bash -# ================================================================= -# Test Training Service Token Generation and Gateway Validation -# ================================================================= - -set -e - -# Configuration -API_BASE="http://localhost:8000" -AUTH_BASE="http://localhost:8001" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -log_info() { echo -e "${BLUE}ℹ️ $1${NC}"; } -log_success() { echo -e "${GREEN}βœ… $1${NC}"; } -log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; } -log_error() { echo -e "${RED}❌ $1${NC}"; } -log_step() { echo -e "${BLUE}πŸ”„ $1${NC}"; } - -echo "πŸ§ͺ Testing Training Service Token with Gateway Middleware" -echo "========================================================" - -# Step 1: Create a service token like training service would -log_step "Step 1: Creating Service Token (Training Service Style)" - -# Use Python to create the same token the training service would create -SERVICE_TOKEN=$(python3 -c " -import sys -import time -import os -sys.path.append('.') - -# Import your shared JWT handler -from shared.auth.jwt_handler import JWTHandler - -# Use same secret as gateway/auth service -JWT_SECRET = os.getenv('JWT_SECRET_KEY', 'your-super-secret-jwt-key-change-in-production-min-32-characters-long') - -# Create JWT handler -jwt_handler = JWTHandler(JWT_SECRET) - -# Create service payload (same as training service would) -service_payload = { - 'sub': 'training-service', - 'user_id': 'training-service', - 'email': 'training-service@internal', - 'service': 'training', - 'type': 'access', # Important: must be 'access' type - 'exp': int(time.time()) + 3600, # 1 hour - 'iat': int(time.time()), - 'iss': 'training-service', - 'full_name': 'Training Service', - 'is_verified': True, - 'is_active': True -} - -# Create token -token = jwt_handler.create_access_token_from_payload(service_payload) -print(token) -") - -if [ -z "$SERVICE_TOKEN" ]; then - log_error "Failed to create service token" - exit 1 -fi - -log_success "Service token created successfully" -echo "Token: ${SERVICE_TOKEN:0:50}..." - -echo "" - -# Step 2: Decode and inspect the token -log_step "Step 2: Decoding Service Token Payload" - -# Decode the payload to see what's inside -PAYLOAD=$(echo "$SERVICE_TOKEN" | cut -d'.' -f2) -# Add padding if needed -while [ $((${#PAYLOAD} % 4)) -ne 0 ]; do - PAYLOAD="${PAYLOAD}=" -done - -echo "Service Token Payload:" -echo "$PAYLOAD" | base64 -d 2>/dev/null | jq '.' || echo "Failed to decode" - -echo "" - -# Step 3: Test token with gateway middleware -log_step "Step 3: Testing Service Token with Gateway Middleware" - -# Test a tenant-scoped endpoint that training service would call -TENANT_ID="b2a268a0-904f-4182-8f81-ec25d0e6def7" # From your test - -log_info "Testing GET /api/v1/tenants/$TENANT_ID/sales with service token..." - -GATEWAY_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" -X GET \ - "$API_BASE/api/v1/tenants/$TENANT_ID/sales" \ - -H "Authorization: Bearer $SERVICE_TOKEN" \ - -H "X-Tenant-ID: $TENANT_ID" \ - -H "X-Service: training-service" \ - -H "Content-Type: application/json") - -echo "Gateway Response:" -echo "$GATEWAY_RESPONSE" - -# Check the result -if echo "$GATEWAY_RESPONSE" | grep -q "HTTP_CODE:200"; then - log_success "βœ… Service token ACCEPTED by gateway middleware!" - log_success "Training service authentication would work!" -elif echo "$GATEWAY_RESPONSE" | grep -q "HTTP_CODE:401"; then - log_error "❌ Service token REJECTED by gateway middleware (401 Unauthorized)" - log_warning "This explains why training service fails" -elif echo "$GATEWAY_RESPONSE" | grep -q "HTTP_CODE:404"; then - log_warning "⚠️ Endpoint not found (404) - but token was accepted by middleware" - log_success "Authentication passed, routing issue" -else - log_warning "Unexpected HTTP response code" -fi - -echo "" - -# Step 4: Test with a known working user token for comparison -log_step "Step 4: Comparison Test with User Token" - -# Get a real user token from the onboarding test -USER_TOKEN="" -if [ -f "/tmp/test_user_token.txt" ]; then - USER_TOKEN=$(cat /tmp/test_user_token.txt) -fi - -if [ -z "$USER_TOKEN" ]; then - log_info "Creating a user token for comparison..." - - # Quick user login to get a token - USER_LOGIN_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/login" \ - -H "Content-Type: application/json" \ - -d '{ - "email": "onboarding.test.1753606890@bakery.com", - "password": "TestPassword123!" - }') - - USER_TOKEN=$(echo "$USER_LOGIN_RESPONSE" | jq -r '.access_token' 2>/dev/null) -fi - -if [ -n "$USER_TOKEN" ] && [ "$USER_TOKEN" != "null" ]; then - log_info "Testing same endpoint with user token..." - - USER_RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}\n" -X GET \ - "$API_BASE/api/v1/tenants/$TENANT_ID/sales" \ - -H "Authorization: Bearer $USER_TOKEN" \ - -H "X-Tenant-ID: $TENANT_ID") - - if echo "$USER_RESPONSE" | grep -q "HTTP_CODE:200"; then - log_success "User token works - gateway middleware is functioning" - elif echo "$USER_RESPONSE" | grep -q "HTTP_CODE:401"; then - log_warning "User token also fails - gateway middleware issue" - else - log_info "User token response: $(echo "$USER_RESPONSE" | tail -1)" - fi -else - log_warning "Could not get user token for comparison" -fi - -echo "" - -# Step 5: Test gateway auth verification endpoint -log_step "Step 5: Testing Token with Gateway Auth Verification" - -log_info "Testing service token with /api/v1/auth/verify..." -VERIFY_RESPONSE=$(curl -s -X POST "$API_BASE/api/v1/auth/verify" \ - -H "Authorization: Bearer $SERVICE_TOKEN") - -echo "Verification Response:" -echo "$VERIFY_RESPONSE" | jq '.' 2>/dev/null || echo "$VERIFY_RESPONSE" - -if echo "$VERIFY_RESPONSE" | jq -e '.valid' > /dev/null 2>&1; then - if [ "$(echo "$VERIFY_RESPONSE" | jq -r '.valid')" = "true" ]; then - log_success "Service token is VALID according to auth service" - else - log_error "Service token is INVALID according to auth service" - fi -else - log_warning "Verification response doesn't contain 'valid' field" -fi - -echo "" - -# Step 6: Diagnosis and recommendations -log_step "Step 6: Diagnosis and Recommendations" - -# Check JWT secrets match -log_info "Checking JWT secret consistency..." -if docker-compose exec -T gateway env 2>/dev/null | grep -q JWT_SECRET_KEY; then - log_success "Gateway has JWT_SECRET_KEY configured" -else - log_error "Gateway missing JWT_SECRET_KEY configuration" -fi - -if docker-compose exec -T auth-service env 2>/dev/null | grep -q JWT_SECRET_KEY; then - log_success "Auth service has JWT_SECRET_KEY configured" -else - log_error "Auth service missing JWT_SECRET_KEY configuration" -fi - -echo "" -echo "🏁 Test Summary:" -echo "==================" - -if echo "$GATEWAY_RESPONSE" | grep -q "HTTP_CODE:200"; then - echo "βœ… Service token authentication: WORKING" - echo "βœ… Training service should be able to fetch sales data" - echo "" - echo "🎯 Next Steps:" - echo "1. Update training service to use gateway URL: http://gateway:8000" - echo "2. Ensure training service creates tokens with same payload structure" - echo "3. Test with: docker-compose restart training-service" -elif echo "$GATEWAY_RESPONSE" | grep -q "HTTP_CODE:401"; then - echo "❌ Service token authentication: FAILING" - echo "❌ This explains why training service gets 401 errors" - echo "" - echo "πŸ”§ Fixes needed:" - echo "1. Check JWT_SECRET_KEY matches across services" - echo "2. Update gateway middleware to accept service tokens" - echo "3. Verify token payload structure matches gateway expectations" -else - echo "⚠️ Inconclusive test results" - echo "Check the response details above" -fi - -echo "" -echo "πŸ§ͺ Test completed!" \ No newline at end of file diff --git a/tests/test_data.py b/tests/test_data.py deleted file mode 100644 index f71faedb..00000000 --- a/tests/test_data.py +++ /dev/null @@ -1,488 +0,0 @@ -# ================================================================ -# validate_data_service_fixed.py - FIXED VERSION -# ================================================================ - -import asyncio -import httpx -import json -import sys -import traceback -from datetime import datetime -from typing import Optional, Dict, Any -import uuid - -# ConfiguraciΓ³n -AUTH_URL = "http://localhost:8001" -DATA_URL = "http://localhost:8004" -GATEWAY_URL = "http://localhost:8000" - -class DataServiceValidator: - """Validador completo para el Data Service - FIXED VERSION""" - - def __init__(self, use_gateway: bool = False): - self.auth_token: Optional[str] = None - self.use_gateway = use_gateway - self.base_url = GATEWAY_URL if use_gateway else DATA_URL - self.auth_base_url = GATEWAY_URL if use_gateway else AUTH_URL - self.user_data = None - - async def test_service_health(self) -> bool: - """Verificar que los servicios estΓ©n funcionando""" - print("πŸ” Checking service health...") - - try: - async with httpx.AsyncClient(timeout=10.0) as client: - # Test auth service - auth_response = await client.get(f"{AUTH_URL}/health") - if auth_response.status_code == 200: - print("βœ… Auth service is healthy") - else: - print(f"❌ Auth service unhealthy: {auth_response.status_code}") - return False - - # Test data service - data_response = await client.get(f"{DATA_URL}/health") - if data_response.status_code == 200: - print("βœ… Data service is healthy") - else: - print(f"❌ Data service unhealthy: {data_response.status_code}") - return False - - # Test gateway if using it - if self.use_gateway: - gateway_response = await client.get(f"{GATEWAY_URL}/health") - if gateway_response.status_code == 200: - print("βœ… Gateway is healthy") - else: - print(f"❌ Gateway unhealthy: {gateway_response.status_code}") - return False - - return True - - except httpx.ConnectError as e: - print(f"❌ Connection error: {e}") - print("πŸ’‘ Make sure services are running with: docker-compose up -d") - return False - except Exception as e: - print(f"❌ Health check failed: {e}") - return False - - async def authenticate(self) -> bool: - """Autenticar y obtener token""" - print("πŸ” Authenticating...") - - try: - async with httpx.AsyncClient(timeout=15.0) as client: - # Generar tenant_id ΓΊnico para esta prueba - tenant_id = str(uuid.uuid4()) - - # Datos de usuario de prueba con tenant_id - self.user_data = { - "email": "test@bakery.es", - "password": "TestPass123", - "full_name": "Test User", - "language": "es", - "tenant_id": tenant_id # βœ… AΓ‘ADIR TENANT_ID - } - - # Intentar registrar usuario (puede fallar si ya existe) - register_endpoint = f"{self.auth_base_url}/api/v1/auth/register" - register_response = await client.post(register_endpoint, json=self.user_data) - - if register_response.status_code == 200: - print("βœ… User registered successfully") - elif register_response.status_code == 409: - print("ℹ️ User already exists, proceeding with login") - elif register_response.status_code == 400: - print("⚠️ Registration validation error, trying login") - else: - print(f"⚠️ Registration response: {register_response.status_code}") - print(f"Response body: {register_response.text}") - - # Login con credenciales - login_data = { - "email": self.user_data["email"], - "password": self.user_data["password"] - } - - login_endpoint = f"{self.auth_base_url}/api/v1/auth/login" - login_response = await client.post(login_endpoint, json=login_data) - - if login_response.status_code == 200: - response_data = login_response.json() - self.auth_token = response_data["access_token"] - print("βœ… Authentication successful") - - # Verificar que el token tenga los campos necesarios - verify_endpoint = f"{self.auth_base_url}/api/v1/auth/verify" - verify_response = await client.post( - verify_endpoint, - headers={"Authorization": f"Bearer {self.auth_token}"} - ) - - if verify_response.status_code == 200: - token_data = verify_response.json() - print(f"πŸ” Token contains: {list(token_data.keys())}") - - # Verificar campos necesarios - required_fields = ["user_id", "email", "tenant_id"] - missing_fields = [field for field in required_fields if field not in token_data] - - if missing_fields: - print(f"⚠️ Token missing fields: {missing_fields}") - else: - print("βœ… Token has all required fields") - - return True - else: - print(f"⚠️ Token verification failed: {verify_response.status_code}") - return True # Continuar de todas formas - else: - print(f"❌ Login failed: {login_response.status_code}") - print(f"Response: {login_response.text}") - return False - - except Exception as e: - print(f"❌ Authentication failed: {e}") - traceback.print_exc() - return False - - def get_headers(self) -> Dict[str, str]: - """Obtener headers con token de autenticaciΓ³n""" - if not self.auth_token: - raise ValueError("No authentication token available") - return {"Authorization": f"Bearer {self.auth_token}"} - - async def test_weather_endpoints(self) -> bool: - """Probar endpoints de clima""" - print("🌀️ Testing weather endpoints...") - - try: - headers = self.get_headers() - madrid_coords = {"latitude": 40.4168, "longitude": -3.7038} - - async with httpx.AsyncClient(timeout=20.0) as client: - # Current weather - FIXED URL - if self.use_gateway: - current_endpoint = f"{self.base_url}/api/v1/data/weather/current" - else: - current_endpoint = f"{self.base_url}/api/v1/weather/current" - - print(f"πŸ”— Requesting: {current_endpoint}") - current_response = await client.get( - current_endpoint, - params=madrid_coords, - headers=headers - ) - - if current_response.status_code == 200: - weather = current_response.json() - print(f"βœ… Current weather: {weather.get('temperature')}Β°C, {weather.get('description')}") - else: - print(f"❌ Current weather failed: {current_response.status_code}") - print(f"Response: {current_response.text}") - - # Si falla, intentar con mock data - if current_response.status_code == 503: - print("ℹ️ External API unavailable, this is expected in test environment") - return True - - return False - - # Weather forecast - if self.use_gateway: - forecast_endpoint = f"{self.base_url}/api/v1/data/weather/forecast" - else: - forecast_endpoint = f"{self.base_url}/api/v1/weather/forecast" - - forecast_response = await client.get( - forecast_endpoint, - params={**madrid_coords, "days": 3}, - headers=headers - ) - - if forecast_response.status_code == 200: - forecast = forecast_response.json() - print(f"βœ… Weather forecast: {len(forecast)} days") - return True - elif forecast_response.status_code == 503: - print("ℹ️ Forecast API unavailable, this is expected in test environment") - return True - else: - print(f"❌ Weather forecast failed: {forecast_response.status_code}") - return False - - except Exception as e: - print(f"❌ Weather tests failed: {e}") - traceback.print_exc() - return False - - async def test_traffic_endpoints(self) -> bool: - """Probar endpoints de trΓ‘fico""" - print("🚦 Testing traffic endpoints...") - - try: - headers = self.get_headers() - madrid_coords = {"latitude": 40.4168, "longitude": -3.7038} - - async with httpx.AsyncClient(timeout=20.0) as client: - # Current traffic - FIXED URL - if self.use_gateway: - current_endpoint = f"{self.base_url}/api/v1/data/traffic/current" - else: - current_endpoint = f"{self.base_url}/api/v1/traffic/current" - - print(f"πŸ”— Requesting: {current_endpoint}") - current_response = await client.get( - current_endpoint, - params=madrid_coords, - headers=headers - ) - - if current_response.status_code == 200: - traffic = current_response.json() - print(f"βœ… Current traffic: {traffic.get('traffic_volume')} vehicles, {traffic.get('congestion_level')} congestion") - return True - elif current_response.status_code == 503: - print("ℹ️ Traffic API unavailable, this is expected in test environment") - return True - else: - print(f"❌ Current traffic failed: {current_response.status_code}") - print(f"Response: {current_response.text}") - return False - - except Exception as e: - print(f"❌ Traffic tests failed: {e}") - traceback.print_exc() - return False - - async def test_sales_endpoints(self) -> bool: - """Probar endpoints de ventas""" - print("πŸ“Š Testing sales endpoints...") - - try: - headers = self.get_headers() - - # Usar tenant_id del usuario autenticado - tenant_id = self.user_data.get("tenant_id", str(uuid.uuid4())) - - # Datos de prueba - sales_data = { - "tenant_id": tenant_id, - "date": datetime.now().isoformat(), - "product_name": "Pan Integral Test", - "quantity_sold": 25, - "revenue": 37.50, - "location_id": "madrid_centro", - "source": "test" - } - - async with httpx.AsyncClient(timeout=20.0) as client: - # Create sales record - FIXED URL - if self.use_gateway: - create_endpoint = f"{self.base_url}/api/v1/data/sales/" - else: - create_endpoint = f"{self.base_url}/api/v1/sales/" - - print(f"πŸ”— Requesting: {create_endpoint}") - create_response = await client.post( - create_endpoint, - json=sales_data, - headers=headers - ) - - if create_response.status_code == 200: - record = create_response.json() - print(f"βœ… Sales record created: ID {record.get('id')}") - else: - print(f"❌ Sales creation failed: {create_response.status_code}") - print(f"Response: {create_response.text}") - return False - - # Test import template - if self.use_gateway: - template_endpoint = f"{self.base_url}/api/v1/data/sales/import/template/csv" - else: - template_endpoint = f"{self.base_url}/api/v1/sales/import/template/csv" - - template_response = await client.get( - template_endpoint, - headers=headers - ) - - if template_response.status_code == 200: - print("βœ… Import template generated successfully") - return True - else: - print(f"❌ Template generation failed: {template_response.status_code}") - print(f"Response: {template_response.text}") - return False - - except Exception as e: - print(f"❌ Sales tests failed: {e}") - traceback.print_exc() - return False - - async def test_import_functionality(self) -> bool: - """Probar funcionalidad de importaciΓ³n""" - print("πŸ“„ Testing import functionality...") - - try: - headers = self.get_headers() - - # Usar tenant_id del usuario autenticado - tenant_id = self.user_data.get("tenant_id", str(uuid.uuid4())) - - # Crear CSV de prueba - csv_content = """fecha,producto,cantidad,ingresos -15/01/2024,Pan Integral,25,37.50 -15/01/2024,Croissant,15,22.50 -15/01/2024,CafΓ© con Leche,10,20.00""" - - # Test CSV import - import_data = { - "tenant_id": tenant_id, - "data_format": "csv", - "data": csv_content - } - - async with httpx.AsyncClient(timeout=30.0) as client: - if self.use_gateway: - import_endpoint = f"{self.base_url}/api/v1/data/sales/import/json" - else: - import_endpoint = f"{self.base_url}/api/v1/sales/import/json" - - print(f"πŸ”— Requesting: {import_endpoint}") - import_response = await client.post( - import_endpoint, - json=import_data, - headers=headers - ) - - if import_response.status_code == 200: - result = import_response.json() - if result.get("success"): - print(f"βœ… CSV import successful: {result.get('records_created')} records created") - return True - else: - print(f"❌ CSV import failed: {result.get('error')}") - return False - elif import_response.status_code == 422: - print("ℹ️ Import validation error (expected in test environment)") - return True - else: - print(f"❌ Import request failed: {import_response.status_code}") - print(f"Response: {import_response.text}") - return False - - except Exception as e: - print(f"❌ Import tests failed: {e}") - traceback.print_exc() - return False - -async def main(): - """FunciΓ³n principal de validaciΓ³n""" - print("πŸš€ Starting Data Service Validation - FIXED VERSION") - print("=" * 60) - - # Preguntar si usar gateway - use_gateway_input = input("Use API Gateway? (y/N): ").lower() - use_gateway = use_gateway_input == 'y' - - if use_gateway: - print("πŸ“‘ Testing via API Gateway") - else: - print("πŸ”— Testing direct service connections") - - validator = DataServiceValidator(use_gateway=use_gateway) - - try: - # 1. Health checks - print("\n" + "="*20 + " HEALTH CHECKS " + "="*20) - if not await validator.test_service_health(): - print("\n❌ Health checks failed. Ensure services are running.") - return False - - # 2. Authentication - print("\n" + "="*20 + " AUTHENTICATION " + "="*20) - if not await validator.authenticate(): - print("\n❌ Authentication failed.") - return False - - # 3. Weather tests - print("\n" + "="*20 + " WEATHER TESTS " + "="*20) - if not await validator.test_weather_endpoints(): - print("\n❌ Weather endpoint tests failed.") - return False - - # 4. Traffic tests - print("\n" + "="*20 + " TRAFFIC TESTS " + "="*20) - if not await validator.test_traffic_endpoints(): - print("\n❌ Traffic endpoint tests failed.") - return False - - # 5. Sales tests - print("\n" + "="*20 + " SALES TESTS " + "="*20) - if not await validator.test_sales_endpoints(): - print("\n❌ Sales endpoint tests failed.") - return False - - # 6. Import tests - print("\n" + "="*20 + " IMPORT TESTS " + "="*20) - if not await validator.test_import_functionality(): - print("\n❌ Import functionality tests failed.") - return False - - print("\n" + "=" * 60) - print("πŸŽ‰ ALL TESTS PASSED! Data Service is working correctly!") - print("=" * 60) - return True - - except KeyboardInterrupt: - print("\n⚠️ Tests interrupted by user") - return False - except Exception as e: - print(f"\n❌ Unexpected error: {e}") - print("Traceback:") - traceback.print_exc() - return False - -def check_dependencies(): - """Verificar que las dependencias estΓ©n instaladas""" - try: - import httpx - print("βœ… httpx is available") - except ImportError: - print("❌ httpx not found. Install with: pip install httpx") - return False - - return True - -if __name__ == "__main__": - print("πŸ”§ Checking dependencies...") - - if not check_dependencies(): - print("\nπŸ’‘ Install dependencies with:") - print("pip install httpx") - sys.exit(1) - - print("βœ… All dependencies available") - print() - - # Ejecutar validaciΓ³n - success = asyncio.run(main()) - - if success: - print("\n🎯 Next steps:") - print("1. Check logs: docker-compose logs -f data-service") - print("2. Connect to DB: docker-compose exec data-db psql -U data_user -d data_db") - print("3. Test with real data imports") - print("4. Check monitoring: http://localhost:3002") - sys.exit(0) - else: - print("\nπŸ”§ Troubleshooting:") - print("1. Check services: docker-compose ps") - print("2. Restart services: docker-compose restart") - print("3. Check logs: docker-compose logs data-service") - print("4. Check gateway logs: docker-compose logs gateway") - sys.exit(1) \ No newline at end of file diff --git a/test_onboarding_flow.sh b/tests/test_onboarding_flow.sh similarity index 100% rename from test_onboarding_flow.sh rename to tests/test_onboarding_flow.sh