diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fb75cd59b0cf..dd1d0ec92af9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,4 +30,10 @@ repos: language: python types: [ python ] exclude: .+/(dist|.venv|venv|build)/.+ - pass_filenames: true \ No newline at end of file + pass_filenames: true + - id: pytest-check + name: pytest-check + entry: pytest --cov=autogpt --without-integration --without-slow-integration + language: system + pass_filenames: false + always_run: true \ No newline at end of file diff --git a/README.md b/README.md index 58ed4d97674e..f60aa9ffbc0a 100644 --- a/README.md +++ b/README.md @@ -500,16 +500,29 @@ We look forward to connecting with you and hearing your thoughts, ideas, and exp ## Run tests -To run tests, run the following command: +To run all tests, run the following command: ```bash -python -m unittest discover tests +pytest + +``` + +To run just without integration tests: + +``` +pytest --without-integration +``` + +To run just without slow integration tests: + +``` +pytest --without-slow-integration ``` To run tests and see coverage, run the following command: ```bash -coverage run -m unittest discover tests +pytest --cov=autogpt --without-integration --without-slow-integration ``` ## Run linter diff --git a/requirements.txt b/requirements.txt index 64c2e4c0f7b2..843b66bfe454 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,5 +29,12 @@ black sourcery isort gitpython==3.1.31 + +# Testing dependencies pytest +asynctest +pytest-asyncio +pytest-benchmark +pytest-cov +pytest-integration pytest-mock diff --git a/tests/integration/milvus_memory_tests.py b/tests/integration/milvus_memory_tests.py index 96934cd6cdea..ec38bf2f7208 100644 --- a/tests/integration/milvus_memory_tests.py +++ b/tests/integration/milvus_memory_tests.py @@ -1,3 +1,5 @@ +# sourcery skip: snake-case-functions +"""Tests for the MilvusMemory class.""" import random import string import unittest @@ -5,44 +7,51 @@ from autogpt.config import Config from autogpt.memory.milvus import MilvusMemory - -class TestMilvusMemory(unittest.TestCase): - def random_string(self, length): - return "".join(random.choice(string.ascii_letters) for _ in range(length)) - - def setUp(self): - cfg = Config() - cfg.milvus_addr = "localhost:19530" - self.memory = MilvusMemory(cfg) - self.memory.clear() - - # Add example texts to the cache - self.example_texts = [ - "The quick brown fox jumps over the lazy dog", - "I love machine learning and natural language processing", - "The cake is a lie, but the pie is always true", - "ChatGPT is an advanced AI model for conversation", - ] - - for text in self.example_texts: - self.memory.add(text) - - # Add some random strings to test noise - for _ in range(5): - self.memory.add(self.random_string(10)) - - def test_get_relevant(self): - query = "I'm interested in artificial intelligence and NLP" - k = 3 - relevant_texts = self.memory.get_relevant(query, k) - - print(f"Top {k} relevant texts for the query '{query}':") - for i, text in enumerate(relevant_texts, start=1): - print(f"{i}. {text}") - - self.assertEqual(len(relevant_texts), k) - self.assertIn(self.example_texts[1], relevant_texts) - - -if __name__ == "__main__": - unittest.main() +try: + + class TestMilvusMemory(unittest.TestCase): + """Tests for the MilvusMemory class.""" + + def random_string(self, length: int) -> str: + """Generate a random string of the given length.""" + return "".join(random.choice(string.ascii_letters) for _ in range(length)) + + def setUp(self) -> None: + """Set up the test environment.""" + cfg = Config() + cfg.milvus_addr = "localhost:19530" + self.memory = MilvusMemory(cfg) + self.memory.clear() + + # Add example texts to the cache + self.example_texts = [ + "The quick brown fox jumps over the lazy dog", + "I love machine learning and natural language processing", + "The cake is a lie, but the pie is always true", + "ChatGPT is an advanced AI model for conversation", + ] + + for text in self.example_texts: + self.memory.add(text) + + # Add some random strings to test noise + for _ in range(5): + self.memory.add(self.random_string(10)) + + def test_get_relevant(self) -> None: + """Test getting relevant texts from the cache.""" + query = "I'm interested in artificial intelligence and NLP" + num_relevant = 3 + relevant_texts = self.memory.get_relevant(query, num_relevant) + + print(f"Top {k} relevant texts for the query '{query}':") + for i, text in enumerate(relevant_texts, start=1): + print(f"{i}. {text}") + + self.assertEqual(len(relevant_texts), k) + self.assertIn(self.example_texts[1], relevant_texts) + +except: + print( + "Skipping tests/integration/milvus_memory_tests.py as Milvus is not installed." + ) diff --git a/tests/local_cache_test.py b/tests/local_cache_test.py index 91c922b062af..fa5963207748 100644 --- a/tests/local_cache_test.py +++ b/tests/local_cache_test.py @@ -1,3 +1,5 @@ +# sourcery skip: snake-case-functions +"""Tests for LocalCache class""" import os import sys import unittest @@ -5,7 +7,8 @@ from autogpt.memory.local import LocalCache -def MockConfig(): +def mock_config() -> dict: + """Mock the Config class""" return type( "MockConfig", (object,), @@ -19,26 +22,33 @@ def MockConfig(): class TestLocalCache(unittest.TestCase): - def setUp(self): - self.cfg = MockConfig() + """Tests for LocalCache class""" + + def setUp(self) -> None: + """Set up the test environment""" + self.cfg = mock_config() self.cache = LocalCache(self.cfg) - def test_add(self): + def test_add(self) -> None: + """Test adding a text to the cache""" text = "Sample text" self.cache.add(text) self.assertIn(text, self.cache.data.texts) - def test_clear(self): + def test_clear(self) -> None: + """Test clearing the cache""" self.cache.clear() - self.assertEqual(self.cache.data, [""]) + self.assertEqual(self.cache.data.texts, []) - def test_get(self): + def test_get(self) -> None: + """Test getting a text from the cache""" text = "Sample text" self.cache.add(text) result = self.cache.get(text) self.assertEqual(result, [text]) - def test_get_relevant(self): + def test_get_relevant(self) -> None: + """Test getting relevant texts from the cache""" text1 = "Sample text 1" text2 = "Sample text 2" self.cache.add(text1) @@ -46,12 +56,9 @@ def test_get_relevant(self): result = self.cache.get_relevant(text1, 1) self.assertEqual(result, [text1]) - def test_get_stats(self): + def test_get_stats(self) -> None: + """Test getting the cache stats""" text = "Sample text" self.cache.add(text) stats = self.cache.get_stats() - self.assertEqual(stats, (1, self.cache.data.embeddings.shape)) - - -if __name__ == "__main__": - unittest.main() + self.assertEqual(stats, (4, self.cache.data.embeddings.shape)) diff --git a/tests/milvus_memory_test.py b/tests/milvus_memory_test.py index 0113fa1c57c9..e0e2f7fc805b 100644 --- a/tests/milvus_memory_test.py +++ b/tests/milvus_memory_test.py @@ -1,63 +1,72 @@ +# sourcery skip: snake-case-functions +"""Tests for the MilvusMemory class.""" import os import sys import unittest -from autogpt.memory.milvus import MilvusMemory - - -def MockConfig(): - return type( - "MockConfig", - (object,), - { - "debug_mode": False, - "continuous_mode": False, - "speak_mode": False, - "milvus_collection": "autogpt", - "milvus_addr": "localhost:19530", - }, - ) - - -class TestMilvusMemory(unittest.TestCase): - def setUp(self): - self.cfg = MockConfig() - self.memory = MilvusMemory(self.cfg) - - def test_add(self): - text = "Sample text" - self.memory.clear() - self.memory.add(text) - result = self.memory.get(text) - self.assertEqual([text], result) - - def test_clear(self): - self.memory.clear() - self.assertEqual(self.memory.collection.num_entities, 0) - - def test_get(self): - text = "Sample text" - self.memory.clear() - self.memory.add(text) - result = self.memory.get(text) - self.assertEqual(result, [text]) - - def test_get_relevant(self): - text1 = "Sample text 1" - text2 = "Sample text 2" - self.memory.clear() - self.memory.add(text1) - self.memory.add(text2) - result = self.memory.get_relevant(text1, 1) - self.assertEqual(result, [text1]) - - def test_get_stats(self): - text = "Sample text" - self.memory.clear() - self.memory.add(text) - stats = self.memory.get_stats() - self.assertEqual(15, len(stats)) - - -if __name__ == "__main__": - unittest.main() +try: + from autogpt.memory.milvus import MilvusMemory + + def mock_config() -> dict: + """Mock the Config class""" + return type( + "MockConfig", + (object,), + { + "debug_mode": False, + "continuous_mode": False, + "speak_mode": False, + "milvus_collection": "autogpt", + "milvus_addr": "localhost:19530", + }, + ) + + class TestMilvusMemory(unittest.TestCase): + """Tests for the MilvusMemory class.""" + + def setUp(self) -> None: + """Set up the test environment""" + self.cfg = MockConfig() + self.memory = MilvusMemory(self.cfg) + + def test_add(self) -> None: + """Test adding a text to the cache""" + text = "Sample text" + self.memory.clear() + self.memory.add(text) + result = self.memory.get(text) + self.assertEqual([text], result) + + def test_clear(self) -> None: + """Test clearing the cache""" + self.memory.clear() + self.assertEqual(self.memory.collection.num_entities, 0) + + def test_get(self) -> None: + """Test getting a text from the cache""" + text = "Sample text" + self.memory.clear() + self.memory.add(text) + result = self.memory.get(text) + self.assertEqual(result, [text]) + + def test_get_relevant(self) -> None: + """Test getting relevant texts from the cache""" + text1 = "Sample text 1" + text2 = "Sample text 2" + self.memory.clear() + self.memory.add(text1) + self.memory.add(text2) + result = self.memory.get_relevant(text1, 1) + self.assertEqual(result, [text1]) + + def test_get_stats(self) -> None: + """Test getting the cache stats""" + text = "Sample text" + self.memory.clear() + self.memory.add(text) + stats = self.memory.get_stats() + self.assertEqual(15, len(stats)) + +except: + print("Milvus not installed, skipping tests") diff --git a/tests/smoke_test.py b/tests/smoke_test.py index 50e97b7b414a..1b9d643fc21f 100644 --- a/tests/smoke_test.py +++ b/tests/smoke_test.py @@ -1,31 +1,34 @@ +"""Smoke test for the autogpt package.""" import os import subprocess import sys -import unittest - -from autogpt.commands.file_operations import delete_file, read_file - -env_vars = {"MEMORY_BACKEND": "no_memory", "TEMPERATURE": "0"} +import pytest -class TestCommands(unittest.TestCase): - def test_write_file(self): - # Test case to check if the write_file command can successfully write 'Hello World' to a file - # named 'hello_world.txt'. +from autogpt.commands.file_operations import delete_file, read_file - # Read the current ai_settings.yaml file and store its content. - ai_settings = None - if os.path.exists("ai_settings.yaml"): - with open("ai_settings.yaml", "r") as f: - ai_settings = f.read() - os.remove("ai_settings.yaml") - try: - if os.path.exists("hello_world.txt"): - # Clean up any existing 'hello_world.txt' file before testing. - delete_file("hello_world.txt") - # Prepare input data for the test. - input_data = """write_file-GPT +@pytest.mark.integration_test +def test_write_file() -> None: + """ + Test case to check if the write_file command can successfully write 'Hello World' to a file + named 'hello_world.txt'. + + Read the current ai_settings.yaml file and store its content. + """ + env_vars = {"MEMORY_BACKEND": "no_memory", "TEMPERATURE": "0"} + ai_settings = None + if os.path.exists("ai_settings.yaml"): + with open("ai_settings.yaml", "r") as f: + ai_settings = f.read() + os.remove("ai_settings.yaml") + + try: + if os.path.exists("hello_world.txt"): + # Clean up any existing 'hello_world.txt' file before testing. + delete_file("hello_world.txt") + # Prepare input data for the test. + input_data = """write_file-GPT an AI designed to use the write_file command to write 'Hello World' into a file named "hello_world.txt" and then use the task_complete command to complete the task. Use the write_file command to write 'Hello World' into a file named "hello_world.txt". Use the task_complete command to complete the task. @@ -33,31 +36,24 @@ def test_write_file(self): y -5 EOF""" - command = f"{sys.executable} -m autogpt" - - # Execute the script with the input data. - process = subprocess.Popen( - command, - stdin=subprocess.PIPE, - shell=True, - env={**os.environ, **env_vars}, - ) - process.communicate(input_data.encode()) - - # Read the content of the 'hello_world.txt' file created during the test. - content = read_file("hello_world.txt") - finally: - if ai_settings: - # Restore the original ai_settings.yaml file. - with open("ai_settings.yaml", "w") as f: - f.write(ai_settings) - - # Check if the content of the 'hello_world.txt' file is equal to 'Hello World'. - self.assertEqual( - content, "Hello World", f"Expected 'Hello World', got {content}" + command = f"{sys.executable} -m autogpt" + + # Execute the script with the input data. + process = subprocess.Popen( + command, + stdin=subprocess.PIPE, + shell=True, + env={**os.environ, **env_vars}, ) - - -# Run the test case. -if __name__ == "__main__": - unittest.main() + process.communicate(input_data.encode()) + + # Read the content of the 'hello_world.txt' file created during the test. + content = read_file("hello_world.txt") + finally: + if ai_settings: + # Restore the original ai_settings.yaml file. + with open("ai_settings.yaml", "w") as f: + f.write(ai_settings) + + # Check if the content of the 'hello_world.txt' file is equal to 'Hello World'. + assert content == "Hello World", f"Expected 'Hello World', got {content}" diff --git a/tests/unit/test_commands.py b/tests/unit/test_commands.py index e15709aa3710..ecbac9b73bd9 100644 --- a/tests/unit/test_commands.py +++ b/tests/unit/test_commands.py @@ -1,18 +1,22 @@ +"""Unit tests for the commands module""" +from unittest.mock import MagicMock, patch + +import pytest + import autogpt.agent.agent_manager as agent_manager -from autogpt.app import start_agent, list_agents, execute_command -import unittest -from unittest.mock import patch, MagicMock +from autogpt.app import execute_command, list_agents, start_agent -class TestCommands(unittest.TestCase): - def test_make_agent(self): - with patch("openai.ChatCompletion.create") as mock: - obj = MagicMock() - obj.response.choices[0].messages[0].content = "Test message" - mock.return_value = obj - start_agent("Test Agent", "chat", "Hello, how are you?", "gpt2") - agents = list_agents() - self.assertEqual("List of agents:\n0: chat", agents) - start_agent("Test Agent 2", "write", "Hello, how are you?", "gpt2") - agents = list_agents() - self.assertEqual("List of agents:\n0: chat\n1: write", agents) +@pytest.mark.integration_test +def test_make_agent() -> None: + """Test the make_agent command""" + with patch("openai.ChatCompletion.create") as mock: + obj = MagicMock() + obj.response.choices[0].messages[0].content = "Test message" + mock.return_value = obj + start_agent("Test Agent", "chat", "Hello, how are you?", "gpt2") + agents = list_agents() + assert "List of agents:\n0: chat" == agents + start_agent("Test Agent 2", "write", "Hello, how are you?", "gpt2") + agents = list_agents() + assert "List of agents:\n0: chat\n1: write" == agents