- Updated database configuration to switch from SQLite to PostgreSQL, including changes to alembic.ini, Docker Compose, and environment settings. - Refactored application code to utilize PostgreSQL database adapters, ensuring compatibility with the new database structure. - Enhanced API routes and data handling to support the new database, including adjustments in data models and query logic. - Introduced new job processing mechanisms for full synchronization of AMO CRM entities, leveraging FastStream for background tasks. - Improved logging and error handling across the application to facilitate better monitoring and debugging. - Removed obsolete SQLite adapter files and migrations, streamlining the project structure for PostgreSQL integration.
322 lines
9.5 KiB
Python
322 lines
9.5 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
Manual API Test Script for AMO CRM Service
|
|
|
|
This script tests the API endpoints without requiring Redis/broker.
|
|
It provides a quick way to verify the service is working.
|
|
"""
|
|
|
|
import requests
|
|
import json
|
|
from datetime import datetime
|
|
from typing import Dict, Any
|
|
|
|
|
|
BASE_URL = "http://localhost:8000"
|
|
API_BASE = f"{BASE_URL}/api/v1"
|
|
|
|
|
|
def print_section(title: str):
|
|
"""Print a formatted section header."""
|
|
print(f"\n{'='*60}")
|
|
print(f" {title}")
|
|
print(f"{'='*60}\n")
|
|
|
|
|
|
def print_result(test_name: str, success: bool, details: str = ""):
|
|
"""Print test result."""
|
|
status = "✅ PASS" if success else "❌ FAIL"
|
|
print(f"{status} - {test_name}")
|
|
if details:
|
|
print(f" {details}")
|
|
|
|
|
|
def test_health() -> bool:
|
|
"""Test health check endpoint."""
|
|
try:
|
|
response = requests.get(f"{BASE_URL}/health", timeout=5)
|
|
return response.status_code == 200 and response.json().get("status") == "healthy"
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def test_root() -> bool:
|
|
"""Test root endpoint."""
|
|
try:
|
|
response = requests.get(BASE_URL, timeout=5)
|
|
data = response.json()
|
|
return (
|
|
response.status_code == 200
|
|
and "AMO CRM" in data.get("message", "")
|
|
)
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def test_list_entities() -> bool:
|
|
"""Test list entities endpoint."""
|
|
try:
|
|
response = requests.get(f"{API_BASE}/entities/", timeout=5)
|
|
data = response.json()
|
|
return (
|
|
response.status_code == 200
|
|
and "entities" in data
|
|
and "deals" in data["entities"]
|
|
)
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def test_ingest_users() -> bool:
|
|
"""Test user data ingestion."""
|
|
try:
|
|
sample_users = [
|
|
{
|
|
"id": 1,
|
|
"name": "Test User",
|
|
"email": "test@example.com",
|
|
"created_at": int(datetime.now().timestamp()),
|
|
"updated_at": int(datetime.now().timestamp()),
|
|
}
|
|
]
|
|
|
|
response = requests.post(
|
|
f"{API_BASE}/data/users",
|
|
json={"data": sample_users, "sync_mode": "upsert"},
|
|
timeout=5
|
|
)
|
|
|
|
return response.status_code == 200 and "Processed" in response.json().get("message", "")
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def test_ingest_deals() -> bool:
|
|
"""Test deal data ingestion."""
|
|
try:
|
|
sample_deals = [
|
|
{
|
|
"id": 1,
|
|
"name": "Test Deal",
|
|
"price": 10000,
|
|
"status_id": 142,
|
|
"pipeline_id": 1,
|
|
"responsible_user_id": 1,
|
|
"created_at": int(datetime.now().timestamp()),
|
|
"updated_at": int(datetime.now().timestamp()),
|
|
}
|
|
]
|
|
|
|
response = requests.post(
|
|
f"{API_BASE}/data/deals",
|
|
json={"data": sample_deals, "sync_mode": "upsert"},
|
|
timeout=5
|
|
)
|
|
|
|
return response.status_code == 200 and "Processed" in response.json().get("message", "")
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def test_list_deal_fields() -> bool:
|
|
"""Test listing deal fields."""
|
|
try:
|
|
response = requests.get(f"{API_BASE}/entities/deals/fields", timeout=5)
|
|
data = response.json()
|
|
return (
|
|
response.status_code == 200
|
|
and data.get("entity_type") == "deals"
|
|
and "fields" in data
|
|
)
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def test_create_export_config() -> tuple[bool, int]:
|
|
"""Test creating export configuration."""
|
|
try:
|
|
config = {
|
|
"name": "Manual Test Export",
|
|
"sheet_id": "test-sheet-123",
|
|
"entity_mappings": {
|
|
"deals": {
|
|
"sheet_name": "Deals",
|
|
"is_enabled": True,
|
|
"field_mapping": [
|
|
{"field_name": "name", "column": "A", "order": 1},
|
|
{"field_name": "price", "column": "B", "order": 2}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
response = requests.post(
|
|
f"{API_BASE}/export/configure",
|
|
json=config,
|
|
timeout=5
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
config_id = response.json().get("configuration_id", 0)
|
|
return True, config_id
|
|
return False, 0
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False, 0
|
|
|
|
|
|
def test_list_export_configs() -> bool:
|
|
"""Test listing export configurations."""
|
|
try:
|
|
response = requests.get(f"{API_BASE}/export/configurations", timeout=5)
|
|
data = response.json()
|
|
return (
|
|
response.status_code == 200
|
|
and "configurations" in data
|
|
)
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def test_amocrm_info() -> bool:
|
|
"""Test AMO CRM connection info (doesn't require valid credentials)."""
|
|
try:
|
|
response = requests.get(f"{API_BASE}/amocrm/info", timeout=5)
|
|
return response.status_code in [200, 401, 500] # Any response means endpoint works
|
|
except Exception as e:
|
|
print(f" Error: {e}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""Run all manual tests."""
|
|
print("""
|
|
╔══════════════════════════════════════════════════════════════╗
|
|
║ AMO CRM Service - Manual API Test Suite ║
|
|
║ ║
|
|
║ Testing core API functionality without Redis/Worker ║
|
|
╚══════════════════════════════════════════════════════════════╝
|
|
""")
|
|
|
|
print("⚙️ Testing API at:", BASE_URL)
|
|
print("📅 Test Date:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
|
|
|
# Track results
|
|
total_tests = 0
|
|
passed_tests = 0
|
|
|
|
# Test 1: Basic Endpoints
|
|
print_section("1. Basic Service Health")
|
|
|
|
result = test_health()
|
|
print_result("Health Check", result)
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
result = test_root()
|
|
print_result("Root Endpoint", result)
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
# Test 2: Entity Management
|
|
print_section("2. Entity Management")
|
|
|
|
result = test_list_entities()
|
|
print_result("List Entities", result)
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
result = test_list_deal_fields()
|
|
print_result("List Deal Fields", result)
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
# Test 3: Data Ingestion
|
|
print_section("3. Data Ingestion")
|
|
|
|
result = test_ingest_users()
|
|
print_result("Ingest Users", result)
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
result = test_ingest_deals()
|
|
print_result("Ingest Deals", result)
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
# Test 4: Export Configuration
|
|
print_section("4. Export Configuration")
|
|
|
|
result, config_id = test_create_export_config()
|
|
print_result("Create Export Config", result, f"Config ID: {config_id}" if result else "")
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
result = test_list_export_configs()
|
|
print_result("List Export Configs", result)
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
# Test 5: AMO CRM Integration
|
|
print_section("5. AMO CRM Integration")
|
|
|
|
result = test_amocrm_info()
|
|
print_result("AMO CRM Info Endpoint", result, "Endpoint responding (credentials may be needed)")
|
|
total_tests += 1
|
|
if result: passed_tests += 1
|
|
|
|
# Summary
|
|
print_section("Test Summary")
|
|
|
|
percentage = (passed_tests / total_tests * 100) if total_tests > 0 else 0
|
|
|
|
print(f"Total Tests: {total_tests}")
|
|
print(f"Passed: {passed_tests} ✅")
|
|
print(f"Failed: {total_tests - passed_tests} ❌")
|
|
print(f"Success Rate: {percentage:.1f}%")
|
|
|
|
if passed_tests == total_tests:
|
|
print("\n🎉 All tests passed! The service is working correctly.")
|
|
print("\n📝 Next Steps:")
|
|
print(" 1. Start Redis server: redis-server")
|
|
print(" 2. Start worker: python -m workers.broker")
|
|
print(" 3. Test export jobs and background processing")
|
|
elif passed_tests >= total_tests * 0.7:
|
|
print("\n✨ Most tests passed! Core functionality is working.")
|
|
print(f"\n⚠️ {total_tests - passed_tests} test(s) failed - check if the service is running")
|
|
else:
|
|
print("\n❌ Many tests failed. Please check:")
|
|
print(" 1. Is the service running? (uvicorn app:app)")
|
|
print(" 2. Is the database initialized? (alembic upgrade head)")
|
|
print(" 3. Are there any error messages in the service logs?")
|
|
|
|
print("\n" + "="*60)
|
|
return passed_tests == total_tests
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
success = main()
|
|
exit(0 if success else 1)
|
|
except KeyboardInterrupt:
|
|
print("\n\n⚠️ Tests interrupted by user")
|
|
exit(130)
|
|
except Exception as e:
|
|
print(f"\n\n❌ Unexpected error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
|