cvs-proxy/cvs_proxy/test_cvs_client.py
Juan José Gutiérrez de Quevedo Pérez d3b40ae93f feat: Add patchset history and diff support with cvsps integration
- Add cvsps package to Docker dependencies
- Implement patchset retrieval and diff endpoints in API
- Add _run_cvsps_command() helper for cvsps integration
- Enhance file history parsing with log message extraction
- Improve UI with enhanced styling and patchset functionality
2025-11-21 17:18:55 +01:00

199 lines
No EOL
7.4 KiB
Python

import unittest
from unittest.mock import patch, MagicMock, mock_open
from cvs_proxy.cvs_client import CVSClient
import subprocess
import os
import tempfile
import shutil
class TestCVSClient(unittest.TestCase):
def setUp(self):
# Use a test repository URL directly
self.test_url = ':pserver:testuser@test.repo.com:/path/to/repo'
# Create a temporary directory to simulate checkouts
self.test_checkouts_dir = tempfile.mkdtemp()
# Patch the checkout method to prevent actual checkout
CVSClient._checkout_repository = lambda self: None
# Create the CVS client with explicit repos_checkout and cvs_module
self.cvs_client = CVSClient(self.test_url, repos_checkout=self.test_checkouts_dir, cvs_module='test_module')
# Override local_repo_path with a test directory
self.test_repo_dir = os.path.join(self.test_checkouts_dir, 'testuser_test_repo_com_path_to_repo')
os.makedirs(self.test_repo_dir, exist_ok=True)
self.cvs_client.local_repo_path = self.test_repo_dir
def tearDown(self):
# Clean up the temporary directory
shutil.rmtree(self.test_checkouts_dir)
# Remove the environment variable
if 'REPO_CHECKOUTS' in os.environ:
del os.environ['REPO_CHECKOUTS']
def _create_test_files(self):
"""
Create a test directory structure for repository tree testing
"""
# Create test files and directories
os.makedirs(os.path.join(self.test_repo_dir, 'src'), exist_ok=True)
os.makedirs(os.path.join(self.test_repo_dir, 'docs'), exist_ok=True)
# Create some files
with open(os.path.join(self.test_repo_dir, 'README.md'), 'w') as f:
f.write('Test README')
with open(os.path.join(self.test_repo_dir, 'src', 'main.py'), 'w') as f:
f.write('def main():\n pass')
with open(os.path.join(self.test_repo_dir, 'docs', 'manual.txt'), 'w') as f:
f.write('Documentation')
def test_initialization(self):
"""Test CVS client initialization"""
# Verify repository URL
self.assertEqual(self.cvs_client.repo_url, ':pserver:testuser@test.repo.com:/path/to/repo')
# Verify checkout directory is created in the specified REPO_CHECKOUTS location
self.assertTrue(os.path.exists(self.test_checkouts_dir))
self.assertTrue(os.path.exists(self.test_repo_dir))
def test_missing_url(self):
"""Test initialization without URL"""
with self.assertRaises(ValueError):
CVSClient()
def test_list_repository_tree(self):
"""Test listing repository tree structure"""
# Create test files
self._create_test_files()
# Test full repository tree
tree = self.cvs_client.list_repository_tree()
expected_tree = [
'README.md',
'docs/manual.txt',
'src/main.py'
]
self.assertEqual(sorted(tree), sorted(expected_tree))
# Test subdirectory listing
src_tree = self.cvs_client.list_repository_tree('src')
self.assertEqual(src_tree, ['main.py'])
# Test non-existent directory
empty_tree = self.cvs_client.list_repository_tree('nonexistent')
self.assertEqual(empty_tree, [])
def test_checkout_directory_configuration(self):
"""Test that checkout directory can be configured via environment variable"""
# Create another test directory
another_checkouts_dir = tempfile.mkdtemp()
os.environ['REPO_CHECKOUTS'] = another_checkouts_dir
# Create a new CVS client
another_client = CVSClient(':pserver:another@example.com:/another/repo')
# Verify the checkout is in the new directory
expected_repo_path = os.path.join(another_checkouts_dir, 'another_example_com_another_repo')
self.assertEqual(another_client.local_repo_path, expected_repo_path)
# Clean up
shutil.rmtree(another_checkouts_dir)
del os.environ['REPO_CHECKOUTS']
@patch('cvs_proxy.cvs_client.subprocess.run')
def test_run_cvs_command(self, mock_run):
"""Test the internal _run_cvs_command method"""
mock_run.return_value = MagicMock(
stdout='Command output',
stderr='',
returncode=0
)
result = self.cvs_client._run_cvs_command(['rlog', 'test.txt'])
self.assertEqual(result, 'Command output')
# Verify the command was constructed correctly
mock_run.assert_called_once()
call_args = mock_run.call_args[0][0]
self.assertEqual(call_args, [
'cvs',
'-d',
':pserver:testuser@test.repo.com:/path/to/repo',
'rlog',
'test.txt'
])
@patch('cvs_proxy.cvs_client.subprocess.run')
def test_get_file_diff(self, mock_run):
"""Test getting file differences"""
mock_run.return_value = MagicMock(
stdout='--- a/file.txt\n+++ b/file.txt\n@@ -1,3 +1,4 @@\n line1\n-old line\n+new line\n line3',
stderr='',
returncode=0
)
diff = self.cvs_client.get_file_diff('file.txt', '1.1', '1.2')
self.assertIn('line1', diff)
self.assertIn('-old line', diff)
self.assertIn('+new line', diff)
@patch('cvs_proxy.cvs_client.subprocess.run')
def test_get_file_history(self, mock_run):
"""Test retrieving file history using cvs log"""
mock_run.return_value = MagicMock(
stdout='''
revision 1.2
date: 2023/11/20 10:00:00; author: testuser; state: Exp; lines: +5 -2
revision 1.1
date: 2023/11/19 15:30:00; author: testuser; state: Exp; lines: +10 -0
''',
stderr='',
returncode=0
)
history = self.cvs_client.get_file_history('file.txt')
self.assertIsInstance(history, list)
self.assertEqual(len(history), 2)
self.assertIn('revision', history[0])
self.assertEqual(history[0]['revision'], '1.2')
self.assertEqual(history[0]['author'], 'testuser')
self.assertEqual(history[0]['date'], '2023/11/20 10:00:00')
self.assertEqual(history[0]['state'], 'Exp')
# Verify the cvs log command was called correctly
mock_run.assert_called()
call_args = mock_run.call_args[0][0]
self.assertEqual(call_args[0], 'cvs')
self.assertIn('log', call_args)
self.assertIn('file.txt', call_args)
@patch('cvs_proxy.cvs_client.subprocess.run')
def test_get_file_content(self, mock_run):
"""Test retrieving file content"""
mock_run.return_value = MagicMock(
stdout='File contents\nMultiple lines\nof text',
stderr='',
returncode=0
)
content = self.cvs_client.get_file_content('file.txt', '1.2')
self.assertEqual(content, 'File contents\nMultiple lines\nof text')
@patch('cvs_proxy.cvs_client.subprocess.run')
def test_command_failure(self, mock_run):
"""Test handling of CVS command failure"""
mock_run.side_effect = subprocess.CalledProcessError(
returncode=1,
cmd=['cvs', 'rlog'],
stderr='Error: Repository not found'
)
with self.assertRaises(subprocess.CalledProcessError):
self.cvs_client._run_cvs_command(['rlog'])
if __name__ == '__main__':
unittest.main()