mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-04-30 11:26:23 +02:00
Merge branch 'main' into incremental_development
# Conflicts: # metagpt/schema.py
This commit is contained in:
commit
e1b783ca14
127 changed files with 2346 additions and 648 deletions
|
|
@ -117,7 +117,6 @@ if __name__ == '__main__':
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_debug_error():
|
||||
CONFIG.src_workspace = CONFIG.git_repo.workdir / uuid.uuid4().hex
|
||||
ctx = RunCodeContext(
|
||||
|
|
@ -150,5 +149,16 @@ async def test_debug_error():
|
|||
rsp = await debug_error.run()
|
||||
|
||||
assert "class Player" in rsp # rewrite the same class
|
||||
# a key logic to rewrite to (original one is "if self.score > 12")
|
||||
# Problematic code:
|
||||
# ```
|
||||
# if self.score > 21 and any(card.rank == 'A' for card in self.hand):
|
||||
# self.score -= 10
|
||||
# ```
|
||||
# Should rewrite to (used "gpt-3.5-turbo-1106"):
|
||||
# ```
|
||||
# ace_count = sum(1 for card in self.hand if card.rank == 'A')
|
||||
# while self.score > 21 and ace_count > 0:
|
||||
# self.score -= 10
|
||||
# ace_count -= 1
|
||||
# ```
|
||||
assert "while self.score > 21" in rsp
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ from tests.metagpt.actions.mock_markdown import PRD_SAMPLE
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_design_api():
|
||||
inputs = ["我们需要一个音乐播放器,它应该有播放、暂停、上一曲、下一曲等功能。", PRD_SAMPLE]
|
||||
for prd in inputs:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from metagpt.actions.design_api_review import DesignReview
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_design_api_review():
|
||||
prd = "我们需要一个音乐播放器,它应该有播放、暂停、上一曲、下一曲等功能。"
|
||||
api_design = """
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ context = """
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_generate_questions():
|
||||
action = GenerateQuestions()
|
||||
rsp = await action.run(context)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ async def test_generate_table(invoice_path: Path, expected_result: dict):
|
|||
("invoice_path", "query", "expected_result"),
|
||||
[(Path("invoices/invoice-1.pdf"), "Invoicing date", "2023年02月03日")],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_reply_question(invoice_path: Path, query: dict, expected_result: str):
|
||||
invoice_path = TEST_DATA_PATH / invoice_path
|
||||
ocr_result = await InvoiceOCR().run(file_path=Path(invoice_path))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ from metagpt.logs import logger
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_prepare_interview():
|
||||
action = PrepareInterview()
|
||||
rsp = await action.run("I just graduated and hope to find a job as a Python engineer")
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ from tests.metagpt.actions.mock_json import DESIGN, PRD
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_design_api():
|
||||
await FileRepository.save_file("1.txt", content=str(PRD), relative_path=PRDS_FILE_REPO)
|
||||
await FileRepository.save_file("1.txt", content=str(DESIGN), relative_path=SYSTEM_DESIGN_FILE_REPO)
|
||||
|
|
|
|||
|
|
@ -11,13 +11,46 @@ from pathlib import Path
|
|||
import pytest
|
||||
|
||||
from metagpt.actions.rebuild_class_view import RebuildClassView
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import GRAPH_REPO_FILE_REPO
|
||||
from metagpt.llm import LLM
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_rebuild():
|
||||
action = RebuildClassView(name="RedBean", context=Path(__file__).parent.parent, llm=LLM())
|
||||
action = RebuildClassView(
|
||||
name="RedBean", context=str(Path(__file__).parent.parent.parent.parent / "metagpt"), llm=LLM()
|
||||
)
|
||||
await action.run()
|
||||
graph_file_repo = CONFIG.git_repo.new_file_repository(relative_path=GRAPH_REPO_FILE_REPO)
|
||||
assert graph_file_repo.changed_files
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("path", "direction", "diff", "want"),
|
||||
[
|
||||
("metagpt/startup.py", "=", ".", "metagpt/startup.py"),
|
||||
("metagpt/startup.py", "+", "MetaGPT", "MetaGPT/metagpt/startup.py"),
|
||||
("metagpt/startup.py", "-", "metagpt", "startup.py"),
|
||||
],
|
||||
)
|
||||
def test_align_path(path, direction, diff, want):
|
||||
res = RebuildClassView._align_root(path=path, direction=direction, diff_path=diff)
|
||||
assert res == want
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("path_root", "package_root", "want_direction", "want_diff"),
|
||||
[
|
||||
("/Users/x/github/MetaGPT/metagpt", "/Users/x/github/MetaGPT/metagpt", "=", "."),
|
||||
("/Users/x/github/MetaGPT", "/Users/x/github/MetaGPT/metagpt", "-", "metagpt"),
|
||||
("/Users/x/github/MetaGPT/metagpt", "/Users/x/github/MetaGPT", "+", "metagpt"),
|
||||
],
|
||||
)
|
||||
def test_diff_path(path_root, package_root, want_direction, want_diff):
|
||||
direction, diff = RebuildClassView._diff_path(path_root=Path(path_root), package_root=Path(package_root))
|
||||
assert direction == want_direction
|
||||
assert diff == want_diff
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
55
tests/metagpt/actions/test_rebuild_sequence_view.py
Normal file
55
tests/metagpt/actions/test_rebuild_sequence_view.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2024/1/4
|
||||
@Author : mashenquan
|
||||
@File : test_rebuild_sequence_view.py
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from metagpt.actions.rebuild_sequence_view import RebuildSequenceView
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import GRAPH_REPO_FILE_REPO
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.utils.common import aread
|
||||
from metagpt.utils.file_repository import FileRepository
|
||||
from metagpt.utils.git_repository import ChangeType
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_rebuild():
|
||||
# Mock
|
||||
data = await aread(filename=Path(__file__).parent / "../../data/graph_db/networkx.json")
|
||||
graph_db_filename = Path(CONFIG.git_repo.workdir.name).with_suffix(".json")
|
||||
await FileRepository.save_file(
|
||||
filename=str(graph_db_filename),
|
||||
relative_path=GRAPH_REPO_FILE_REPO,
|
||||
content=data,
|
||||
)
|
||||
CONFIG.git_repo.add_change({f"{GRAPH_REPO_FILE_REPO}/{graph_db_filename}": ChangeType.UNTRACTED})
|
||||
CONFIG.git_repo.commit("commit1")
|
||||
|
||||
action = RebuildSequenceView(
|
||||
name="RedBean", context=str(Path(__file__).parent.parent.parent.parent / "metagpt"), llm=LLM()
|
||||
)
|
||||
await action.run()
|
||||
graph_file_repo = CONFIG.git_repo.new_file_repository(relative_path=GRAPH_REPO_FILE_REPO)
|
||||
assert graph_file_repo.changed_files
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("root", "pathname", "want"),
|
||||
[
|
||||
(Path(__file__).parent.parent.parent, "/".join(__file__.split("/")[-2:]), Path(__file__)),
|
||||
(Path(__file__).parent.parent.parent, "f/g.txt", None),
|
||||
],
|
||||
)
|
||||
def test_get_full_filename(root, pathname, want):
|
||||
res = RebuildSequenceView._get_full_filename(root=root, pathname=pathname)
|
||||
assert res == want
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-s"])
|
||||
|
|
@ -8,14 +8,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from metagpt.actions import CollectLinks, research
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_action():
|
||||
action = CollectLinks()
|
||||
result = await action.run(topic="baidu")
|
||||
assert result
|
||||
from metagpt.actions import research
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -47,7 +47,10 @@ class TestSkillAction:
|
|||
assert args.get("size_type") == "512x512"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parser_action(self):
|
||||
async def test_parser_action(self, mocker):
|
||||
# mock
|
||||
mocker.patch("metagpt.learn.text_to_image", return_value="https://mock.com/xxx")
|
||||
|
||||
parser_action = ArgumentsParingAction(skill=self.skill, ask="Draw an apple")
|
||||
rsp = await parser_action.run()
|
||||
assert rsp
|
||||
|
|
@ -80,7 +83,8 @@ class TestSkillAction:
|
|||
@pytest.mark.asyncio
|
||||
async def test_skill_action_error(self):
|
||||
action = SkillAction(skill=self.skill, args={})
|
||||
await action.run()
|
||||
rsp = await action.run()
|
||||
assert "Error" in rsp.content
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ class Snake:
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_summarize_code():
|
||||
CONFIG.src_workspace = CONFIG.git_repo.workdir / "src"
|
||||
await FileRepository.save_file(filename="1.json", relative_path=SYSTEM_DESIGN_FILE_REPO, content=DESIGN_CONTENT)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ from metagpt.schema import Message
|
|||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_prompt(agent_description, language, context, knowledge, history_summary):
|
||||
# Prerequisites
|
||||
CONFIG.agent_description = agent_description
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ from tests.metagpt.actions.mock_markdown import TASKS_2, WRITE_CODE_PROMPT_SAMPL
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_code():
|
||||
context = CodingContext(
|
||||
filename="task_filename.py", design_doc=Document(content="设计一个名为'add'的函数,该函数接受两个整数作为输入,并返回它们的和。")
|
||||
|
|
@ -45,7 +44,6 @@ async def test_write_code():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_code_directly():
|
||||
prompt = WRITE_CODE_PROMPT_SAMPLE + "\n" + TASKS_2[0]
|
||||
llm = LLM()
|
||||
|
|
@ -54,7 +52,6 @@ async def test_write_code_directly():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_code_deps():
|
||||
# Prerequisites
|
||||
CONFIG.src_workspace = CONFIG.git_repo.workdir / "snake1/snake1"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ from metagpt.schema import CodingContext, Document
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_code_review(capfd):
|
||||
code = """
|
||||
def add(a, b):
|
||||
|
|
|
|||
|
|
@ -27,14 +27,12 @@ class Person:
|
|||
],
|
||||
ids=["google", "numpy", "sphinx"],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_docstring(style: str, part: str):
|
||||
ret = await WriteDocstring().run(code, style=style)
|
||||
assert part in ret
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write():
|
||||
code = await WriteDocstring.write_docstring(__file__)
|
||||
assert code
|
||||
|
|
|
|||
|
|
@ -8,22 +8,25 @@
|
|||
"""
|
||||
import pytest
|
||||
|
||||
from metagpt.actions import UserRequirement
|
||||
from metagpt.actions import UserRequirement, WritePRD
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import DOCS_FILE_REPO, PRDS_FILE_REPO, REQUIREMENT_FILENAME
|
||||
from metagpt.logs import logger
|
||||
from metagpt.roles.product_manager import ProductManager
|
||||
from metagpt.roles.role import RoleReactMode
|
||||
from metagpt.schema import Message
|
||||
from metagpt.utils.common import any_to_str
|
||||
from metagpt.utils.file_repository import FileRepository
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_prd():
|
||||
async def test_write_prd(new_filename):
|
||||
product_manager = ProductManager()
|
||||
requirements = "开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结"
|
||||
await FileRepository.save_file(filename=REQUIREMENT_FILENAME, content=requirements, relative_path=DOCS_FILE_REPO)
|
||||
product_manager.rc.react_mode = RoleReactMode.BY_ORDER
|
||||
prd = await product_manager.run(Message(content=requirements, cause_by=UserRequirement))
|
||||
assert prd.cause_by == any_to_str(WritePRD)
|
||||
logger.info(requirements)
|
||||
logger.info(prd)
|
||||
|
||||
|
|
@ -31,3 +34,7 @@ async def test_write_prd():
|
|||
assert prd is not None
|
||||
assert prd.content != ""
|
||||
assert CONFIG.git_repo.new_file_repository(relative_path=PRDS_FILE_REPO).changed_files
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-s"])
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from metagpt.actions.write_prd_review import WritePRDReview
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_prd_review():
|
||||
prd = """
|
||||
Introduction: This is a new feature for our product.
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ CONTEXT = """
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_review():
|
||||
write_review = WriteReview()
|
||||
review = await write_review.run(CONTEXT)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ from metagpt.actions.write_teaching_plan import WriteTeachingPlanPart
|
|||
("topic", "context"),
|
||||
[("Title", "Lesson 1: Learn to draw an apple."), ("Teaching Content", "Lesson 1: Learn to draw an apple.")],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_teaching_plan_part(topic, context):
|
||||
action = WriteTeachingPlanPart(topic=topic, context=context)
|
||||
rsp = await action.run()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ from metagpt.schema import Document, TestingContext
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_test():
|
||||
code = """
|
||||
import random
|
||||
|
|
@ -40,7 +39,6 @@ async def test_write_test():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_code_invalid_code(mocker):
|
||||
# Mock the _aask method to return an invalid code string
|
||||
mocker.patch.object(WriteTest, "_aask", return_value="Invalid Code String")
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ from metagpt.actions.write_tutorial import WriteContent, WriteDirectory
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(("language", "topic"), [("English", "Write a tutorial about Python")])
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_directory(language: str, topic: str):
|
||||
ret = await WriteDirectory(language=language).run(topic=topic)
|
||||
assert isinstance(ret, dict)
|
||||
|
|
@ -30,7 +29,6 @@ async def test_write_directory(language: str, topic: str):
|
|||
("language", "topic", "directory"),
|
||||
[("English", "Write a tutorial about Python", {"Introduction": ["What is Python?", "Why learn Python?"]})],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_content(language: str, topic: str, directory: Dict):
|
||||
ret = await WriteContent(language=language, directory=directory).run(topic=topic)
|
||||
assert isinstance(ret, str)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,16 @@ points = [
|
|||
]
|
||||
|
||||
|
||||
def assert_almost_equal(actual, expected):
|
||||
delta = 1e-10
|
||||
if isinstance(expected, list):
|
||||
assert len(actual) == len(expected)
|
||||
for ac, exp in zip(actual, expected):
|
||||
assert abs(ac - exp) <= delta, f"{ac} is not within {delta} of {exp}"
|
||||
else:
|
||||
assert abs(actual - expected) <= delta, f"{actual} is not within {delta} of {expected}"
|
||||
|
||||
|
||||
def test_qdrant_store():
|
||||
qdrant_connection = QdrantConnection(memory=True)
|
||||
vectors_config = VectorParams(size=2, distance=Distance.COSINE)
|
||||
|
|
@ -42,30 +52,30 @@ def test_qdrant_store():
|
|||
qdrant_store.add("Book", points)
|
||||
results = qdrant_store.search("Book", query=[1.0, 1.0])
|
||||
assert results[0]["id"] == 2
|
||||
assert results[0]["score"] == 0.999106722578389
|
||||
assert_almost_equal(results[0]["score"], 0.999106722578389)
|
||||
assert results[1]["id"] == 7
|
||||
assert results[1]["score"] == 0.9961650411397226
|
||||
assert_almost_equal(results[1]["score"], 0.9961650411397226)
|
||||
results = qdrant_store.search("Book", query=[1.0, 1.0], return_vector=True)
|
||||
assert results[0]["id"] == 2
|
||||
assert results[0]["score"] == 0.999106722578389
|
||||
assert results[0]["vector"] == [0.7363563179969788, 0.6765939593315125]
|
||||
assert_almost_equal(results[0]["score"], 0.999106722578389)
|
||||
assert_almost_equal(results[0]["vector"], [0.7363563179969788, 0.6765939593315125])
|
||||
assert results[1]["id"] == 7
|
||||
assert results[1]["score"] == 0.9961650411397226
|
||||
assert results[1]["vector"] == [0.7662628889083862, 0.6425272226333618]
|
||||
assert_almost_equal(results[1]["score"], 0.9961650411397226)
|
||||
assert_almost_equal(results[1]["vector"], [0.7662628889083862, 0.6425272226333618])
|
||||
results = qdrant_store.search(
|
||||
"Book",
|
||||
query=[1.0, 1.0],
|
||||
query_filter=Filter(must=[FieldCondition(key="rand_number", range=Range(gte=8))]),
|
||||
)
|
||||
assert results[0]["id"] == 8
|
||||
assert results[0]["score"] == 0.9100373450784073
|
||||
assert_almost_equal(results[0]["score"], 0.9100373450784073)
|
||||
assert results[1]["id"] == 9
|
||||
assert results[1]["score"] == 0.7127610621127889
|
||||
assert_almost_equal(results[1]["score"], 0.7127610621127889)
|
||||
results = qdrant_store.search(
|
||||
"Book",
|
||||
query=[1.0, 1.0],
|
||||
query_filter=Filter(must=[FieldCondition(key="rand_number", range=Range(gte=8))]),
|
||||
return_vector=True,
|
||||
)
|
||||
assert results[0]["vector"] == [0.35037919878959656, 0.9366079568862915]
|
||||
assert results[1]["vector"] == [0.9999677538871765, 0.00802854634821415]
|
||||
assert_almost_equal(results[0]["vector"], [0.35037919878959656, 0.9366079568862915])
|
||||
assert_almost_equal(results[1]["vector"], [0.9999677538871765, 0.00802854634821415])
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
@File : test_skill_loader.py
|
||||
@Desc : Unit tests.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
|
|
@ -23,7 +25,8 @@ async def test_suite():
|
|||
{"id": 6, "name": "knowledge", "type": "builtin", "config": {}, "enabled": True},
|
||||
{"id": 6, "name": "web_search", "type": "builtin", "config": {}, "enabled": True},
|
||||
]
|
||||
loader = await SkillsDeclaration.load()
|
||||
pathname = Path(__file__).parent / "../../../docs/.well-known/skills.yaml"
|
||||
loader = await SkillsDeclaration.load(skill_yaml_file_name=pathname)
|
||||
skills = loader.get_skill_list()
|
||||
assert skills
|
||||
assert len(skills) >= 3
|
||||
|
|
|
|||
|
|
@ -12,10 +12,18 @@ import pytest
|
|||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.learn.text_to_image import text_to_image
|
||||
from metagpt.tools.metagpt_text_to_image import MetaGPTText2Image
|
||||
from metagpt.tools.openai_text_to_image import OpenAIText2Image
|
||||
from metagpt.utils.s3 import S3
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_metagpt_llm():
|
||||
async def test_text_to_image(mocker):
|
||||
# mock
|
||||
mocker.patch.object(MetaGPTText2Image, "text_2_image", return_value=b"mock MetaGPTText2Image")
|
||||
mocker.patch.object(OpenAIText2Image, "text_2_image", return_value=b"mock OpenAIText2Image")
|
||||
mocker.patch.object(S3, "cache", return_value="http://mock/s3")
|
||||
|
||||
# Prerequisites
|
||||
assert CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL
|
||||
assert CONFIG.OPENAI_API_KEY
|
||||
|
|
|
|||
8
tests/metagpt/provider/conftest.py
Normal file
8
tests/metagpt/provider/conftest.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def llm_mock(rsp_cache, mocker, request):
|
||||
# An empty fixture to overwrite the global llm_mock fixture
|
||||
# because in provider folder, we want to test the aask and aask functions for the specific models
|
||||
pass
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
# @Desc : the unittest of ZhiPuAILLM
|
||||
|
||||
import pytest
|
||||
from zhipuai.utils.sse_client import Event
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.provider.zhipuai_api import ZhiPuAILLM
|
||||
|
|
@ -15,35 +14,16 @@ messages = [{"role": "user", "content": prompt_msg}]
|
|||
|
||||
resp_content = "I'm chatglm-turbo"
|
||||
default_resp = {
|
||||
"code": 200,
|
||||
"data": {
|
||||
"choices": [{"role": "assistant", "content": resp_content}],
|
||||
"usage": {"prompt_tokens": 20, "completion_tokens": 20},
|
||||
},
|
||||
"choices": [{"finish_reason": "stop", "index": 0, "message": {"content": resp_content, "role": "assistant"}}],
|
||||
"usage": {"completion_tokens": 22, "prompt_tokens": 19, "total_tokens": 41},
|
||||
}
|
||||
|
||||
|
||||
def mock_zhipuai_invoke(**kwargs) -> dict:
|
||||
return default_resp
|
||||
|
||||
|
||||
async def mock_zhipuai_ainvoke(**kwargs) -> dict:
|
||||
return default_resp
|
||||
|
||||
|
||||
async def mock_zhipuai_asse_invoke(**kwargs):
|
||||
async def mock_zhipuai_acreate_stream(self, **kwargs):
|
||||
class MockResponse(object):
|
||||
async def _aread(self):
|
||||
class Iterator(object):
|
||||
events = [
|
||||
Event(id="xxx", event="add", data=resp_content, retry=0),
|
||||
Event(
|
||||
id="xxx",
|
||||
event="finish",
|
||||
data="",
|
||||
meta='{"usage": {"completion_tokens": 20,"prompt_tokens": 20}}',
|
||||
),
|
||||
]
|
||||
events = [{"choices": [{"index": 0, "delta": {"content": resp_content, "role": "assistant"}}]}]
|
||||
|
||||
async def __aiter__(self):
|
||||
for event in self.events:
|
||||
|
|
@ -52,23 +32,26 @@ async def mock_zhipuai_asse_invoke(**kwargs):
|
|||
async for chunk in Iterator():
|
||||
yield chunk
|
||||
|
||||
async def async_events(self):
|
||||
async def stream(self):
|
||||
async for chunk in self._aread():
|
||||
yield chunk
|
||||
|
||||
return MockResponse()
|
||||
|
||||
|
||||
async def mock_zhipuai_acreate(self, **kwargs) -> dict:
|
||||
return default_resp
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_zhipuai_acompletion(mocker):
|
||||
mocker.patch("metagpt.provider.zhipuai.zhipu_model_api.ZhiPuModelAPI.invoke", mock_zhipuai_invoke)
|
||||
mocker.patch("metagpt.provider.zhipuai.zhipu_model_api.ZhiPuModelAPI.ainvoke", mock_zhipuai_ainvoke)
|
||||
mocker.patch("metagpt.provider.zhipuai.zhipu_model_api.ZhiPuModelAPI.asse_invoke", mock_zhipuai_asse_invoke)
|
||||
mocker.patch("metagpt.provider.zhipuai.zhipu_model_api.ZhiPuModelAPI.acreate", mock_zhipuai_acreate)
|
||||
mocker.patch("metagpt.provider.zhipuai.zhipu_model_api.ZhiPuModelAPI.acreate_stream", mock_zhipuai_acreate_stream)
|
||||
|
||||
zhipu_gpt = ZhiPuAILLM()
|
||||
|
||||
resp = await zhipu_gpt.acompletion(messages)
|
||||
assert resp["data"]["choices"][0]["content"] == resp_content
|
||||
assert resp["choices"][0]["message"]["content"] == resp_content
|
||||
|
||||
resp = await zhipu_gpt.aask(prompt_msg, stream=False)
|
||||
assert resp == resp_content
|
||||
|
|
|
|||
|
|
@ -11,16 +11,16 @@ from metagpt.provider.zhipuai.async_sse_client import AsyncSSEClient
|
|||
async def test_async_sse_client():
|
||||
class Iterator(object):
|
||||
async def __aiter__(self):
|
||||
yield b"data: test_value"
|
||||
yield b'data: {"test_key": "test_value"}'
|
||||
|
||||
async_sse_client = AsyncSSEClient(event_source=Iterator())
|
||||
async for event in async_sse_client.async_events():
|
||||
assert event.data, "test_value"
|
||||
async for chunk in async_sse_client.stream():
|
||||
assert "test_value" in chunk.values()
|
||||
|
||||
class InvalidIterator(object):
|
||||
async def __aiter__(self):
|
||||
yield b"invalid: test_value"
|
||||
|
||||
async_sse_client = AsyncSSEClient(event_source=InvalidIterator())
|
||||
async for event in async_sse_client.async_events():
|
||||
assert not event
|
||||
async for chunk in async_sse_client.stream():
|
||||
assert not chunk
|
||||
|
|
|
|||
|
|
@ -6,15 +6,13 @@ from typing import Any, Tuple
|
|||
|
||||
import pytest
|
||||
import zhipuai
|
||||
from zhipuai.model_api.api import InvokeType
|
||||
from zhipuai.utils.http_client import headers as zhipuai_default_headers
|
||||
|
||||
from metagpt.provider.zhipuai.zhipu_model_api import ZhiPuModelAPI
|
||||
|
||||
api_key = "xxx.xxx"
|
||||
zhipuai.api_key = api_key
|
||||
|
||||
default_resp = b'{"result": "test response"}'
|
||||
default_resp = b'{"choices": [{"finish_reason": "stop", "index": 0, "message": {"content": "test response", "role": "assistant"}}]}'
|
||||
|
||||
|
||||
async def mock_requestor_arequest(self, **kwargs) -> Tuple[Any, Any, str]:
|
||||
|
|
@ -23,22 +21,15 @@ async def mock_requestor_arequest(self, **kwargs) -> Tuple[Any, Any, str]:
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_zhipu_model_api(mocker):
|
||||
header = ZhiPuModelAPI.get_header()
|
||||
zhipuai_default_headers.update({"Authorization": api_key})
|
||||
assert header == zhipuai_default_headers
|
||||
|
||||
sse_header = ZhiPuModelAPI.get_sse_header()
|
||||
assert len(sse_header["Authorization"]) == 191
|
||||
|
||||
url_prefix, url_suffix = ZhiPuModelAPI.split_zhipu_api_url(InvokeType.SYNC, kwargs={"model": "chatglm_turbo"})
|
||||
url_prefix, url_suffix = ZhiPuModelAPI(api_key=api_key).split_zhipu_api_url()
|
||||
assert url_prefix == "https://open.bigmodel.cn/api"
|
||||
assert url_suffix == "/paas/v3/model-api/chatglm_turbo/invoke"
|
||||
assert url_suffix == "/paas/v4/chat/completions"
|
||||
|
||||
mocker.patch("metagpt.provider.general_api_requestor.GeneralAPIRequestor.arequest", mock_requestor_arequest)
|
||||
result = await ZhiPuModelAPI.arequest(
|
||||
InvokeType.SYNC, stream=False, method="get", headers={}, kwargs={"model": "chatglm_turbo"}
|
||||
result = await ZhiPuModelAPI(api_key=api_key).arequest(
|
||||
stream=False, method="get", headers={}, kwargs={"model": "glm-3-turbo"}
|
||||
)
|
||||
assert result == default_resp
|
||||
|
||||
result = await ZhiPuModelAPI.ainvoke()
|
||||
assert result["result"] == "test response"
|
||||
result = await ZhiPuModelAPI(api_key=api_key).acreate()
|
||||
assert result["choices"][0]["message"]["content"] == "test response"
|
||||
|
|
|
|||
|
|
@ -284,4 +284,6 @@ class MockMessages:
|
|||
prd = Message(role="Product Manager", content=PRD, cause_by=WritePRD)
|
||||
system_design = Message(role="Architect", content=SYSTEM_DESIGN, cause_by=WriteDesign)
|
||||
tasks = Message(role="Project Manager", content=TASKS, cause_by=WriteTasks)
|
||||
json_tasks = Message(role="Project Manager", content=json.dumps(JSON_TASKS), cause_by=WriteTasks)
|
||||
json_tasks = Message(
|
||||
role="Project Manager", content=json.dumps(JSON_TASKS, ensure_ascii=False), cause_by=WriteTasks
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ from tests.metagpt.roles.mock import MockMessages
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_architect():
|
||||
# Prerequisites
|
||||
filename = uuid.uuid4().hex + ".json"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ from pydantic import BaseModel
|
|||
from metagpt.actions.skill_action import SkillAction
|
||||
from metagpt.actions.talk_action import TalkAction
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
from metagpt.memory.brain_memory import BrainMemory
|
||||
from metagpt.roles.assistant import Assistant
|
||||
from metagpt.schema import Message
|
||||
|
|
@ -21,7 +20,6 @@ from metagpt.utils.common import any_to_str
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_run():
|
||||
CONFIG.language = "Chinese"
|
||||
|
||||
|
|
@ -88,7 +86,7 @@ async def test_run():
|
|||
if not has_action:
|
||||
break
|
||||
msg: Message = await role.act()
|
||||
logger.info(msg)
|
||||
# logger.info(msg)
|
||||
assert msg
|
||||
assert msg.cause_by == seed.cause_by
|
||||
assert msg.content
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ from tests.metagpt.roles.mock import STRS_FOR_PARSING, TASKS, MockMessages
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_engineer():
|
||||
# Prerequisites
|
||||
rqno = "20231221155954.json"
|
||||
|
|
@ -114,7 +113,6 @@ def test_todo():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_new_coding_context():
|
||||
# Prerequisites
|
||||
demo_path = Path(__file__).parent / "../../data/demo_project"
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ from metagpt.schema import Message
|
|||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_invoice_ocr_assistant(query: str, invoice_path: Path, invoice_table_path: Path, expected_result: dict):
|
||||
invoice_path = TEST_DATA_PATH / invoice_path
|
||||
role = InvoiceOCRAssistant()
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ from tests.metagpt.roles.mock import MockMessages
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_product_manager():
|
||||
async def test_product_manager(new_filename):
|
||||
product_manager = ProductManager()
|
||||
rsp = await product_manager.run(MockMessages.req)
|
||||
logger.info(rsp)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ from tests.metagpt.roles.mock import MockMessages
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_project_manager():
|
||||
project_manager = ProjectManager()
|
||||
rsp = await project_manager.run(MockMessages.system_design)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# @Desc : unittest of Role
|
||||
import pytest
|
||||
|
||||
from metagpt.llm import HumanProvider
|
||||
from metagpt.roles.role import Role
|
||||
|
||||
|
||||
|
|
@ -12,5 +13,10 @@ def test_role_desc():
|
|||
assert role.desc == "Best Seller"
|
||||
|
||||
|
||||
def test_role_human():
|
||||
role = Role(is_human=True)
|
||||
assert isinstance(role.llm, HumanProvider)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-s"])
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from metagpt.schema import Message
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skip
|
||||
async def test_init():
|
||||
class Inputs(BaseModel):
|
||||
name: str
|
||||
|
|
@ -103,7 +104,6 @@ async def test_new_file_name():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_run():
|
||||
CONFIG.set_context({"language": "Chinese", "teaching_language": "English"})
|
||||
lesson = """
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ from metagpt.roles.tutorial_assistant import TutorialAssistant
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(("language", "topic"), [("Chinese", "Write a tutorial about pip")])
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_tutorial_assistant(language: str, topic: str):
|
||||
role = TutorialAssistant(language=language)
|
||||
msg = await role.run(topic)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ def test_action_serialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_action_deserialize():
|
||||
action = Action()
|
||||
serialized_data = action.model_dump()
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ def test_architect_serialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_architect_deserialize():
|
||||
role = Architect()
|
||||
ser_role_dict = role.model_dump(by_alias=True)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ from metagpt.actions.prepare_interview import PrepareInterview
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_action_deserialize():
|
||||
action = PrepareInterview()
|
||||
serialized_data = action.model_dump()
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ from metagpt.schema import Message
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_product_manager_deserialize():
|
||||
async def test_product_manager_deserialize(new_filename):
|
||||
role = ProductManager()
|
||||
ser_role_dict = role.model_dump(by_alias=True)
|
||||
new_role = ProductManager(**ser_role_dict)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ def test_project_manager_serialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_project_manager_deserialize():
|
||||
role = ProjectManager()
|
||||
ser_role_dict = role.model_dump(by_alias=True)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ def test_engineer_serialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_engineer_deserialize():
|
||||
role = Engineer(use_code_review=True)
|
||||
ser_role_dict = role.model_dump()
|
||||
|
|
@ -97,7 +96,6 @@ def test_role_serdeser_save():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_role_serdeser_interrupt():
|
||||
role_c = RoleC()
|
||||
shutil.rmtree(SERDESER_PATH.joinpath("team"), ignore_errors=True)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ async def test_team_recover_save():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_team_recover_multi_roles_save():
|
||||
idea = "write a snake game"
|
||||
stg_path = SERDESER_PATH.joinpath("team")
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ def test_write_design_serialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_code_deserialize():
|
||||
context = CodingContext(
|
||||
filename="test_code.py", design_doc=Document(content="write add function to calculate two numbers")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from metagpt.schema import CodingContext, Document
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_code_review_deserialize():
|
||||
code_content = """
|
||||
def div(a: int, b: int = 0):
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ def test_write_task_serialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_design_deserialize():
|
||||
action = WriteDesign()
|
||||
serialized_data = action.model_dump()
|
||||
|
|
@ -32,7 +31,6 @@ async def test_write_design_deserialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_task_deserialize():
|
||||
action = WriteTasks()
|
||||
serialized_data = action.model_dump()
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ class Person:
|
|||
],
|
||||
ids=["google", "numpy", "sphinx"],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_action_deserialize(style: str, part: str):
|
||||
action = WriteDocstring()
|
||||
serialized_data = action.model_dump()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from metagpt.actions import WritePRD
|
|||
from metagpt.schema import Message
|
||||
|
||||
|
||||
def test_action_serialize():
|
||||
def test_action_serialize(new_filename):
|
||||
action = WritePRD()
|
||||
ser_action_dict = action.model_dump()
|
||||
assert "name" in ser_action_dict
|
||||
|
|
@ -17,8 +17,7 @@ def test_action_serialize():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_action_deserialize():
|
||||
async def test_action_deserialize(new_filename):
|
||||
action = WritePRD()
|
||||
serialized_data = action.model_dump()
|
||||
new_action = WritePRD(**serialized_data)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ CONTEXT = """
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_action_deserialize():
|
||||
action = WriteReview()
|
||||
serialized_data = action.model_dump()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from metagpt.actions.write_tutorial import WriteContent, WriteDirectory
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(("language", "topic"), [("English", "Write a tutorial about Python")])
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_directory_deserialize(language: str, topic: str):
|
||||
action = WriteDirectory()
|
||||
serialized_data = action.model_dump()
|
||||
|
|
@ -31,7 +30,6 @@ async def test_write_directory_deserialize(language: str, topic: str):
|
|||
("language", "topic", "directory"),
|
||||
[("English", "Write a tutorial about Python", {"Introduction": ["What is Python?", "Why learn Python?"]})],
|
||||
)
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_write_content_deserialize(language: str, topic: str, directory: Dict):
|
||||
action = WriteContent(language=language, directory=directory)
|
||||
serialized_data = action.model_dump()
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ def test_get_roles(env: Environment):
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_publish_and_process_message(env: Environment):
|
||||
async def test_publish_and_process_message(env: Environment, new_filename):
|
||||
if CONFIG.git_repo:
|
||||
CONFIG.git_repo.delete_repository()
|
||||
CONFIG.git_repo = None
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ from metagpt.config import CONFIG
|
|||
from metagpt.const import SYSTEM_DESIGN_FILE_REPO, TASK_FILE_REPO
|
||||
from metagpt.schema import (
|
||||
AIMessage,
|
||||
ClassAttribute,
|
||||
ClassMethod,
|
||||
ClassView,
|
||||
CodeSummarizeContext,
|
||||
Document,
|
||||
Message,
|
||||
|
|
@ -156,5 +159,30 @@ def test_CodeSummarizeContext(file_list, want):
|
|||
assert want in m
|
||||
|
||||
|
||||
def test_class_view():
|
||||
attr_a = ClassAttribute(name="a", value_type="int", default_value="0", visibility="+", abstraction=True)
|
||||
assert attr_a.get_mermaid(align=1) == "\t+int a=0*"
|
||||
attr_b = ClassAttribute(name="b", value_type="str", default_value="0", visibility="#", static=True)
|
||||
assert attr_b.get_mermaid(align=0) == '#str b="0"$'
|
||||
class_view = ClassView(name="A")
|
||||
class_view.attributes = [attr_a, attr_b]
|
||||
|
||||
method_a = ClassMethod(name="run", visibility="+", abstraction=True)
|
||||
assert method_a.get_mermaid(align=1) == "\t+run()*"
|
||||
method_b = ClassMethod(
|
||||
name="_test",
|
||||
visibility="#",
|
||||
static=True,
|
||||
args=[ClassAttribute(name="a", value_type="str"), ClassAttribute(name="b", value_type="int")],
|
||||
return_type="str",
|
||||
)
|
||||
assert method_b.get_mermaid(align=0) == "#_test(str a,int b):str$"
|
||||
class_view.methods = [method_a, method_b]
|
||||
assert (
|
||||
class_view.get_mermaid(align=0)
|
||||
== 'class A{\n\t+int a=0*\n\t#str b="0"$\n\t+run()*\n\t#_test(str a,int b):str$\n}\n'
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-s"])
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ runner = CliRunner()
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_team():
|
||||
async def test_empty_team(new_filename):
|
||||
# FIXME: we're now using "metagpt" cli, so the entrance should be replaced instead.
|
||||
company = Team()
|
||||
history = await company.run(idea="Build a simple search system. I will upload my files later.")
|
||||
logger.info(history)
|
||||
|
||||
|
||||
def test_startup():
|
||||
def test_startup(new_filename):
|
||||
args = ["Make a cli snake game"]
|
||||
result = runner.invoke(app, args)
|
||||
logger.info(result)
|
||||
|
|
|
|||
|
|
@ -24,13 +24,14 @@ async def test_oas2_svc():
|
|||
process = subprocess.Popen(["python", str(script_pathname)], cwd=str(workdir), env=env)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
url = "http://localhost:8080/openapi/greeting/dave"
|
||||
headers = {"accept": "text/plain", "Content-Type": "application/json"}
|
||||
data = {}
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
assert response.text == "Hello dave\n"
|
||||
|
||||
process.terminate()
|
||||
try:
|
||||
url = "http://localhost:8080/openapi/greeting/dave"
|
||||
headers = {"accept": "text/plain", "Content-Type": "application/json"}
|
||||
data = {}
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
assert response.text == "Hello dave\n"
|
||||
finally:
|
||||
process.terminate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
@Author : mashenquan
|
||||
@File : test_metagpt_text_to_image.py
|
||||
"""
|
||||
import base64
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -13,7 +15,14 @@ from metagpt.tools.metagpt_text_to_image import oas3_metagpt_text_to_image
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_draw():
|
||||
async def test_draw(mocker):
|
||||
# mock
|
||||
mock_post = mocker.patch("aiohttp.ClientSession.post")
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 200
|
||||
mock_response.json.return_value = {"images": [base64.b64encode(b"success")], "parameters": {"size": 1110}}
|
||||
mock_post.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
# Prerequisites
|
||||
assert CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"""
|
||||
@Time : 2023/12/26
|
||||
@Author : mashenquan
|
||||
@File : test_hello.py
|
||||
@File : test_openapi_v3_hello.py
|
||||
"""
|
||||
import asyncio
|
||||
import subprocess
|
||||
|
|
@ -24,13 +24,14 @@ async def test_hello():
|
|||
process = subprocess.Popen(["python", str(script_pathname)], cwd=workdir, env=env)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
url = "http://localhost:8082/openapi/greeting/dave"
|
||||
headers = {"accept": "text/plain", "Content-Type": "application/json"}
|
||||
data = {}
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
assert response.text == "Hello dave\n"
|
||||
|
||||
process.terminate()
|
||||
try:
|
||||
url = "http://localhost:8082/openapi/greeting/dave"
|
||||
headers = {"accept": "text/plain", "Content-Type": "application/json"}
|
||||
data = {}
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
assert response.text == "Hello dave\n"
|
||||
finally:
|
||||
process.terminate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Date : 2023/7/22 02:40
|
||||
# @Author : stellahong (stellahong@deepwisdom.ai)
|
||||
#
|
||||
import os
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.tools.sd_engine import SDEngine
|
||||
|
||||
|
||||
def test_sd_engine_init():
|
||||
sd_engine = SDEngine()
|
||||
assert sd_engine.payload["seed"] == -1
|
||||
|
||||
|
||||
def test_sd_engine_generate_prompt():
|
||||
sd_engine = SDEngine()
|
||||
sd_engine.construct_payload(prompt="test")
|
||||
assert sd_engine.payload["prompt"] == "test"
|
||||
|
||||
|
||||
async def test_sd_engine_run_t2i():
|
||||
sd_engine = SDEngine()
|
||||
await sd_engine.run_t2i(prompts=["test"])
|
||||
img_path = CONFIG.workspace_path / "resources" / "SD_Output" / "output_0.png"
|
||||
assert os.path.exists(img_path)
|
||||
|
|
@ -7,15 +7,20 @@
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Callable
|
||||
|
||||
import pytest
|
||||
|
||||
import tests.data.search
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
from metagpt.tools import SearchEngineType
|
||||
from metagpt.tools.search_engine import SearchEngine
|
||||
|
||||
search_cache_path = Path(tests.data.search.__path__[0])
|
||||
|
||||
|
||||
class MockSearchEnine:
|
||||
async def run(self, query: str, max_results: int = 8, as_string: bool = True) -> str | list[dict[str, str]]:
|
||||
|
|
@ -41,16 +46,23 @@ class MockSearchEnine:
|
|||
(SearchEngineType.CUSTOM_ENGINE, MockSearchEnine().run, 6, False),
|
||||
],
|
||||
)
|
||||
async def test_search_engine(search_engine_type, run_func: Callable, max_results: int, as_string: bool):
|
||||
async def test_search_engine(search_engine_type, run_func: Callable, max_results: int, as_string: bool, aiohttp_mocker):
|
||||
# Prerequisites
|
||||
cache_json_path = None
|
||||
if search_engine_type is SearchEngineType.SERPAPI_GOOGLE:
|
||||
assert CONFIG.SERPAPI_API_KEY and CONFIG.SERPAPI_API_KEY != "YOUR_API_KEY"
|
||||
cache_json_path = search_cache_path / f"serpapi-metagpt-{max_results}.json"
|
||||
elif search_engine_type is SearchEngineType.DIRECT_GOOGLE:
|
||||
assert CONFIG.GOOGLE_API_KEY and CONFIG.GOOGLE_API_KEY != "YOUR_API_KEY"
|
||||
assert CONFIG.GOOGLE_CSE_ID and CONFIG.GOOGLE_CSE_ID != "YOUR_CSE_ID"
|
||||
elif search_engine_type is SearchEngineType.SERPER_GOOGLE:
|
||||
assert CONFIG.SERPER_API_KEY and CONFIG.SERPER_API_KEY != "YOUR_API_KEY"
|
||||
cache_json_path = search_cache_path / f"serper-metagpt-{max_results}.json"
|
||||
|
||||
if cache_json_path:
|
||||
with open(cache_json_path) as f:
|
||||
data = json.load(f)
|
||||
aiohttp_mocker.set_json(data)
|
||||
search_engine = SearchEngine(search_engine_type, run_func)
|
||||
rsp = await search_engine.run("metagpt", max_results, as_string)
|
||||
logger.info(rsp)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ def search_engine_server():
|
|||
meilisearch_process.wait()
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_meilisearch(search_engine_server):
|
||||
# Prerequisites
|
||||
# https://www.meilisearch.com/docs/learn/getting_started/installation
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ from metagpt.tools.translator import Translator
|
|||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("llm_api")
|
||||
@pytest.mark.usefixtures("llm_mock")
|
||||
async def test_translate(llm_api):
|
||||
poetries = [
|
||||
("Let life be beautiful like summer flowers", "花"),
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ from metagpt.utils.parse_html import WebPage
|
|||
@pytest.mark.parametrize(
|
||||
"browser_type, use_proxy, kwagrs, url, urls",
|
||||
[
|
||||
("chromium", {"proxy": True}, {}, "https://deepwisdom.ai", ("https://deepwisdom.ai",)),
|
||||
("firefox", {}, {"ignore_https_errors": True}, "https://deepwisdom.ai", ("https://deepwisdom.ai",)),
|
||||
("webkit", {}, {"ignore_https_errors": True}, "https://deepwisdom.ai", ("https://deepwisdom.ai",)),
|
||||
("chromium", {"proxy": True}, {}, "https://www.deepwisdom.ai", ("https://www.deepwisdom.ai",)),
|
||||
("firefox", {}, {"ignore_https_errors": True}, "https://www.deepwisdom.ai", ("https://www.deepwisdom.ai",)),
|
||||
("webkit", {}, {"ignore_https_errors": True}, "https://www.deepwisdom.ai", ("https://www.deepwisdom.ai",)),
|
||||
],
|
||||
ids=["chromium-normal", "firefox-normal", "webkit-normal"],
|
||||
)
|
||||
|
|
@ -23,6 +23,7 @@ async def test_scrape_web_page(browser_type, use_proxy, kwagrs, url, urls, proxy
|
|||
global_proxy = CONFIG.global_proxy
|
||||
try:
|
||||
if use_proxy:
|
||||
server, proxy = await proxy
|
||||
CONFIG.global_proxy = proxy
|
||||
browser = web_browser_engine_playwright.PlaywrightWrapper(browser_type=browser_type, **kwagrs)
|
||||
result = await browser.run(url)
|
||||
|
|
@ -35,6 +36,7 @@ async def test_scrape_web_page(browser_type, use_proxy, kwagrs, url, urls, proxy
|
|||
assert len(results) == len(urls) + 1
|
||||
assert all(("MetaGPT" in i.inner_text) for i in results)
|
||||
if use_proxy:
|
||||
server.close()
|
||||
assert "Proxy:" in capfd.readouterr().out
|
||||
finally:
|
||||
CONFIG.global_proxy = global_proxy
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ async def test_scrape_web_page(browser_type, use_proxy, url, urls, proxy, capfd)
|
|||
global_proxy = CONFIG.global_proxy
|
||||
try:
|
||||
if use_proxy:
|
||||
server, proxy = await proxy
|
||||
CONFIG.global_proxy = proxy
|
||||
browser = web_browser_engine_selenium.SeleniumWrapper(browser_type=browser_type)
|
||||
result = await browser.run(url)
|
||||
|
|
@ -38,6 +39,7 @@ async def test_scrape_web_page(browser_type, use_proxy, url, urls, proxy, capfd)
|
|||
assert len(results) == len(urls) + 1
|
||||
assert all(("MetaGPT" in i.inner_text) for i in results)
|
||||
if use_proxy:
|
||||
server.close()
|
||||
assert "Proxy:" in capfd.readouterr().out
|
||||
finally:
|
||||
CONFIG.global_proxy = global_proxy
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ from metagpt.utils.common import (
|
|||
read_file_block,
|
||||
read_json_file,
|
||||
require_python_version,
|
||||
split_namespace,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -163,6 +164,23 @@ class TestGetProjectRoot:
|
|||
assert concat_namespace("a", "b", "c", "e") == "a:b:c:e"
|
||||
assert concat_namespace("a", "b", "c", "e", "f") == "a:b:c:e:f"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("val", "want"),
|
||||
[
|
||||
(
|
||||
"tests/metagpt/test_role.py:test_react:Input:subscription",
|
||||
["tests/metagpt/test_role.py", "test_react", "Input", "subscription"],
|
||||
),
|
||||
(
|
||||
"tests/metagpt/test_role.py:test_react:Input:goal",
|
||||
["tests/metagpt/test_role.py", "test_react", "Input", "goal"],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_split_namespace(self, val, want):
|
||||
res = split_namespace(val)
|
||||
assert res == want
|
||||
|
||||
def test_read_json_file(self):
|
||||
assert read_json_file(str(Path(__file__).parent / "../../data/ut_writer/yft_swaggerApi.json"), encoding="utf-8")
|
||||
with pytest.raises(FileNotFoundError):
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ async def test_js_parser():
|
|||
repo_parser = RepoParser(base_directory=data.path)
|
||||
symbols = repo_parser.generate_symbols()
|
||||
for s in symbols:
|
||||
await GraphRepository.update_graph_db(graph_db=graph, file_info=s)
|
||||
await GraphRepository.update_graph_db_with_file_info(graph_db=graph, file_info=s)
|
||||
data = graph.json()
|
||||
assert data
|
||||
|
||||
|
|
@ -71,11 +71,11 @@ async def test_codes():
|
|||
for file_info in symbols:
|
||||
for code_block in file_info.page_info:
|
||||
try:
|
||||
val = code_block.json(ensure_ascii=False)
|
||||
val = code_block.model_dump_json()
|
||||
assert val
|
||||
except TypeError as e:
|
||||
assert not e
|
||||
await GraphRepository.update_graph_db(graph_db=graph, file_info=file_info)
|
||||
await GraphRepository.update_graph_db_with_file_info(graph_db=graph, file_info=file_info)
|
||||
data = graph.json()
|
||||
assert data
|
||||
print(data)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@
|
|||
@Author : alexanderwu
|
||||
@File : test_read_docx.py
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from metagpt.const import METAGPT_ROOT
|
||||
from metagpt.utils.read_document import read_docx
|
||||
|
||||
|
||||
@pytest.mark.skip # https://copyprogramming.com/howto/python-docx-error-opening-file-bad-magic-number-for-file-header-eoferror
|
||||
class TestReadDocx:
|
||||
def test_read_docx(self):
|
||||
docx_sample = METAGPT_ROOT / "tests/data/docx_for_test.docx"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
@Author : mashenquan
|
||||
@File : test_redis.py
|
||||
"""
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -12,14 +13,23 @@ from metagpt.config import CONFIG
|
|||
from metagpt.utils.redis import Redis
|
||||
|
||||
|
||||
async def async_mock_from_url(*args, **kwargs):
|
||||
mock_client = AsyncMock()
|
||||
mock_client.set.return_value = None
|
||||
mock_client.get.side_effect = [b"test", b""]
|
||||
return mock_client
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_redis():
|
||||
async def test_redis(mocker):
|
||||
# Mock
|
||||
mocker.patch("aioredis.from_url", return_value=async_mock_from_url())
|
||||
|
||||
# Prerequisites
|
||||
assert CONFIG.REDIS_HOST and CONFIG.REDIS_HOST != "YOUR_REDIS_HOST"
|
||||
assert CONFIG.REDIS_PORT and CONFIG.REDIS_PORT != "YOUR_REDIS_PORT"
|
||||
# assert CONFIG.REDIS_USER
|
||||
assert CONFIG.REDIS_PASSWORD is not None and CONFIG.REDIS_PASSWORD != "YOUR_REDIS_PASSWORD"
|
||||
assert CONFIG.REDIS_DB is not None and CONFIG.REDIS_DB != "YOUR_REDIS_DB_INDEX, str, 0-based"
|
||||
CONFIG.REDIS_HOST = "MOCK_REDIS_HOST"
|
||||
CONFIG.REDIS_PORT = "MOCK_REDIS_PORT"
|
||||
CONFIG.REDIS_PASSWORD = "MOCK_REDIS_PASSWORD"
|
||||
CONFIG.REDIS_DB = 0
|
||||
|
||||
conn = Redis()
|
||||
assert not conn.is_valid
|
||||
|
|
|
|||
|
|
@ -2,20 +2,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Desc : unittest of repair_llm_raw_output
|
||||
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.utils.repair_llm_raw_output import (
|
||||
RepairType,
|
||||
extract_content_from_output,
|
||||
repair_invalid_json,
|
||||
repair_llm_raw_output,
|
||||
retry_parse_json_text,
|
||||
)
|
||||
|
||||
"""
|
||||
CONFIG.repair_llm_output should be True before retry_parse_json_text imported.
|
||||
so we move `from ... impot ...` into each `test_xx` to avoid `Module level import not at top of file` format warning.
|
||||
"""
|
||||
CONFIG.repair_llm_output = True
|
||||
|
||||
|
||||
def test_repair_case_sensitivity():
|
||||
from metagpt.utils.repair_llm_raw_output import repair_llm_raw_output
|
||||
|
||||
raw_output = """{
|
||||
"Original requirements": "Write a 2048 game",
|
||||
"search Information": "",
|
||||
|
|
@ -36,6 +34,8 @@ def test_repair_case_sensitivity():
|
|||
|
||||
|
||||
def test_repair_special_character_missing():
|
||||
from metagpt.utils.repair_llm_raw_output import repair_llm_raw_output
|
||||
|
||||
raw_output = """[CONTENT]
|
||||
"Anything UNCLEAR": "No unclear requirements or information."
|
||||
[CONTENT]"""
|
||||
|
|
@ -66,11 +66,12 @@ def test_repair_special_character_missing():
|
|||
target_output = '[CONTENT] {"a": "b"} [/CONTENT]'
|
||||
|
||||
output = repair_llm_raw_output(output=raw_output, req_keys=["[/CONTENT]"])
|
||||
print("output\n", output)
|
||||
assert output == target_output
|
||||
|
||||
|
||||
def test_required_key_pair_missing():
|
||||
from metagpt.utils.repair_llm_raw_output import repair_llm_raw_output
|
||||
|
||||
raw_output = '[CONTENT] {"a": "b"}'
|
||||
target_output = '[CONTENT] {"a": "b"}\n[/CONTENT]'
|
||||
|
||||
|
|
@ -107,6 +108,8 @@ xxx
|
|||
|
||||
|
||||
def test_repair_json_format():
|
||||
from metagpt.utils.repair_llm_raw_output import RepairType, repair_llm_raw_output
|
||||
|
||||
raw_output = "{ xxx }]"
|
||||
target_output = "{ xxx }"
|
||||
|
||||
|
|
@ -125,8 +128,23 @@ def test_repair_json_format():
|
|||
output = repair_llm_raw_output(output=raw_output, req_keys=[None], repair_type=RepairType.JSON)
|
||||
assert output == target_output
|
||||
|
||||
raw_output = """
|
||||
{
|
||||
"Language": "en_us", # define language
|
||||
"Programming Language": "Python"
|
||||
}
|
||||
"""
|
||||
target_output = """{
|
||||
"Language": "en_us",
|
||||
"Programming Language": "Python"
|
||||
}"""
|
||||
output = repair_llm_raw_output(output=raw_output, req_keys=[None], repair_type=RepairType.JSON)
|
||||
assert output == target_output
|
||||
|
||||
|
||||
def test_repair_invalid_json():
|
||||
from metagpt.utils.repair_llm_raw_output import repair_invalid_json
|
||||
|
||||
raw_output = """{
|
||||
"key": "value"
|
||||
},
|
||||
|
|
@ -169,6 +187,8 @@ value
|
|||
|
||||
|
||||
def test_retry_parse_json_text():
|
||||
from metagpt.utils.repair_llm_raw_output import retry_parse_json_text
|
||||
|
||||
invalid_json_text = """{
|
||||
"Original Requirements": "Create a 2048 game",
|
||||
"Competitive Quadrant Chart": "quadrantChart\n\ttitle Reach and engagement of campaigns\n\t\tx-axis"
|
||||
|
|
@ -197,6 +217,25 @@ def test_retry_parse_json_text():
|
|||
output = retry_parse_json_text(output=invalid_json_text)
|
||||
assert output == target_json
|
||||
|
||||
invalid_json_text = '''{
|
||||
"Data structures and interfaces": """
|
||||
class UI:
|
||||
- game_engine: GameEngine
|
||||
+ __init__(engine: GameEngine) -> None
|
||||
+ display_board() -> None
|
||||
+ display_score() -> None
|
||||
+ prompt_move() -> str
|
||||
+ reset_game() -> None
|
||||
"""
|
||||
"Anything UNCLEAR": "no"
|
||||
}'''
|
||||
target_json = {
|
||||
"Data structures and interfaces": "\n class UI:\n - game_engine: GameEngine\n + __init__(engine: GameEngine) -> None\n + display_board() -> None\n + display_score() -> None\n + prompt_move() -> str\n + reset_game() -> None\n ",
|
||||
"Anything UNCLEAR": "no",
|
||||
}
|
||||
output = retry_parse_json_text(output=invalid_json_text)
|
||||
assert output == target_json
|
||||
|
||||
|
||||
def test_extract_content_from_output():
|
||||
"""
|
||||
|
|
@ -205,6 +244,7 @@ def test_extract_content_from_output():
|
|||
xxx [CONTENT] xxx [CONTENT] xxxx [/CONTENT]
|
||||
xxx [CONTENT] xxxx [/CONTENT] xxx [CONTENT][/CONTENT] xxx [CONTENT][/CONTENT] # target pair is the last one
|
||||
"""
|
||||
from metagpt.utils.repair_llm_raw_output import extract_content_from_output
|
||||
|
||||
output = (
|
||||
'Sure! Here is the properly formatted JSON output based on the given context:\n\n[CONTENT]\n{\n"'
|
||||
|
|
|
|||
|
|
@ -9,20 +9,36 @@ import uuid
|
|||
from pathlib import Path
|
||||
|
||||
import aiofiles
|
||||
import mock
|
||||
import pytest
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.utils.common import aread
|
||||
from metagpt.utils.s3 import S3
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_s3():
|
||||
@mock.patch("aioboto3.Session")
|
||||
async def test_s3(mock_session_class):
|
||||
# Set up the mock response
|
||||
data = await aread(__file__, "utf-8")
|
||||
mock_session_object = mock.Mock()
|
||||
reader_mock = mock.AsyncMock()
|
||||
reader_mock.read.side_effect = [data.encode("utf-8"), b"", data.encode("utf-8")]
|
||||
type(reader_mock).url = mock.PropertyMock(return_value="https://mock")
|
||||
mock_client = mock.AsyncMock()
|
||||
mock_client.put_object.return_value = None
|
||||
mock_client.get_object.return_value = {"Body": reader_mock}
|
||||
mock_client.__aenter__.return_value = mock_client
|
||||
mock_client.__aexit__.return_value = None
|
||||
mock_session_object.client.return_value = mock_client
|
||||
mock_session_class.return_value = mock_session_object
|
||||
|
||||
# Prerequisites
|
||||
assert CONFIG.S3_ACCESS_KEY and CONFIG.S3_ACCESS_KEY != "YOUR_S3_ACCESS_KEY"
|
||||
assert CONFIG.S3_SECRET_KEY and CONFIG.S3_SECRET_KEY != "YOUR_S3_SECRET_KEY"
|
||||
assert CONFIG.S3_ENDPOINT_URL and CONFIG.S3_ENDPOINT_URL != "YOUR_S3_ENDPOINT_URL"
|
||||
# assert CONFIG.S3_SECURE: true # true/false
|
||||
assert CONFIG.S3_BUCKET and CONFIG.S3_BUCKET != "YOUR_S3_BUCKET"
|
||||
# assert CONFIG.S3_ACCESS_KEY and CONFIG.S3_ACCESS_KEY != "YOUR_S3_ACCESS_KEY"
|
||||
# assert CONFIG.S3_SECRET_KEY and CONFIG.S3_SECRET_KEY != "YOUR_S3_SECRET_KEY"
|
||||
# assert CONFIG.S3_ENDPOINT_URL and CONFIG.S3_ENDPOINT_URL != "YOUR_S3_ENDPOINT_URL"
|
||||
# assert CONFIG.S3_BUCKET and CONFIG.S3_BUCKET != "YOUR_S3_BUCKET"
|
||||
|
||||
conn = S3()
|
||||
assert conn.is_valid
|
||||
|
|
@ -42,6 +58,7 @@ async def test_s3():
|
|||
assert "http" in res
|
||||
|
||||
# Mock session env
|
||||
type(reader_mock).url = mock.PropertyMock(return_value="")
|
||||
old_options = CONFIG.options.copy()
|
||||
new_options = old_options.copy()
|
||||
new_options["S3_ACCESS_KEY"] = "YOUR_S3_ACCESS_KEY"
|
||||
|
|
@ -54,6 +71,8 @@ async def test_s3():
|
|||
finally:
|
||||
CONFIG.set_context(old_options)
|
||||
|
||||
await reader.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-s"])
|
||||
|
|
|
|||
13
tests/metagpt/utils/test_session.py
Normal file
13
tests/metagpt/utils/test_session.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
# _*_ coding: utf-8 _*_
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_nodeid(request):
|
||||
print(request.node.nodeid)
|
||||
assert request.node.nodeid
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-s"])
|
||||
Loading…
Add table
Add a link
Reference in a new issue