Skip to content

Commit

Permalink
feat: Added more test cases!
Browse files Browse the repository at this point in the history
  • Loading branch information
amindadgar committed Nov 20, 2024
1 parent 016ea37 commit 3ab6239
Show file tree
Hide file tree
Showing 7 changed files with 353 additions and 2 deletions.
3 changes: 3 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ services:
- POSTGRES_PORT=5432
- SENTRY_DSN=sample_dsn
- SENTRY_ENV=local
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=
- CHUNK_SIZE=512
- EMBEDDING_DIM=1024
- QDRANT_HOST=qdrant
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name="tc-hivemind-backend",
version="1.3.0",
version="1.4.0",
author="Mohammad Amin Dadgar, TogetherCrew",
maintainer="Mohammad Amin Dadgar",
maintainer_email="[email protected]",
Expand Down
3 changes: 2 additions & 1 deletion tc_hivemind_backend/db/mongo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import Optional
import logging

from pymongo import MongoClient
Expand All @@ -6,7 +7,7 @@


class MongoSingleton:
__instance: "MongoSingleton" | None = None
__instance: Optional["MongoSingleton"] = None

def __init__(self):
if MongoSingleton.__instance is not None:
Expand Down
26 changes: 26 additions & 0 deletions tc_hivemind_backend/tests/integration/test_mongo_singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import unittest

from pymongo.mongo_client import MongoClient
from tc_hivemind_backend.db.mongo import MongoSingleton


class TestMongoSingletonIntegration(unittest.TestCase):
"""Separate test class for integration tests"""

def setUp(self):
"""Reset the singleton instance before each test"""
MongoSingleton._MongoSingleton__instance = None

def test_real_connection(self):
"""Integration test for real MongoDB connection"""
instance = MongoSingleton.get_instance()
client = instance.get_client()
self.assertIsInstance(client, MongoClient)

# Test actual connection
try:
info = client.server_info()
self.assertIsInstance(info, dict)
self.assertIn("version", info)
except Exception as e:
self.fail(f"Failed to connect to MongoDB: {e}")
108 changes: 108 additions & 0 deletions tc_hivemind_backend/tests/unit/test_mongo_singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import unittest
from unittest.mock import patch, MagicMock
import logging

# Import the modules to test
from tc_hivemind_backend.db.mongo import MongoSingleton, get_mongo_uri


class TestMongoSingleton(unittest.TestCase):
def setUp(self):
"""Reset the singleton instance before each test"""
MongoSingleton._MongoSingleton__instance = None
# Set up logging capture
self.log_records = []
self.logger = logging.getLogger()
self.old_level = self.logger.level
self.logger.setLevel(logging.INFO)
self.handler = logging.Handler()
self.handler.emit = lambda record: self.log_records.append(record)
self.logger.addHandler(self.handler)

def tearDown(self):
"""Clean up after each test"""
self.logger.removeHandler(self.handler)
self.logger.setLevel(self.old_level)
self.log_records = []

def test_get_mongo_uri(self):
"""Test the get_mongo_uri function"""
mock_credentials = {
"user": "test_user",
"password": "test_pass",
"host": "test_host",
"port": "27017",
}

with patch("tc_hivemind_backend.db.mongo.Credentials") as mock_creds:
mock_creds.return_value.load_mongo.return_value = mock_credentials
uri = get_mongo_uri()
expected_uri = "mongodb://test_user:test_pass@test_host:27017"
self.assertEqual(uri, expected_uri)

def test_singleton_creation(self):
"""Test that only one instance of MongoSingleton can be created"""
with patch("tc_hivemind_backend.db.mongo.MongoClient"):
# First instance should be created successfully
instance1 = MongoSingleton.get_instance()
self.assertIsInstance(instance1, MongoSingleton)

# Second instance should return the same object
instance2 = MongoSingleton.get_instance()
self.assertIs(instance1, instance2)

def test_direct_instantiation_fails(self):
"""Test that direct instantiation fails after first instance"""
with patch("tc_hivemind_backend.db.mongo.MongoClient"):
# First instantiation should work
_ = MongoSingleton()

# Second instantiation should raise an exception
with self.assertRaises(Exception) as context:
MongoSingleton()
self.assertEqual(str(context.exception), "This class is a singleton!")

def test_successful_connection(self):
"""Test successful MongoDB connection logging"""
with patch("tc_hivemind_backend.db.mongo.MongoClient") as mock_client:
# Mock successful connection
mock_client_instance = mock_client.return_value
mock_client_instance.server_info.return_value = {"version": "4.4.0"}

instance = MongoSingleton.get_instance()

# Verify logging
log_messages = [record.getMessage() for record in self.log_records]
self.assertTrue(
any("MongoDB Connected Successfully!" in msg for msg in log_messages)
)
self.assertTrue(any("version" in msg for msg in log_messages))

def test_failed_connection(self):
"""Test failed MongoDB connection logging"""
with patch("tc_hivemind_backend.db.mongo.MongoClient") as mock_client:
# Mock failed connection
mock_client_instance = mock_client.return_value
mock_client_instance.server_info.side_effect = Exception(
"Connection failed"
)

instance = MongoSingleton.get_instance()

# Verify logging
log_messages = [record.getMessage() for record in self.log_records]
self.assertTrue(
any("MongoDB not connected!" in msg for msg in log_messages)
)
self.assertTrue(any("Connection failed" in msg for msg in log_messages))

def test_get_client(self):
"""Test get_client method returns MongoDB client"""
with patch("tc_hivemind_backend.db.mongo.MongoClient") as mock_client:
mock_instance = MagicMock()
mock_client.return_value = mock_instance

singleton = MongoSingleton.get_instance()
client = singleton.get_client()

self.assertIs(client, mock_instance)
108 changes: 108 additions & 0 deletions tc_hivemind_backend/tests/unit/test_qdrant_singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import unittest
from unittest.mock import patch, MagicMock
from tc_hivemind_backend.db.qdrant import QdrantSingleton


class TestQdrantSingleton(unittest.TestCase):
def setUp(self):
QdrantSingleton._QdrantSingleton__instance = None

def test_singleton_pattern(self):
instance1 = QdrantSingleton.get_instance()
instance2 = QdrantSingleton.get_instance()

self.assertIs(instance1, instance2)

with self.assertRaises(Exception) as context:
QdrantSingleton()
self.assertEqual(str(context.exception), "This class is a singleton!")

@patch("tc_hivemind_backend.db.qdrant.load_qdrant_credentials")
@patch("tc_hivemind_backend.db.qdrant.QdrantClient")
def test_initialization_without_api_key(
self, mock_qdrant_client, mock_load_credentials
):
mock_load_credentials.return_value = {
"host": "test_host",
"port": 6333,
"api_key": "",
}

instance = QdrantSingleton.get_instance()

mock_qdrant_client.assert_called_once_with(host="test_host", port=6333)

self.assertEqual(instance.get_client(), mock_qdrant_client.return_value)

@patch("tc_hivemind_backend.db.qdrant.load_qdrant_credentials")
@patch("tc_hivemind_backend.db.qdrant.QdrantClient")
def test_initialization_with_api_key(
self, mock_qdrant_client, mock_load_credentials
):
mock_load_credentials.return_value = {
"host": "test_host",
"port": 6333,
"api_key": "test_api_key",
}

instance = QdrantSingleton.get_instance()

mock_qdrant_client.assert_called_once_with(
host="test_host", port=6333, api_key="test_api_key", https=False
)

self.assertEqual(instance.get_client(), mock_qdrant_client.return_value)

@patch("tc_hivemind_backend.db.qdrant.load_qdrant_credentials")
@patch("tc_hivemind_backend.db.qdrant.QdrantClient")
@patch("logging.info")
@patch("logging.error")
def test_successful_connection(
self, mock_error_log, mock_info_log, mock_qdrant_client, mock_load_credentials
):
mock_load_credentials.return_value = {
"host": "test_host",
"port": 6333,
"api_key": "test_api_key",
}

mock_client = MagicMock()
mock_client.get_collections.return_value = []
mock_qdrant_client.return_value = mock_client

QdrantSingleton.get_instance()

mock_info_log.assert_called_once_with("QDrant Connected Successfully!")
mock_error_log.assert_not_called()

@patch("tc_hivemind_backend.db.qdrant.load_qdrant_credentials")
@patch("tc_hivemind_backend.db.qdrant.QdrantClient")
@patch("logging.info")
@patch("logging.error")
def test_failed_connection(
self, mock_error_log, mock_info_log, mock_qdrant_client, mock_load_credentials
):
mock_load_credentials.return_value = {
"host": "test_host",
"port": 6333,
"api_key": "test_api_key",
}

mock_client = MagicMock()
mock_client.get_collections.side_effect = Exception("Connection failed")
mock_qdrant_client.return_value = mock_client

QdrantSingleton.get_instance()

mock_error_log.assert_called_once_with(
"QDrant not connected! exp: Connection failed"
)
mock_info_log.assert_not_called()

@patch("tc_hivemind_backend.db.qdrant.load_qdrant_credentials")
def test_credentials_loading_error(self, mock_load_credentials):
mock_load_credentials.side_effect = Exception("Failed to load credentials")

with self.assertRaises(Exception) as context:
QdrantSingleton.get_instance()
self.assertEqual(str(context.exception), "Failed to load credentials")
105 changes: 105 additions & 0 deletions tc_hivemind_backend/tests/unit/test_redis_singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import unittest
from unittest.mock import patch, MagicMock
from tc_hivemind_backend.db.redis import RedisSingleton


class TestRedisSingleton(unittest.TestCase):
def setUp(self):
RedisSingleton._RedisSingleton__instance = None

def test_singleton_pattern(self):
instance1 = RedisSingleton.get_instance()
instance2 = RedisSingleton.get_instance()

self.assertIs(instance1, instance2)

with self.assertRaises(Exception) as context:
RedisSingleton()
self.assertEqual(str(context.exception), "This class is a singleton!")

@patch("tc_hivemind_backend.db.redis.Credentials")
@patch("redis.Redis")
def test_initialization(self, mock_redis, mock_credentials):
mock_credentials_instance = MagicMock()
mock_credentials_instance.load_redis.return_value = {
"host": "test_host",
"port": "6379",
"password": "test_password",
}
mock_credentials.return_value = mock_credentials_instance

instance = RedisSingleton.get_instance()

mock_redis.assert_called_once_with(
host="test_host", port=6379, password="test_password", decode_responses=True
)

self.assertEqual(instance.get_client(), mock_redis.return_value)

@patch("tc_hivemind_backend.db.redis.Credentials")
@patch("redis.Redis")
@patch("logging.info")
@patch("logging.error")
def test_successful_connection(
self, mock_error_log, mock_info_log, mock_redis, mock_credentials
):
mock_credentials_instance = MagicMock()
mock_credentials_instance.load_redis.return_value = {
"host": "test_host",
"port": "6379",
"password": "test_password",
}
mock_credentials.return_value = mock_credentials_instance

mock_client = MagicMock()
mock_client.ping.return_value = True
mock_redis.return_value = mock_client

RedisSingleton.get_instance()

mock_info_log.assert_called_once_with(
"Redis Connected Successfully! Ping returned: True"
)
mock_error_log.assert_not_called()

@patch("tc_hivemind_backend.db.redis.Credentials")
@patch("redis.Redis")
@patch("logging.info")
@patch("logging.error")
def test_failed_connection(
self, mock_error_log, mock_info_log, mock_redis, mock_credentials
):
mock_credentials_instance = MagicMock()
mock_credentials_instance.load_redis.return_value = {
"host": "test_host",
"port": "6379",
"password": "test_password",
}
mock_credentials.return_value = mock_credentials_instance

mock_client = MagicMock()
mock_client.ping.side_effect = Exception("Connection failed")
mock_redis.return_value = mock_client

RedisSingleton.get_instance()

mock_error_log.assert_called_once_with(
"Redis not connected! exp: Connection failed"
)
mock_info_log.assert_not_called()

@patch("tc_hivemind_backend.db.redis.Credentials")
def test_credentials_loading_error(self, mock_credentials):
mock_credentials_instance = MagicMock()
mock_credentials_instance.load_redis.side_effect = Exception(
"Failed to load credentials"
)
mock_credentials.return_value = mock_credentials_instance

with self.assertRaises(Exception) as context:
RedisSingleton.get_instance()
self.assertEqual(str(context.exception), "Failed to load credentials")


if __name__ == "__main__":
unittest.main()

0 comments on commit 3ab6239

Please sign in to comment.