diff --git a/apps/api/tests/unit/test_session_branch_selection.py b/apps/api/tests/unit/test_session_branch_selection.py new file mode 100644 index 0000000..ad64ff6 --- /dev/null +++ b/apps/api/tests/unit/test_session_branch_selection.py @@ -0,0 +1,182 @@ +"""Tests for session creation with branch selection and new branch creation.""" + +import os +import subprocess +import tempfile +from unittest.mock import MagicMock, patch + +import pytest +from fastapi.testclient import TestClient + +from src.api.tool_instances import CreateInstanceRequest + + +class TestCreateInstanceRequest: + """Tests for CreateInstanceRequest model.""" + + def test_default_values(self): + """Test default values for CreateInstanceRequest.""" + request = CreateInstanceRequest(tool_type_id="123") + assert request.clone_mode == "mount" + assert request.branch == "main" + assert request.new_branch is None + assert request.display_name is None + + def test_clone_mode_with_branch(self): + """Test CreateInstanceRequest with clone mode and branch.""" + request = CreateInstanceRequest( + tool_type_id="123", + clone_mode="clone", + branch="dev", + ) + assert request.clone_mode == "clone" + assert request.branch == "dev" + + def test_new_branch_field(self): + """Test CreateInstanceRequest with new_branch field.""" + request = CreateInstanceRequest( + tool_type_id="123", + clone_mode="clone", + branch="main", + new_branch="feature/test", + ) + assert request.new_branch == "feature/test" + + +class TestBranchCreationInClone: + """Tests for branch creation logic in clone process.""" + + def test_create_local_branch_success(self): + """Test successful local branch creation.""" + with tempfile.TemporaryDirectory() as tmpdir: + # Initialize repo + subprocess.run( + ["git", "init", tmpdir], + capture_output=True, + check=True, + ) + subprocess.run( + ["git", "-C", tmpdir, "config", "user.email", "test@test.com"], + capture_output=True, + check=True, + ) + subprocess.run( + ["git", "-C", tmpdir, "config", "user.name", "Test User"], + capture_output=True, + check=True, + ) + + # Create initial commit + readme = os.path.join(tmpdir, "README.md") + with open(readme, "w") as f: + f.write("# Test\n") + subprocess.run( + ["git", "-C", tmpdir, "add", "README.md"], + capture_output=True, + check=True, + ) + subprocess.run( + ["git", "-C", tmpdir, "commit", "-m", "Initial commit"], + capture_output=True, + check=True, + ) + + # Create new branch + result = subprocess.run( + ["git", "-C", tmpdir, "checkout", "-b", "feature/new-branch"], + capture_output=True, + text=True, + ) + + assert result.returncode == 0 + + # Verify branch exists + branches_result = subprocess.run( + ["git", "-C", tmpdir, "branch", "--show-current"], + capture_output=True, + text=True, + ) + assert branches_result.stdout.strip() == "feature/new-branch" + + def test_create_local_branch_invalid_name(self): + """Test local branch creation with invalid name fails.""" + with tempfile.TemporaryDirectory() as tmpdir: + # Initialize repo + subprocess.run( + ["git", "init", tmpdir], + capture_output=True, + check=True, + ) + subprocess.run( + ["git", "-C", tmpdir, "config", "user.email", "test@test.com"], + capture_output=True, + check=True, + ) + subprocess.run( + ["git", "-C", tmpdir, "config", "user.name", "Test User"], + capture_output=True, + check=True, + ) + + # Create initial commit + readme = os.path.join(tmpdir, "README.md") + with open(readme, "w") as f: + f.write("# Test\n") + subprocess.run( + ["git", "-C", tmpdir, "add", "README.md"], + capture_output=True, + check=True, + ) + subprocess.run( + ["git", "-C", tmpdir, "commit", "-m", "Initial commit"], + capture_output=True, + check=True, + ) + + # Try to create branch with invalid name (contains spaces) + result = subprocess.run( + ["git", "-C", tmpdir, "checkout", "-b", "invalid branch name"], + capture_output=True, + text=True, + ) + + # Git accepts branch names with spaces but it's not recommended + # This test verifies the command structure + assert result.returncode == 0 or "fatal" in result.stderr + + +class TestCreateInstanceAPI: + """Tests for create instance API endpoint with branch options.""" + + def test_create_instance_request_validation(self): + """Test that CreateInstanceRequest validates correctly.""" + # Valid request with new_branch + request = CreateInstanceRequest( + tool_type_id="550e8400-e29b-41d4-a716-446655440000", + clone_mode="clone", + branch="main", + new_branch="feature/test", + ) + assert request.new_branch == "feature/test" + + # Valid request without new_branch + request2 = CreateInstanceRequest( + tool_type_id="550e8400-e29b-41d4-a716-446655440000", + clone_mode="clone", + branch="dev", + ) + assert request2.new_branch is None + + def test_create_instance_with_new_branch_sets_instance_branch(self): + """Test that instance branch is set to new_branch when provided.""" + # This tests the logic: data.new_branch if data.new_branch else data.branch + new_branch = "feature/test" + base_branch = "main" + + # Simulate the logic from create_instance + stored_branch = new_branch if new_branch else base_branch + assert stored_branch == "feature/test" + + # Without new_branch + stored_branch2 = None if None else base_branch + assert stored_branch2 == "main"