Skip to content

Commit

Permalink
Fix break in app config (#10)
Browse files Browse the repository at this point in the history
* Fix break in app config

* Fix warning
  • Loading branch information
neubig authored Aug 23, 2024
1 parent ab818c4 commit d78ef5c
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 46 deletions.
5 changes: 2 additions & 3 deletions github_resolver/resolve_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ async def initialize_runtime(
logger.info('-' * 30)
obs: CmdOutputObservation

action = CmdRunAction(command=f'cd /workspace')
action = CmdRunAction(command='cd /workspace')
logger.info(action, extra={'msg_type': 'ACTION'})
obs = cast(CmdOutputObservation, await runtime.run_action(action))
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
Expand Down Expand Up @@ -129,7 +129,7 @@ async def complete_runtime(
logger.info('-' * 30)
obs: CmdOutputObservation

action = CmdRunAction(command=f'cd /workspace')
action = CmdRunAction(command='cd /workspace')
logger.info(action, extra={'msg_type': 'ACTION'})
obs = cast(CmdOutputObservation, await runtime.run_action(action))
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
Expand Down Expand Up @@ -254,7 +254,6 @@ async def process_issue(

config = AppConfig(
default_agent="CodeActAgent",
run_as_devin=False,
runtime='eventstream',
max_budget_per_task=4,
max_iterations=max_iterations,
Expand Down
22 changes: 11 additions & 11 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

161 changes: 129 additions & 32 deletions tests/test_resolve_issues.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,71 @@
import os
import tempfile
import pytest

from unittest.mock import patch, MagicMock

from unittest.mock import AsyncMock, patch, MagicMock
from github_resolver.resolve_issues import (
create_git_patch,
initialize_runtime,
complete_runtime,
get_instruction,
process_issue,
)
from github_resolver.github_issue import GithubIssue
from openhands.events.action import CmdRunAction
from openhands.events.observation import CmdOutputObservation
from openhands.events.observation import CmdOutputObservation, NullObservation
from github_resolver.resolver_output import ResolverOutput
from openhands.core.config import LLMConfig


@pytest.fixture
def mock_output_dir():
with tempfile.TemporaryDirectory() as temp_dir:
repo_path = os.path.join(temp_dir, "repo")
# Initialize a GitHub repo in "repo" and add a commit with "README.md"
os.makedirs(repo_path)
os.system(f"git init {repo_path}")
readme_path = os.path.join(repo_path, "README.md")
with open(readme_path, "w") as f:
f.write("hello world")
os.system(f"git -C {repo_path} add README.md")
os.system(f"git -C {repo_path} commit -m 'Initial commit'")
yield temp_dir


@pytest.fixture
def mock_subprocess():
with patch('subprocess.check_output') as mock_check_output:
with patch("subprocess.check_output") as mock_check_output:
yield mock_check_output


@pytest.fixture
def mock_os():
with patch('os.system') as mock_system, patch('os.path.join') as mock_join:
with patch("os.system") as mock_system, patch("os.path.join") as mock_join:
yield mock_system, mock_join


def test_create_git_patch(mock_subprocess, mock_os):
mock_subprocess.return_value = b'abcdef1234567890'
mock_subprocess.return_value = b"abcdef1234567890"
mock_os[0].return_value = 0
mock_os[1].return_value = '/path/to/workspace/123.patch'
mock_os[1].return_value = "/path/to/workspace/123.patch"

with patch('builtins.open', MagicMock()) as mock_open:
with patch("builtins.open", MagicMock()) as mock_open:
mock_open.return_value.__enter__.return_value.read.return_value = (
'patch content'
"patch content"
)

git_id, patch_content = create_git_patch(
'/path/to/workspace', 'main', 'fix', 123
"/path/to/workspace", "main", "fix", 123
)

assert git_id == 'abcdef1234567890'
assert patch_content == 'patch content'
mock_subprocess.assert_called_once_with(['git', 'rev-parse', 'main'])
assert git_id == "abcdef1234567890"
assert patch_content == "patch content"
mock_subprocess.assert_called_once_with(["git", "rev-parse", "main"])
mock_os[0].assert_called_once_with(
'cd /path/to/workspace && git diff main fix > 123.patch'
"cd /path/to/workspace && git diff main fix > 123.patch"
)
mock_open.assert_called_once_with('/path/to/workspace/123.patch', 'r')
mock_open.assert_called_once_with("/path/to/workspace/123.patch", "r")


async def create_cmd_output(
Expand All @@ -60,11 +81,11 @@ async def test_initialize_runtime():
mock_runtime = MagicMock()
mock_runtime.run_action.side_effect = [
create_cmd_output(
exit_code=0, content='', command_id=1, command='cd /workspace'
exit_code=0, content="", command_id=1, command="cd /workspace"
),
create_cmd_output(
exit_code=0,
content='',
content="",
command_id=2,
command='git config --global core.pager ""',
),
Expand All @@ -73,7 +94,7 @@ async def test_initialize_runtime():
await initialize_runtime(mock_runtime)

assert mock_runtime.run_action.call_count == 2
mock_runtime.run_action.assert_any_call(CmdRunAction(command='cd /workspace'))
mock_runtime.run_action.assert_any_call(CmdRunAction(command="cd /workspace"))
mock_runtime.run_action.assert_any_call(
CmdRunAction(command='git config --global core.pager ""')
)
Expand All @@ -84,50 +105,126 @@ async def test_complete_runtime():
mock_runtime = MagicMock()
mock_runtime.run_action.side_effect = [
create_cmd_output(
exit_code=0, content='', command_id=1, command='cd /workspace'
exit_code=0, content="", command_id=1, command="cd /workspace"
),
create_cmd_output(
exit_code=0,
content='',
content="",
command_id=2,
command='git config --global core.pager ""',
),
create_cmd_output(
exit_code=0,
content='',
content="",
command_id=3,
command='git diff base_commit_hash fix',
command="git diff base_commit_hash fix",
),
create_cmd_output(
exit_code=0, content='git diff content', command_id=4, command='git apply'
exit_code=0, content="git diff content", command_id=4, command="git apply"
),
]

result = await complete_runtime(mock_runtime, 'base_commit_hash')
result = await complete_runtime(mock_runtime, "base_commit_hash")

assert result == {'git_patch': 'git diff content'}
assert result == {"git_patch": "git diff content"}
assert mock_runtime.run_action.call_count == 4


@pytest.mark.asyncio
async def test_process_issue(mock_output_dir):
# Mock dependencies
mock_create_runtime = AsyncMock()
mock_initialize_runtime = AsyncMock()
mock_run_controller = AsyncMock()
mock_complete_runtime = AsyncMock()
mock_guess_success = MagicMock()

# Set up test data
issue = GithubIssue(
owner="test_owner",
repo="test_repo",
number=1,
title="Test Issue",
body="This is a test issue",
)
base_commit = "abcdef1234567890"
max_iterations = 5
llm_config = LLMConfig(model="test_model", api_key="test_api_key")
container_image = "test_image:latest"

# Mock return values
mock_create_runtime.return_value = MagicMock()
mock_run_controller.return_value = MagicMock(
history=MagicMock(
get_events=MagicMock(return_value=[NullObservation(content="")])
),
metrics=MagicMock(get=MagicMock(return_value={"test_result": "passed"})),
last_error=None,
)
mock_complete_runtime.return_value = {"git_patch": "test patch"}
mock_guess_success.return_value = (True, "Issue resolved successfully")

# Patch the necessary functions
with patch(
"github_resolver.resolve_issues.create_runtime", mock_create_runtime
), patch(
"github_resolver.resolve_issues.initialize_runtime", mock_initialize_runtime
), patch(
"github_resolver.resolve_issues.run_controller", mock_run_controller
), patch(
"github_resolver.resolve_issues.complete_runtime", mock_complete_runtime
), patch(
"github_resolver.resolve_issues.guess_success", mock_guess_success
), patch(
"github_resolver.resolve_issues.logger"
):

# Call the function
result = await process_issue(
issue,
base_commit,
max_iterations,
llm_config,
mock_output_dir,
container_image,
)

# Assert the result
assert isinstance(result, ResolverOutput)
assert result.issue == issue
assert result.base_commit == base_commit
assert result.git_patch == "test patch"
assert result.success
assert result.success_explanation == "Issue resolved successfully"
assert result.error is None

# Assert that the mocked functions were called
mock_create_runtime.assert_called_once()
mock_initialize_runtime.assert_called_once()
mock_run_controller.assert_called_once()
mock_complete_runtime.assert_called_once()
mock_guess_success.assert_called_once()


def test_get_instruction():
issue = GithubIssue(
owner='test_owner',
repo='test_repo',
owner="test_owner",
repo="test_repo",
number=123,
title='Test Issue',
body='This is a test issue',
title="Test Issue",
body="This is a test issue",
)
instruction = get_instruction(issue)

assert (
'Please fix the following issue for the repository in /workspace.'
"Please fix the following issue for the repository in /workspace."
in instruction
)
assert 'This is a test issue' in instruction
assert "This is a test issue" in instruction
assert (
'You should ONLY interact with the environment provided to you' in instruction
"You should ONLY interact with the environment provided to you" in instruction
)


if __name__ == '__main__':
if __name__ == "__main__":
pytest.main()

0 comments on commit d78ef5c

Please sign in to comment.