Spaces:
Build error
Build error
| from unittest.mock import MagicMock, call | |
| import pytest | |
| from openhands.events.action import CmdRunAction, FileReadAction | |
| from openhands.events.observation import ( | |
| CmdOutputObservation, | |
| ErrorObservation, | |
| FileReadObservation, | |
| ) | |
| from openhands.runtime.base import Runtime | |
| class TestGitHooks: | |
| def mock_runtime(self): | |
| # Create a mock runtime | |
| mock_runtime = MagicMock(spec=Runtime) | |
| mock_runtime.status_callback = None | |
| # Set up read to return different values based on the path | |
| def mock_read(action): | |
| if action.path == '.openhands/pre-commit.sh': | |
| return FileReadObservation( | |
| content="#!/bin/bash\necho 'Test pre-commit hook'\nexit 0", | |
| path='.openhands/pre-commit.sh', | |
| ) | |
| elif action.path == '.git/hooks/pre-commit': | |
| # Simulate no existing pre-commit hook | |
| return ErrorObservation(content='File not found') | |
| return ErrorObservation(content='Unexpected path') | |
| mock_runtime.read.side_effect = mock_read | |
| mock_runtime.run_action.return_value = CmdOutputObservation( | |
| content='', exit_code=0, command='test command' | |
| ) | |
| mock_runtime.write.return_value = None | |
| return mock_runtime | |
| def test_maybe_setup_git_hooks_success(self, mock_runtime): | |
| # Test successful setup of git hooks | |
| Runtime.maybe_setup_git_hooks(mock_runtime) | |
| # Verify that the runtime tried to read the pre-commit script | |
| assert mock_runtime.read.call_args_list[0] == call( | |
| FileReadAction(path='.openhands/pre-commit.sh') | |
| ) | |
| # Verify that the runtime created the git hooks directory | |
| # We can't directly compare the CmdRunAction objects, so we check if run_action was called | |
| assert mock_runtime.run_action.called | |
| # Verify that the runtime made the pre-commit script executable | |
| # We can't directly compare the CmdRunAction objects, so we check if run_action was called | |
| assert mock_runtime.run_action.called | |
| # Verify that the runtime wrote the pre-commit hook | |
| assert mock_runtime.write.called | |
| # Verify that the runtime made the pre-commit hook executable | |
| # We can't directly compare the CmdRunAction objects, so we check if run_action was called | |
| assert mock_runtime.run_action.call_count >= 3 | |
| # Verify that the runtime logged success | |
| mock_runtime.log.assert_called_with( | |
| 'info', 'Git pre-commit hook installed successfully' | |
| ) | |
| def test_maybe_setup_git_hooks_no_script(self, mock_runtime): | |
| # Test when pre-commit script doesn't exist | |
| mock_runtime.read.side_effect = lambda action: ErrorObservation( | |
| content='File not found' | |
| ) | |
| Runtime.maybe_setup_git_hooks(mock_runtime) | |
| # Verify that the runtime tried to read the pre-commit script | |
| mock_runtime.read.assert_called_with( | |
| FileReadAction(path='.openhands/pre-commit.sh') | |
| ) | |
| # Verify that no other actions were taken | |
| mock_runtime.run_action.assert_not_called() | |
| mock_runtime.write.assert_not_called() | |
| def test_maybe_setup_git_hooks_mkdir_failure(self, mock_runtime): | |
| # Test failure to create git hooks directory | |
| def mock_run_action(action): | |
| if ( | |
| isinstance(action, CmdRunAction) | |
| and action.command == 'mkdir -p .git/hooks' | |
| ): | |
| return CmdOutputObservation( | |
| content='Permission denied', | |
| exit_code=1, | |
| command='mkdir -p .git/hooks', | |
| ) | |
| return CmdOutputObservation(content='', exit_code=0, command=action.command) | |
| mock_runtime.run_action.side_effect = mock_run_action | |
| Runtime.maybe_setup_git_hooks(mock_runtime) | |
| # Verify that the runtime tried to create the git hooks directory | |
| assert mock_runtime.run_action.called | |
| # Verify that the runtime logged an error | |
| mock_runtime.log.assert_called_with( | |
| 'error', 'Failed to create git hooks directory: Permission denied' | |
| ) | |
| # Verify that no other actions were taken | |
| mock_runtime.write.assert_not_called() | |
| def test_maybe_setup_git_hooks_with_existing_hook(self, mock_runtime): | |
| # Test when there's an existing pre-commit hook | |
| def mock_read(action): | |
| if action.path == '.openhands/pre-commit.sh': | |
| return FileReadObservation( | |
| content="#!/bin/bash\necho 'Test pre-commit hook'\nexit 0", | |
| path='.openhands/pre-commit.sh', | |
| ) | |
| elif action.path == '.git/hooks/pre-commit': | |
| # Simulate existing pre-commit hook | |
| return FileReadObservation( | |
| content="#!/bin/bash\necho 'Existing hook'\nexit 0", | |
| path='.git/hooks/pre-commit', | |
| ) | |
| return ErrorObservation(content='Unexpected path') | |
| mock_runtime.read.side_effect = mock_read | |
| Runtime.maybe_setup_git_hooks(mock_runtime) | |
| # Verify that the runtime tried to read both scripts | |
| assert len(mock_runtime.read.call_args_list) >= 2 | |
| # Verify that the runtime preserved the existing hook | |
| assert mock_runtime.log.call_args_list[0] == call( | |
| 'info', 'Preserving existing pre-commit hook' | |
| ) | |
| # Verify that the runtime moved the existing hook | |
| move_calls = [ | |
| call | |
| for call in mock_runtime.run_action.call_args_list | |
| if isinstance(call[0][0], CmdRunAction) and 'mv' in call[0][0].command | |
| ] | |
| assert len(move_calls) > 0 | |
| # Verify that the runtime wrote the new pre-commit hook | |
| assert mock_runtime.write.called | |
| # Verify that the runtime logged success | |
| assert mock_runtime.log.call_args_list[-1] == call( | |
| 'info', 'Git pre-commit hook installed successfully' | |
| ) | |