BCards/scripts/test-mongodb-connection.sh
2025-07-22 23:19:17 -03:00

495 lines
16 KiB
Bash

#!/bin/bash
# MongoDB Connection Test Script for Release Environment
# Tests connectivity, database operations, and index validation
set -euo pipefail
# Configuration
readonly MONGODB_HOST="${MONGODB_HOST:-192.168.0.100}"
readonly MONGODB_PORT="${MONGODB_PORT:-27017}"
readonly DATABASE_NAME="${DATABASE_NAME:-BCardsDB}"
readonly CONNECTION_STRING="mongodb://${MONGODB_HOST}:${MONGODB_PORT}/${DATABASE_NAME}"
readonly TIMEOUT=30
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Test basic TCP connectivity
test_tcp_connection() {
log_info "Testing TCP connection to $MONGODB_HOST:$MONGODB_PORT..."
if timeout $TIMEOUT bash -c "</dev/tcp/$MONGODB_HOST/$MONGODB_PORT" 2>/dev/null; then
log_success "TCP connection successful"
return 0
else
log_error "TCP connection failed"
return 1
fi
}
# Test MongoDB connectivity using mongosh if available
test_mongodb_with_mongosh() {
if ! command -v mongosh >/dev/null 2>&1; then
log_warning "mongosh not available, skipping MongoDB shell tests"
return 1
fi
log_info "Testing MongoDB connection with mongosh..."
# Test basic connection
local test_output=$(timeout $TIMEOUT mongosh "$CONNECTION_STRING" --quiet --eval "db.runCommand({ping: 1})" 2>/dev/null || echo "FAILED")
if [[ "$test_output" == *"ok"* ]]; then
log_success "MongoDB ping successful"
else
log_error "MongoDB ping failed"
return 1
fi
# Test database access
log_info "Testing database operations..."
local db_test=$(timeout $TIMEOUT mongosh "$CONNECTION_STRING" --quiet --eval "
try {
// Test basic database operations
db.connection_test.insertOne({test: true, timestamp: new Date()});
var result = db.connection_test.findOne({test: true});
db.connection_test.deleteOne({test: true});
print('DATABASE_ACCESS_OK');
} catch (e) {
print('DATABASE_ACCESS_FAILED: ' + e.message);
}
" 2>/dev/null || echo "DATABASE_ACCESS_FAILED")
if [[ "$db_test" == *"DATABASE_ACCESS_OK"* ]]; then
log_success "Database operations test passed"
else
log_error "Database operations test failed: $db_test"
return 1
fi
return 0
}
# Test MongoDB connectivity using Python if available
test_mongodb_with_python() {
if ! command -v python3 >/dev/null 2>&1; then
log_warning "Python3 not available, skipping Python MongoDB tests"
return 1
fi
log_info "Testing MongoDB connection with Python..."
python3 << EOF
import sys
try:
import pymongo
from pymongo import MongoClient
import socket
# Test connection
client = MongoClient("$CONNECTION_STRING", serverSelectionTimeoutMS=$((TIMEOUT * 1000)))
# Test ping
client.admin.command('ping')
print("MongoDB ping successful (Python)")
# Test database access
db = client["$DATABASE_NAME"]
# Insert test document
test_collection = db.connection_test
result = test_collection.insert_one({"test": True, "source": "python"})
# Read test document
doc = test_collection.find_one({"_id": result.inserted_id})
if doc:
print("Database read/write test passed (Python)")
# Cleanup
test_collection.delete_one({"_id": result.inserted_id})
client.close()
print("PYTHON_TEST_SUCCESS")
except ImportError:
print("PyMongo not installed, skipping Python tests")
sys.exit(1)
except Exception as e:
print(f"Python MongoDB test failed: {e}")
sys.exit(1)
EOF
local python_result=$?
if [ $python_result -eq 0 ]; then
log_success "Python MongoDB test passed"
return 0
else
log_error "Python MongoDB test failed"
return 1
fi
}
# Test using Docker MongoDB client
test_mongodb_with_docker() {
if ! command -v docker >/dev/null 2>&1; then
log_warning "Docker not available, skipping Docker MongoDB tests"
return 1
fi
log_info "Testing MongoDB connection using Docker MongoDB client..."
# Use official MongoDB image to test connection
local docker_test=$(timeout $TIMEOUT docker run --rm mongo:7.0 mongosh "$CONNECTION_STRING" --quiet --eval "
try {
db.runCommand({ping: 1});
db.connection_test.insertOne({test: true, source: 'docker', timestamp: new Date()});
var doc = db.connection_test.findOne({source: 'docker'});
db.connection_test.deleteOne({source: 'docker'});
print('DOCKER_TEST_SUCCESS');
} catch (e) {
print('DOCKER_TEST_FAILED: ' + e.message);
}
" 2>/dev/null || echo "DOCKER_TEST_FAILED")
if [[ "$docker_test" == *"DOCKER_TEST_SUCCESS"* ]]; then
log_success "Docker MongoDB test passed"
return 0
else
log_error "Docker MongoDB test failed: $docker_test"
return 1
fi
}
# Test MongoDB from application container
test_from_application_container() {
local container_name="bcards-staging"
if ! docker ps --format "{{.Names}}" | grep -q "^${container_name}$"; then
log_warning "Application container '$container_name' not running, skipping application test"
return 1
fi
log_info "Testing MongoDB connection from application container..."
# Test connection from the application container
local app_test=$(docker exec "$container_name" timeout 10 bash -c "
# Test TCP connection
if timeout 5 bash -c '</dev/tcp/$MONGODB_HOST/$MONGODB_PORT' 2>/dev/null; then
echo 'APP_TCP_OK'
else
echo 'APP_TCP_FAILED'
exit 1
fi
# Test HTTP health endpoint if available
if curl -f -s http://localhost:8080/health >/dev/null 2>&1; then
echo 'APP_HEALTH_OK'
else
echo 'APP_HEALTH_FAILED'
fi
" 2>/dev/null || echo "APP_TEST_FAILED")
if [[ "$app_test" == *"APP_TCP_OK"* ]]; then
log_success "Application container can connect to MongoDB"
if [[ "$app_test" == *"APP_HEALTH_OK"* ]]; then
log_success "Application health check passed"
else
log_warning "Application health check failed - app may still be starting"
fi
return 0
else
log_error "Application container cannot connect to MongoDB"
return 1
fi
}
# Check MongoDB server status and version
check_mongodb_status() {
log_info "Checking MongoDB server status..."
# Try multiple methods to check status
local status_checked=false
# Method 1: Using mongosh
if command -v mongosh >/dev/null 2>&1; then
local server_status=$(timeout $TIMEOUT mongosh "$CONNECTION_STRING" --quiet --eval "
try {
var status = db.runCommand({serverStatus: 1});
print('MongoDB Version: ' + status.version);
print('Uptime: ' + status.uptime + ' seconds');
print('Connections: ' + status.connections.current + '/' + status.connections.available);
print('STATUS_CHECK_OK');
} catch (e) {
print('STATUS_CHECK_FAILED: ' + e.message);
}
" 2>/dev/null || echo "STATUS_CHECK_FAILED")
if [[ "$server_status" == *"STATUS_CHECK_OK"* ]]; then
echo "$server_status" | grep -v "STATUS_CHECK_OK"
log_success "MongoDB server status check passed"
status_checked=true
fi
fi
# Method 2: Using Docker if mongosh failed
if [ "$status_checked" = false ] && command -v docker >/dev/null 2>&1; then
local docker_status=$(timeout $TIMEOUT docker run --rm mongo:7.0 mongosh "$CONNECTION_STRING" --quiet --eval "
try {
var status = db.runCommand({serverStatus: 1});
print('MongoDB Version: ' + status.version);
print('STATUS_CHECK_OK');
} catch (e) {
print('STATUS_CHECK_FAILED: ' + e.message);
}
" 2>/dev/null || echo "STATUS_CHECK_FAILED")
if [[ "$docker_status" == *"STATUS_CHECK_OK"* ]]; then
echo "$docker_status" | grep -v "STATUS_CHECK_OK"
log_success "MongoDB server status check passed (via Docker)"
status_checked=true
fi
fi
if [ "$status_checked" = false ]; then
log_warning "Could not retrieve MongoDB server status"
return 1
fi
return 0
}
# Test BCards specific collections and indexes
test_bcards_collections() {
if ! command -v mongosh >/dev/null 2>&1 && ! command -v docker >/dev/null 2>&1; then
log_warning "Cannot test BCards collections - no MongoDB client available"
return 1
fi
log_info "Testing BCards specific collections and indexes..."
local mongo_cmd="mongosh"
local docker_prefix=""
if ! command -v mongosh >/dev/null 2>&1; then
mongo_cmd="docker run --rm mongo:7.0 mongosh"
docker_prefix="timeout $TIMEOUT "
fi
local collections_test=$(${docker_prefix}${mongo_cmd} "$CONNECTION_STRING" --quiet --eval "
try {
// Check required collections
var collections = db.listCollectionNames();
var requiredCollections = ['users', 'userpages', 'categories'];
var missingCollections = [];
requiredCollections.forEach(function(collection) {
if (collections.indexOf(collection) === -1) {
missingCollections.push(collection);
}
});
if (missingCollections.length > 0) {
print('Missing collections: ' + missingCollections.join(', '));
} else {
print('All required collections exist');
}
// Check indexes on userpages collection
if (collections.indexOf('userpages') !== -1) {
var indexes = db.userpages.getIndexes();
print('UserPages collection has ' + indexes.length + ' indexes');
// Check for important compound index
var hasCompoundIndex = indexes.some(function(index) {
return index.key && index.key.category && index.key.slug;
});
if (hasCompoundIndex) {
print('Required compound index (category, slug) exists');
} else {
print('WARNING: Compound index (category, slug) is missing');
}
}
print('COLLECTIONS_TEST_OK');
} catch (e) {
print('COLLECTIONS_TEST_FAILED: ' + e.message);
}
" 2>/dev/null || echo "COLLECTIONS_TEST_FAILED")
if [[ "$collections_test" == *"COLLECTIONS_TEST_OK"* ]]; then
echo "$collections_test" | grep -v "COLLECTIONS_TEST_OK"
log_success "BCards collections test passed"
return 0
else
log_warning "BCards collections test had issues: $collections_test"
return 1
fi
}
# Performance test
test_mongodb_performance() {
log_info "Running basic performance test..."
if ! command -v mongosh >/dev/null 2>&1; then
log_warning "mongosh not available, skipping performance test"
return 1
fi
local perf_test=$(timeout $TIMEOUT mongosh "$CONNECTION_STRING" --quiet --eval "
try {
var start = new Date();
// Insert test documents
var docs = [];
for (var i = 0; i < 100; i++) {
docs.push({test: true, index: i, timestamp: new Date()});
}
db.performance_test.insertMany(docs);
// Read test
var count = db.performance_test.countDocuments({test: true});
// Update test
db.performance_test.updateMany({test: true}, {\$set: {updated: true}});
// Delete test
db.performance_test.deleteMany({test: true});
var end = new Date();
var duration = end - start;
print('Performance test completed in ' + duration + 'ms');
print('Operations: 100 inserts, 1 count, 100 updates, 100 deletes');
if (duration < 5000) {
print('PERFORMANCE_TEST_OK');
} else {
print('PERFORMANCE_TEST_SLOW');
}
} catch (e) {
print('PERFORMANCE_TEST_FAILED: ' + e.message);
}
" 2>/dev/null || echo "PERFORMANCE_TEST_FAILED")
if [[ "$perf_test" == *"PERFORMANCE_TEST_OK"* ]]; then
echo "$perf_test" | grep -v "PERFORMANCE_TEST_OK"
log_success "Performance test passed"
return 0
elif [[ "$perf_test" == *"PERFORMANCE_TEST_SLOW"* ]]; then
echo "$perf_test" | grep -v "PERFORMANCE_TEST_SLOW"
log_warning "Performance test completed but was slow"
return 0
else
log_error "Performance test failed: $perf_test"
return 1
fi
}
# Display connection summary
display_summary() {
echo ""
log_info "MongoDB Connection Test Summary"
echo "=================================================="
echo "🏠 Host: $MONGODB_HOST:$MONGODB_PORT"
echo "🗄️ Database: $DATABASE_NAME"
echo "🔗 Connection String: $CONNECTION_STRING"
echo "⏱️ Timeout: ${TIMEOUT}s"
echo "📊 Tests completed: $(date)"
echo "=================================================="
}
# Main test function
main() {
log_info "Starting MongoDB connection tests for Release environment"
local test_results=()
local overall_success=true
# Run all tests
if test_tcp_connection; then
test_results+=("✅ TCP Connection")
else
test_results+=("❌ TCP Connection")
overall_success=false
fi
if test_mongodb_with_mongosh; then
test_results+=("✅ MongoDB Shell")
elif test_mongodb_with_docker; then
test_results+=("✅ MongoDB Docker")
elif test_mongodb_with_python; then
test_results+=("✅ MongoDB Python")
else
test_results+=("❌ MongoDB Client")
overall_success=false
fi
if test_from_application_container; then
test_results+=("✅ Application Container")
else
test_results+=("⚠️ Application Container")
fi
if check_mongodb_status; then
test_results+=("✅ Server Status")
else
test_results+=("⚠️ Server Status")
fi
if test_bcards_collections; then
test_results+=("✅ BCards Collections")
else
test_results+=("⚠️ BCards Collections")
fi
if test_mongodb_performance; then
test_results+=("✅ Performance Test")
else
test_results+=("⚠️ Performance Test")
fi
# Display results
display_summary
echo ""
log_info "Test Results:"
for result in "${test_results[@]}"; do
echo " $result"
done
echo ""
if [ "$overall_success" = true ]; then
log_success "All critical MongoDB tests passed!"
exit 0
else
log_error "Some critical MongoDB tests failed!"
exit 1
fi
}
# Run main function
main "$@"