""" Unit tests for MongoDB database connection module. Tests the database connection functionality with mocking to avoid requiring actual MongoDB instance during tests. """ import pytest from unittest.mock import Mock, patch, MagicMock from pymongo.errors import ConnectionFailure, ServerSelectionTimeoutError from app.database.connection import ( create_mongodb_client, get_database, close_database_connection, get_mongodb_client, test_database_connection ) def test_i_can_get_database_connection(): """Test successful database connection creation.""" mock_client = Mock() mock_database = Mock() mock_client.__getitem__.return_value = mock_database with patch('app.database.connection.MongoClient', return_value=mock_client): with patch('app.database.connection.get_mongodb_url', return_value="mongodb://localhost:27017"): with patch('app.database.connection.get_mongodb_database_name', return_value="testdb"): # Reset global variables import app.database.connection app.database.connection._client = None app.database.connection._database = None result = get_database() assert result == mock_database mock_client.admin.command.assert_called_with('ping') def test_i_cannot_connect_to_invalid_mongodb_url(): """Test fail-fast behavior with invalid MongoDB URL.""" mock_client = Mock() mock_client.admin.command.side_effect = ConnectionFailure("Connection failed") with patch('app.database.connection.MongoClient', return_value=mock_client): with patch('app.database.connection.get_mongodb_url', return_value="mongodb://invalid:27017"): with pytest.raises(SystemExit) as exc_info: create_mongodb_client() assert exc_info.value.code == 1 def test_i_cannot_connect_with_server_selection_timeout(): """Test fail-fast behavior with server selection timeout.""" mock_client = Mock() mock_client.admin.command.side_effect = ServerSelectionTimeoutError("Timeout") with patch('app.database.connection.MongoClient', return_value=mock_client): with patch('app.database.connection.get_mongodb_url', return_value="mongodb://timeout:27017"): with pytest.raises(SystemExit) as exc_info: create_mongodb_client() assert exc_info.value.code == 1 def test_i_cannot_connect_with_unexpected_error(): """Test fail-fast behavior with unexpected connection error.""" with patch('app.database.connection.MongoClient', side_effect=Exception("Unexpected error")): with patch('app.database.connection.get_mongodb_url', return_value="mongodb://error:27017"): with pytest.raises(SystemExit) as exc_info: create_mongodb_client() assert exc_info.value.code == 1 def test_i_can_get_database_singleton(): """Test that get_database returns the same instance (singleton pattern).""" mock_client = Mock() mock_database = Mock() mock_client.__getitem__.return_value = mock_database with patch('app.database.connection.MongoClient', return_value=mock_client): with patch('app.database.connection.get_mongodb_url', return_value="mongodb://localhost:27017"): with patch('app.database.connection.get_mongodb_database_name', return_value="testdb"): # Reset global variables import app.database.connection app.database.connection._client = None app.database.connection._database = None # First call db1 = get_database() # Second call db2 = get_database() assert db1 is db2 # MongoClient should be called only once assert mock_client.admin.command.call_count == 1 def test_i_can_close_database_connection(): """Test closing database connection.""" mock_client = Mock() mock_database = Mock() mock_client.__getitem__.return_value = mock_database with patch('app.database.connection.MongoClient', return_value=mock_client): with patch('app.database.connection.get_mongodb_url', return_value="mongodb://localhost:27017"): with patch('app.database.connection.get_mongodb_database_name', return_value="testdb"): # Reset global variables import app.database.connection app.database.connection._client = None app.database.connection._database = None # Create connection get_database() # Close connection close_database_connection() mock_client.close.assert_called_once() assert app.database.connection._client is None assert app.database.connection._database is None def test_i_can_get_mongodb_client(): """Test getting raw MongoDB client instance.""" mock_client = Mock() mock_database = Mock() mock_client.__getitem__.return_value = mock_database with patch('app.database.connection.MongoClient', return_value=mock_client): with patch('app.database.connection.get_mongodb_url', return_value="mongodb://localhost:27017"): with patch('app.database.connection.get_mongodb_database_name', return_value="testdb"): # Reset global variables import app.database.connection app.database.connection._client = None app.database.connection._database = None # Create connection first get_database() # Get client result = get_mongodb_client() assert result == mock_client def test_i_can_get_none_mongodb_client_when_not_connected(): """Test getting MongoDB client returns None when not connected.""" # Reset global variables import app.database.connection app.database.connection._client = None app.database.connection._database = None result = get_mongodb_client() assert result is None def test_i_can_test_database_connection_success(): """Test database connection health check - success case.""" mock_database = Mock() mock_database.command.return_value = True with patch('app.database.connection.get_database', return_value=mock_database): result = test_database_connection() assert result is True mock_database.command.assert_called_with('ping') def test_i_cannot_test_database_connection_failure(): """Test database connection health check - failure case.""" mock_database = Mock() mock_database.command.side_effect = Exception("Connection error") with patch('app.database.connection.get_database', return_value=mock_database): result = test_database_connection() assert result is False def test_i_can_close_connection_when_no_client(): """Test closing connection when no client exists (should not raise error).""" # Reset global variables import app.database.connection app.database.connection._client = None app.database.connection._database = None # Should not raise any exception close_database_connection() assert app.database.connection._client is None assert app.database.connection._database is None