tests, model

This commit is contained in:
Evgeny Vakhteev
2023-04-17 20:51:27 -07:00
parent 193c80849f
commit 9fd80a8660
5 changed files with 290 additions and 8 deletions

View File

@@ -6,7 +6,7 @@ from __future__ import annotations
import os import os
from pathlib import Path from pathlib import Path
from typing import Type from typing import Type, Optional
import yaml import yaml
from autogpt.prompts.generator import PromptGenerator from autogpt.prompts.generator import PromptGenerator

View File

@@ -1,5 +1,4 @@
"""Handles loading of plugins.""" """Handles loading of plugins."""
import zipfile
from typing import Any, Dict, List, Optional, Tuple, TypedDict from typing import Any, Dict, List, Optional, Tuple, TypedDict
from typing import TypeVar from typing import TypeVar
@@ -11,7 +10,7 @@ class Message(TypedDict):
content: str content: str
class BaseOpenAIPluginClient(): class BaseOpenAIPlugin:
""" """
This is a template for Auto-GPT plugins. This is a template for Auto-GPT plugins.
""" """

View File

@@ -14,7 +14,7 @@ from abstract_singleton import AbstractSingleton
from openapi_python_client.cli import Config as OpenAPIConfig from openapi_python_client.cli import Config as OpenAPIConfig
from autogpt.config import Config from autogpt.config import Config
from autogpt.models.base_open_ai_plugin import BaseOpenAIPluginClient from autogpt.models.base_open_ai_plugin import BaseOpenAIPlugin
def inspect_zip_for_module(zip_path: str, debug: bool = False) -> Optional[str]: def inspect_zip_for_module(zip_path: str, debug: bool = False) -> Optional[str]:
@@ -160,18 +160,18 @@ def initialize_openai_plugins(manifests_specs: dict, cfg: Config, debug: bool =
def instantiate_openai_plugin_clients(manifests_specs_clients: dict, cfg: Config, debug: bool = False) -> dict: def instantiate_openai_plugin_clients(manifests_specs_clients: dict, cfg: Config, debug: bool = False) -> dict:
""" """
Instantiates BaseOpenAIPluginClient instances for each OpenAI plugin. Instantiates BaseOpenAIPlugin instances for each OpenAI plugin.
Args: Args:
manifests_specs_clients (dict): per url dictionary of manifest, spec and client. manifests_specs_clients (dict): per url dictionary of manifest, spec and client.
cfg (Config): Config instance including plugins config cfg (Config): Config instance including plugins config
debug (bool, optional): Enable debug logging. Defaults to False. debug (bool, optional): Enable debug logging. Defaults to False.
Returns: Returns:
plugins (dict): per url dictionary of BaseOpenAIPluginClient instances. plugins (dict): per url dictionary of BaseOpenAIPlugin instances.
""" """
plugins = {} plugins = {}
for url, manifest_spec_client in manifests_specs_clients.items(): for url, manifest_spec_client in manifests_specs_clients.items():
plugins[url] = BaseOpenAIPluginClient(manifest_spec_client) plugins[url] = BaseOpenAIPlugin(manifest_spec_client)
return plugins return plugins
@@ -197,7 +197,7 @@ def scan_plugins(cfg: Config, debug: bool = False) -> List[Tuple[str, Path]]:
if manifests_specs.keys(): if manifests_specs.keys():
manifests_specs_clients = initialize_openai_plugins(manifests_specs, cfg, debug) manifests_specs_clients = initialize_openai_plugins(manifests_specs, cfg, debug)
for url, openai_plugin_meta in manifests_specs_clients.items(): for url, openai_plugin_meta in manifests_specs_clients.items():
plugin = BaseOpenAIPluginClient(openai_plugin_meta) plugin = BaseOpenAIPlugin(openai_plugin_meta)
plugins.append((plugin, url)) plugins.append((plugin, url))
return plugins return plugins

View File

@@ -0,0 +1,61 @@
import pytest
from typing import Any, Dict, List, Optional, Tuple
from autogpt.models.base_open_ai_plugin import BaseOpenAIPlugin, Message, PromptGenerator
class DummyPlugin(BaseOpenAIPlugin):
pass
@pytest.fixture
def dummy_plugin():
manifests_specs_clients = {
"manifest": {
"name_for_model": "Dummy",
"schema_version": "1.0",
"description_for_model": "A dummy plugin for testing purposes"
},
"client": None,
"openapi_spec": None
}
return DummyPlugin(manifests_specs_clients)
def test_dummy_plugin_inheritance(dummy_plugin):
assert isinstance(dummy_plugin, BaseOpenAIPlugin)
def test_dummy_plugin_name(dummy_plugin):
assert dummy_plugin._name == "Dummy"
def test_dummy_plugin_version(dummy_plugin):
assert dummy_plugin._version == "1.0"
def test_dummy_plugin_description(dummy_plugin):
assert dummy_plugin._description == "A dummy plugin for testing purposes"
def test_dummy_plugin_default_methods(dummy_plugin):
assert not dummy_plugin.can_handle_on_response()
assert not dummy_plugin.can_handle_post_prompt()
assert not dummy_plugin.can_handle_on_planning()
assert not dummy_plugin.can_handle_post_planning()
assert not dummy_plugin.can_handle_pre_instruction()
assert not dummy_plugin.can_handle_on_instruction()
assert not dummy_plugin.can_handle_post_instruction()
assert not dummy_plugin.can_handle_pre_command()
assert not dummy_plugin.can_handle_post_command()
assert not dummy_plugin.can_handle_chat_completion(None, None, None, None)
assert dummy_plugin.on_response(None) is None
assert dummy_plugin.post_prompt(None) is None
assert dummy_plugin.on_planning(None, None) is None
assert dummy_plugin.post_planning(None) is None
assert dummy_plugin.pre_instruction(None) is None
assert dummy_plugin.on_instruction(None) is None
assert dummy_plugin.post_instruction(None) is None
assert dummy_plugin.pre_command(None, None) is None
assert dummy_plugin.post_command(None, None) is None
assert dummy_plugin.handle_chat_completion(None, None, None, None) is None

View File

@@ -0,0 +1,222 @@
import json
import os
import tempfile
import zipfile
from pathlib import Path
from urllib.parse import urlparse
from unittest.mock import MagicMock, patch
import pytest
from autogpt.plugins import create_directory_if_not_exists, inspect_zip_for_module, load_plugins, \
blacklist_whitelist_check, instantiate_openai_plugin_clients, scan_plugins, fetch_openai_plugins_manifest_and_spec, \
initialize_openai_plugins
PLUGINS_TEST_DIR = "tests/unit/data/test_plugins"
PLUGIN_TEST_ZIP_FILE = "Auto-GPT-Plugin-Test-master.zip"
PLUGIN_TEST_INIT_PY = "Auto-GPT-Plugin-Test-master/src/auto_gpt_plugin_template/__init__.py"
def test_inspect_zip_for_module():
with tempfile.TemporaryDirectory() as temp_dir:
zip_path = os.path.join(temp_dir, "sample.zip")
with zipfile.ZipFile(zip_path, "w") as zf:
zf.writestr("test_module/__init__.py", "")
result = plugins.inspect_zip_for_module(zip_path)
assert result == "test_module/__init__.py"
result = plugins.inspect_zip_for_module(zip_path, debug=True)
assert result == "test_module/__init__.py"
with zipfile.ZipFile(zip_path, "w") as zf:
zf.writestr("not_a_module.py", "")
result = plugins.inspect_zip_for_module(zip_path)
assert result is None
def test_write_dict_to_json_file():
with tempfile.NamedTemporaryFile(mode="w+", delete=False) as file:
test_data = {"test_key": "test_value"}
plugins.write_dict_to_json_file(test_data, file.name)
file.seek(0)
loaded_data = json.load(file)
assert loaded_data == test_data
def test_create_directory_if_not_exists():
with tempfile.TemporaryDirectory() as temp_dir:
new_dir = os.path.join(temp_dir, "test_dir")
assert not os.path.exists(new_dir)
result = create_directory_if_not_exists(new_dir)
assert result is True
assert os.path.exists(new_dir)
result = create_directory_if_not_exists(new_dir)
assert result is True
@pytest.fixture
def config_mock():
config = MagicMock()
config.plugins_dir = "/plugins"
config.plugins_openai = []
return config
@patch("autogpt.plugins.write_dict_to_json_file")
@patch("requests.get")
@patch("autogpt.plugins.create_directory_if_not_exists")
def test_fetch_openai_plugins_manifest_and_spec(create_directory_mock, write_dict_mock, requests_get_mock, config_mock):
requests_get_mock.side_effect = [
MagicMock(status_code=200, json=lambda: {
"schema_version": "v1",
"api": {"type": "openapi", "url": "http://example.com/openapi.json"}
}),
MagicMock(status_code=404),
]
config_mock.plugins_openai = ["http://example.com"]
result = fetch_openai_plugins_manifest_and_spec(config_mock)
assert len(result) == 1
assert "http://example.com" in result
assert "manifest" in result["http://example.com"]
assert "openapi_spec" in result["http://example.com"]
create_directory_mock.assert_called_once()
write_dict_mock.assert_called_once()
requests_get_mock.assert_has_calls([
patch("requests.get", args=("http://example.com/.well-known/ai-plugin.json",)),
patch("requests.get", args=("http://example.com/openapi.json",)),
])
# @patch("BaseOpenAIPlugin")
# def test_instantiate_openai_plugin_clients(base_openai_plugin_client_mock, config_mock):
# manifests_specs_clients = {
# "http://example.com": {
# "manifest": {},
# "openapi_spec": {},
# "client": MagicMock(),
# }
# }
#
# result = instantiate_openai_plugin_clients(manifests_specs_clients, config_mock)
# assert len(result) == 1
def test_scan_plugins(config_mock):
with patch("inspect_zip_for_module", return_value="test_module/__init__.py"):
plugins = scan_plugins(config_mock)
assert len(plugins) == 0
# @patch("BaseOpenAIPlugin")
# def test_initialize_openai_plugins(base_openai_plugin_client_mock, config_mock):
# manifests_specs = {
# "http://example.com": {
# "manifest": {},
# "openapi_spec": {},
# }
# }
#
# with patch("Path.cwd") as cwd_mock:
# cwd_mock.return_value = Path("/fake_cwd")
# result = initialize_openai_plugins(manifests_specs, config_mock)
# assert len(result) == 1
# assert "http://example.com" in result
# assert "client" in result["http://example.com"]
def test_blacklist_whitelist_check(config_mock):
class Plugin1(MagicMock):
__name__ = "Plugin1"
class Plugin2(MagicMock):
__name__ = "Plugin2"
config_mock.plugins_blacklist = ["Plugin1"]
config_mock.plugins_whitelist = ["Plugin2"]
plugins = [Plugin1, Plugin2]
result = blacklist_whitelist_check(plugins, config_mock)
assert len(result) == 1
assert isinstance(result[0], Plugin2)
config_mock.plugins_blacklist = []
config_mock.plugins_whitelist = []
with patch("builtins.input", side_effect=["y", "n"]):
result = blacklist_whitelist_check(plugins, config_mock)
assert len(result) == 1
assert isinstance(result[0], Plugin1)
@patch("autogpt.plugins.scan_plugins")
@patch("autogpt.plugins.blacklist_whitelist_check")
def test_load_plugins(blacklist_whitelist_check_mock, scan_plugins_mock, config_mock):
load_plugins(cfg=config_mock, debug=True)
scan_plugins_mock.assert_called_once_with(config_mock)
blacklist_whitelist_check_mock.assert_called_once_with(scan_plugins_mock.return_value, config_mock)
def test_inspect_zip_for_module_no_init_py():
with patch("zipfile.ZipFile") as zip_mock:
zip_mock.return_value.__enter__.return_value.namelist.return_value = ["test_module/file1.py"]
result = inspect_zip_for_module("test_module.zip")
assert result is None
def test_create_directory_if_not_exists_error():
with patch("os.makedirs") as makedirs_mock:
makedirs_mock.side_effect = OSError("Error creating directory")
result = create_directory_if_not_exists("non_existent_dir")
assert result is False
def test_fetch_openai_plugins_manifest_and_spec_invalid_manifest():
with patch("requests.get") as get_mock:
get_mock.return_value.status_code = 200
get_mock.return_value.json.return_value = {
"schema_version": "v2",
"api": {"type": "openapi"},
}
config = MagicMock()
config.plugins_openai = ["http://example.com"]
result = fetch_openai_plugins_manifest_and_spec(config)
assert result == {}
# @patch("BaseOpenAIPlugin")
# def test_instantiate_openai_plugin_clients_invalid_input(base_openai_plugin_client_mock):
# with pytest.raises(TypeError):
# instantiate_openai_plugin_clients("invalid_input", MagicMock())
def test_scan_plugins_invalid_config():
with pytest.raises(AttributeError):
scan_plugins("invalid_config")
def test_blacklist_whitelist_check_invalid_plugins_input():
with pytest.raises(TypeError):
blacklist_whitelist_check("invalid_plugins_input", MagicMock())
def test_blacklist_whitelist_check_invalid_config_input():
with pytest.raises(TypeError):
blacklist_whitelist_check([], "invalid_config_input")
def test_load_plugins_invalid_config_input():
with pytest.raises(TypeError):
load_plugins("invalid_config_input")