diff --git a/services/search/solr-config/conf/solrconfig.xml b/services/search/solr-config/conf/solrconfig.xml
index e16dcb7..43c3403 100644
--- a/services/search/solr-config/conf/solrconfig.xml
+++ b/services/search/solr-config/conf/solrconfig.xml
@@ -146,9 +146,7 @@
-
-
+
-
-
+
\ No newline at end of file
diff --git a/services/search/solr-config/conf/stopwords.txt b/services/search/solr-config/conf/stopwords.txt
new file mode 100644
index 0000000..3f50366
--- /dev/null
+++ b/services/search/solr-config/conf/stopwords.txt
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF)
+# Standard English stop words
+a
+an
+and
+are
+as
+at
+be
+but
+by
+for
+if
+in
+into
+is
+it
+no
+not
+of
+on
+or
+such
+that
+the
+their
+then
+there
+these
+they
+this
+to
+was
+will
+with
\ No newline at end of file
diff --git a/services/search/solr-config/conf/synonyms.txt b/services/search/solr-config/conf/synonyms.txt
new file mode 100644
index 0000000..c167f27
--- /dev/null
+++ b/services/search/solr-config/conf/synonyms.txt
@@ -0,0 +1,38 @@
+# Synonyms for site11 search
+# Format: term1, term2, term3 => all are synonyms
+# Or: term1, term2 => term1 is replaced by term2
+
+# Technology synonyms
+javascript, js
+typescript, ts
+python, py
+golang, go
+database, db
+kubernetes, k8s
+docker, container, containerization
+
+# Common terms
+search, find, query, lookup
+upload, import, add
+download, export, get
+delete, remove, erase
+update, modify, edit, change
+create, make, new, add
+
+# File related
+document, doc, file
+image, picture, photo, img
+video, movie, clip
+audio, sound, music
+
+# User related
+user, member, account
+admin, administrator, moderator
+profile, account, user
+
+# Status
+active, enabled, live
+inactive, disabled, offline
+pending, waiting, processing
+complete, done, finished
+error, failed, failure
\ No newline at end of file
diff --git a/test_all_services.py b/test_all_services.py
new file mode 100644
index 0000000..7f0147c
--- /dev/null
+++ b/test_all_services.py
@@ -0,0 +1,416 @@
+#!/usr/bin/env python3
+"""
+Complete test suite for all backend services
+"""
+import asyncio
+import httpx
+import json
+from datetime import datetime
+import base64
+import os
+
+# Service endpoints
+SERVICES = {
+ "users": "http://localhost:8001",
+ "images": "http://localhost:8002",
+ "oauth": "http://localhost:8003",
+ "console": "http://localhost:8011",
+ "statistics": "http://localhost:8012",
+ "notifications": "http://localhost:8013",
+ "files": "http://localhost:8014",
+ "search": "http://localhost:8015"
+}
+
+def print_section(title):
+ """Print section header"""
+ print(f"\n{'='*60}")
+ print(f" {title}")
+ print(f"{'='*60}")
+
+def print_test(name, status, details=""):
+ """Print test result"""
+ icon = "ā
" if status else "ā"
+ print(f"{icon} {name}: {details}")
+
+async def test_health_endpoints():
+ """Test all health endpoints"""
+ print_section("1. HEALTH CHECK ENDPOINTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ results = {}
+ for service, url in SERVICES.items():
+ try:
+ response = await client.get(f"{url}/health")
+ if response.status_code == 200:
+ data = response.json()
+ status = data.get("status", "unknown")
+ print_test(f"{service.upper()} Health", True, f"Status: {status}")
+ results[service] = True
+ else:
+ print_test(f"{service.upper()} Health", False, f"HTTP {response.status_code}")
+ results[service] = False
+ except Exception as e:
+ print_test(f"{service.upper()} Health", False, f"Error: {str(e)}")
+ results[service] = False
+ return results
+
+async def test_users_service():
+ """Test Users Service API"""
+ print_section("2. USERS SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ base_url = SERVICES["users"]
+
+ # Create user
+ user_data = {
+ "username": f"testuser_{datetime.now().timestamp()}",
+ "email": f"test_{datetime.now().timestamp()}@example.com",
+ "password": "Test123!@#",
+ "full_name": "Test User"
+ }
+
+ try:
+ response = await client.post(f"{base_url}/api/users/register", json=user_data)
+ if response.status_code == 200:
+ user = response.json()
+ print_test("Create User", True, f"User ID: {user.get('id')}")
+
+ # Get user
+ response = await client.get(f"{base_url}/api/users/{user['id']}")
+ print_test("Get User", response.status_code == 200, f"Username: {user.get('username')}")
+
+ # List users
+ response = await client.get(f"{base_url}/api/users")
+ data = response.json()
+ print_test("List Users", response.status_code == 200, f"Total: {data.get('total', 0)} users")
+
+ # Update user
+ update_data = {"bio": "Updated bio"}
+ response = await client.put(f"{base_url}/api/users/{user['id']}", json=update_data)
+ print_test("Update User", response.status_code == 200)
+
+ # Delete user
+ response = await client.delete(f"{base_url}/api/users/{user['id']}")
+ print_test("Delete User", response.status_code == 200)
+ else:
+ print_test("Create User", False, f"HTTP {response.status_code}")
+ except Exception as e:
+ print_test("Users Service", False, f"Error: {str(e)}")
+
+async def test_oauth_service():
+ """Test OAuth Service"""
+ print_section("3. OAUTH SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ base_url = SERVICES["oauth"]
+
+ try:
+ # Test OAuth providers
+ response = await client.get(f"{base_url}/api/oauth/providers")
+ if response.status_code == 200:
+ providers = response.json()
+ print_test("Get OAuth Providers", True, f"Providers: {', '.join(providers.get('providers', []))}")
+ else:
+ print_test("Get OAuth Providers", False, f"HTTP {response.status_code}")
+
+ # Test Google OAuth URL
+ response = await client.get(f"{base_url}/api/oauth/google/authorize")
+ print_test("Google OAuth URL", response.status_code == 200, "Authorization URL generated")
+
+ # Test GitHub OAuth URL
+ response = await client.get(f"{base_url}/api/oauth/github/authorize")
+ print_test("GitHub OAuth URL", response.status_code == 200, "Authorization URL generated")
+
+ except Exception as e:
+ print_test("OAuth Service", False, f"Error: {str(e)}")
+
+async def test_images_service():
+ """Test Images Service"""
+ print_section("4. IMAGES SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ base_url = SERVICES["images"]
+
+ try:
+ # Create test image (1x1 pixel PNG)
+ image_data = base64.b64decode(
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
+ )
+
+ # Upload image
+ files = {"file": ("test.png", image_data, "image/png")}
+ response = await client.post(f"{base_url}/api/images/upload", files=files)
+
+ if response.status_code == 200:
+ image = response.json()
+ print_test("Upload Image", True, f"Image ID: {image.get('id')}")
+
+ # Get image metadata
+ response = await client.get(f"{base_url}/api/images/{image['id']}/metadata")
+ print_test("Get Image Metadata", response.status_code == 200)
+
+ # List images
+ response = await client.get(f"{base_url}/api/images")
+ data = response.json()
+ print_test("List Images", response.status_code == 200, f"Total: {data.get('total', 0)} images")
+
+ # Delete image
+ response = await client.delete(f"{base_url}/api/images/{image['id']}")
+ print_test("Delete Image", response.status_code == 200)
+ else:
+ print_test("Upload Image", False, f"HTTP {response.status_code}")
+
+ except Exception as e:
+ print_test("Images Service", False, f"Error: {str(e)}")
+
+async def test_files_service():
+ """Test Files Service"""
+ print_section("5. FILES SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=30.0) as client:
+ base_url = SERVICES["files"]
+
+ try:
+ # Upload test file
+ test_content = b"Test file content for MinIO storage"
+ files = {"file": ("test.txt", test_content, "text/plain")}
+
+ response = await client.post(f"{base_url}/api/files/upload", files=files)
+
+ if response.status_code == 200:
+ file_info = response.json()
+ print_test("Upload File", True, f"File ID: {file_info.get('file_id')}")
+
+ # Get file info
+ response = await client.get(f"{base_url}/api/files/{file_info['file_id']}")
+ print_test("Get File Info", response.status_code == 200)
+
+ # List files
+ response = await client.get(f"{base_url}/api/files")
+ data = response.json()
+ print_test("List Files", response.status_code == 200, f"Total: {data.get('total', 0)} files")
+
+ # Delete file
+ response = await client.delete(f"{base_url}/api/files/{file_info['file_id']}")
+ print_test("Delete File", response.status_code == 200)
+ else:
+ print_test("Upload File", False, f"HTTP {response.status_code}")
+
+ except Exception as e:
+ print_test("Files Service", False, f"Error: {str(e)}")
+
+async def test_notifications_service():
+ """Test Notifications Service"""
+ print_section("6. NOTIFICATIONS SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ base_url = SERVICES["notifications"]
+
+ try:
+ # Send email notification
+ email_data = {
+ "to": "test@example.com",
+ "subject": "Test Email",
+ "body": "This is a test email",
+ "template": "default"
+ }
+
+ response = await client.post(f"{base_url}/api/notifications/email", json=email_data)
+ print_test("Send Email", response.status_code == 200, "Email queued")
+
+ # Send SMS notification
+ sms_data = {
+ "to": "+1234567890",
+ "message": "Test SMS message"
+ }
+
+ response = await client.post(f"{base_url}/api/notifications/sms", json=sms_data)
+ print_test("Send SMS", response.status_code == 200, "SMS queued")
+
+ # Send push notification
+ push_data = {
+ "user_id": "test_user",
+ "title": "Test Push",
+ "body": "Test push notification",
+ "data": {"key": "value"}
+ }
+
+ response = await client.post(f"{base_url}/api/notifications/push", json=push_data)
+ print_test("Send Push", response.status_code == 200, "Push notification queued")
+
+ # Get notification history
+ response = await client.get(f"{base_url}/api/notifications/history?user_id=test_user")
+ data = response.json()
+ print_test("Get History", response.status_code == 200, f"Total: {data.get('total', 0)} notifications")
+
+ except Exception as e:
+ print_test("Notifications Service", False, f"Error: {str(e)}")
+
+async def test_statistics_service():
+ """Test Statistics Service"""
+ print_section("7. STATISTICS SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ base_url = SERVICES["statistics"]
+
+ try:
+ # Track event
+ event_data = {
+ "event_type": "page_view",
+ "user_id": "test_user",
+ "metadata": {
+ "page": "/home",
+ "referrer": "google.com"
+ }
+ }
+
+ response = await client.post(f"{base_url}/api/statistics/events", json=event_data)
+ print_test("Track Event", response.status_code == 200, "Event tracked")
+
+ # Get user statistics
+ response = await client.get(f"{base_url}/api/statistics/users/test_user")
+ print_test("Get User Stats", response.status_code == 200)
+
+ # Get system statistics
+ response = await client.get(f"{base_url}/api/statistics/system")
+ if response.status_code == 200:
+ stats = response.json()
+ print_test("System Stats", True, f"Total events: {stats.get('total_events', 0)}")
+ else:
+ print_test("System Stats", False, f"HTTP {response.status_code}")
+
+ # Get analytics
+ response = await client.get(f"{base_url}/api/statistics/analytics?period=day")
+ print_test("Get Analytics", response.status_code == 200, "Daily analytics retrieved")
+
+ except Exception as e:
+ print_test("Statistics Service", False, f"Error: {str(e)}")
+
+async def test_search_service():
+ """Test Search Service"""
+ print_section("8. SEARCH SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ base_url = SERVICES["search"]
+
+ try:
+ # Index test document
+ doc = {
+ "id": f"test_doc_{datetime.now().timestamp()}",
+ "doc_type": "test",
+ "title": "Test Document",
+ "content": "This is a test document for search functionality",
+ "tags": ["test", "search", "solr"],
+ "created_at": datetime.utcnow().isoformat()
+ }
+
+ response = await client.post(f"{base_url}/api/search/index", json=doc)
+ print_test("Index Document", response.status_code == 200, f"Document ID: {doc['id']}")
+
+ # Wait for indexing
+ await asyncio.sleep(2)
+
+ # Search documents
+ response = await client.get(f"{base_url}/api/search", params={"q": "test"})
+ if response.status_code == 200:
+ data = response.json()
+ print_test("Search Documents", True, f"Found {data.get('total', 0)} results")
+ else:
+ print_test("Search Documents", False, f"HTTP {response.status_code}")
+
+ # Get suggestions
+ response = await client.get(f"{base_url}/api/search/suggest", params={"q": "tes"})
+ if response.status_code == 200:
+ data = response.json()
+ suggestions = data.get("suggestions", [])
+ print_test("Get Suggestions", True, f"{len(suggestions)} suggestions")
+ else:
+ print_test("Get Suggestions", False, f"HTTP {response.status_code}")
+
+ # Get statistics
+ response = await client.get(f"{base_url}/api/search/stats")
+ if response.status_code == 200:
+ stats = response.json()
+ print_test("Search Stats", True, f"Total docs: {stats.get('statistics', {}).get('total_documents', 0)}")
+ else:
+ print_test("Search Stats", False, f"HTTP {response.status_code}")
+
+ # Delete document
+ response = await client.delete(f"{base_url}/api/search/document/{doc['id']}")
+ print_test("Delete Document", response.status_code == 200)
+
+ except Exception as e:
+ print_test("Search Service", False, f"Error: {str(e)}")
+
+async def test_console_service():
+ """Test Console Service"""
+ print_section("9. CONSOLE SERVICE TESTS")
+
+ async with httpx.AsyncClient(timeout=10.0) as client:
+ base_url = SERVICES["console"]
+
+ try:
+ # Get services status
+ response = await client.get(f"{base_url}/api/console/services")
+ if response.status_code == 200:
+ services = response.json()
+ print_test("Get Services", True, f"{len(services.get('services', []))} services")
+ else:
+ print_test("Get Services", False, f"HTTP {response.status_code}")
+
+ # Get system info
+ response = await client.get(f"{base_url}/api/console/system")
+ print_test("System Info", response.status_code == 200, "System information retrieved")
+
+ # Get logs
+ response = await client.get(f"{base_url}/api/console/logs?service=users&limit=10")
+ print_test("Get Logs", response.status_code == 200, "Logs retrieved")
+
+ # Get metrics
+ response = await client.get(f"{base_url}/api/console/metrics")
+ if response.status_code == 200:
+ metrics = response.json()
+ print_test("Get Metrics", True, f"CPU: {metrics.get('metrics', {}).get('cpu_usage', 'N/A')}%")
+ else:
+ print_test("Get Metrics", False, f"HTTP {response.status_code}")
+
+ except Exception as e:
+ print_test("Console Service", False, f"Error: {str(e)}")
+
+async def main():
+ """Run all tests"""
+ print("="*60)
+ print(" BACKEND SERVICES COMPREHENSIVE TEST SUITE")
+ print("="*60)
+ print(f"Started at: {datetime.now().isoformat()}")
+
+ # Test health endpoints first
+ health_results = await test_health_endpoints()
+
+ # Test individual services
+ await test_users_service()
+ await test_oauth_service()
+ await test_images_service()
+ await test_files_service()
+ await test_notifications_service()
+ await test_statistics_service()
+ await test_search_service()
+ await test_console_service()
+
+ # Summary
+ print_section("TEST SUMMARY")
+ healthy_count = sum(1 for v in health_results.values() if v)
+ total_count = len(health_results)
+
+ print(f"\nš Services Health: {healthy_count}/{total_count} services are healthy")
+ print(f"ā
Healthy Services: {', '.join([k for k, v in health_results.items() if v])}")
+
+ if healthy_count < total_count:
+ unhealthy = [k for k, v in health_results.items() if not v]
+ print(f"ā Unhealthy Services: {', '.join(unhealthy)}")
+
+ print(f"\nš Test suite completed at: {datetime.now().isoformat()}")
+ print("="*60)
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file