Files
OpenJarvis/tests/tools/test_git_tool.py
T
Jon Saad-FalconandClaude Opus 4.6 a4c4081ff4 Add desktop distribution pipeline: rolling releases, auto-updates, code signing
- Rewrite .github/workflows/desktop.yml: 2-job pipeline (validate + build-and-release)
  with rolling desktop-latest pre-release on push to main and stable desktop-v* releases
- Add UpdateChecker component: checks for updates on startup + every 30 min,
  background download with progress bar, one-click relaunch
- Configure Tauri updater: endpoints pointing to desktop-latest release, pubkey placeholder
- Add tauri-plugin-process for relaunch support (Cargo.toml, lib.rs, package.json)
- Add macOS Entitlements.plist for notarization (network + file access, no sandbox)
- Add scripts/bump-desktop-version.sh for atomic version bumps across 3 config files
- Add desktop/README.md with dev setup, auto-update architecture, signing docs
- Update .gitignore for desktop/node_modules, dist, target
- Configure macOS minimumSystemVersion, Windows timestampUrl
- Include all Phase 14-21 work: agent hardening, RBAC, taint tracking, workflows,
  skills, knowledge graph, sessions, A2A, MCP templates, WASM sandbox, TUI dashboard,
  production tools, CLI expansion, API expansion, learning productionization,
  Tauri desktop app, and 10 new channels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 19:14:05 +00:00

416 lines
13 KiB
Python

"""Tests for the git tools (status, diff, commit, log)."""
from __future__ import annotations
import subprocess
from unittest.mock import patch
from openjarvis.tools.git_tool import (
GitCommitTool,
GitDiffTool,
GitLogTool,
GitStatusTool,
)
def _init_repo(path):
"""Initialize a git repo with an initial commit at *path*."""
subprocess.run(
["git", "init"],
cwd=str(path),
capture_output=True,
check=True,
)
subprocess.run(
["git", "config", "user.email", "test@test.com"],
cwd=str(path),
capture_output=True,
check=True,
)
subprocess.run(
["git", "config", "user.name", "Test User"],
cwd=str(path),
capture_output=True,
check=True,
)
# Create an initial commit so HEAD exists
readme = path / "README.md"
readme.write_text("# Test Repo\n")
subprocess.run(
["git", "add", "."],
cwd=str(path),
capture_output=True,
check=True,
)
subprocess.run(
["git", "commit", "-m", "Initial commit"],
cwd=str(path),
capture_output=True,
check=True,
)
# ---------------------------------------------------------------------------
# TestGitStatusTool
# ---------------------------------------------------------------------------
class TestGitStatusTool:
def test_spec(self):
tool = GitStatusTool()
assert tool.spec.name == "git_status"
assert tool.spec.category == "vcs"
assert "file:read" in tool.spec.required_capabilities
def test_tool_id(self):
tool = GitStatusTool()
assert tool.tool_id == "git_status"
def test_clean_repo(self, tmp_path):
_init_repo(tmp_path)
tool = GitStatusTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.success is True
# Clean repo has no porcelain output
assert result.content == "(no output)"
def test_modified_file(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "README.md").write_text("# Modified\n")
tool = GitStatusTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.success is True
assert "README.md" in result.content
def test_untracked_file(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "new_file.txt").write_text("hello")
tool = GitStatusTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.success is True
assert "new_file.txt" in result.content
def test_default_repo_path(self):
tool = GitStatusTool()
result = tool.execute()
# Should succeed or fail depending on cwd; not a crash
assert isinstance(result.content, str)
def test_invalid_repo_path(self, tmp_path):
tool = GitStatusTool()
result = tool.execute(repo_path=str(tmp_path / "nonexistent"))
assert result.success is False
def test_returncode_in_metadata(self, tmp_path):
_init_repo(tmp_path)
tool = GitStatusTool()
result = tool.execute(repo_path=str(tmp_path))
assert "returncode" in result.metadata
assert result.metadata["returncode"] == 0
def test_git_not_found(self):
tool = GitStatusTool()
with patch("openjarvis.tools.git_tool.shutil.which", return_value=None):
result = tool.execute(repo_path=".")
assert result.success is False
assert "not found" in result.content
def test_to_openai_function(self):
tool = GitStatusTool()
fn = tool.to_openai_function()
assert fn["type"] == "function"
assert fn["function"]["name"] == "git_status"
# ---------------------------------------------------------------------------
# TestGitDiffTool
# ---------------------------------------------------------------------------
class TestGitDiffTool:
def test_spec(self):
tool = GitDiffTool()
assert tool.spec.name == "git_diff"
assert tool.spec.category == "vcs"
assert "file:read" in tool.spec.required_capabilities
def test_tool_id(self):
tool = GitDiffTool()
assert tool.tool_id == "git_diff"
def test_no_changes(self, tmp_path):
_init_repo(tmp_path)
tool = GitDiffTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.success is True
assert result.content == "(no output)"
def test_unstaged_changes(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "README.md").write_text("# Changed\n")
tool = GitDiffTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.success is True
assert "Changed" in result.content
def test_staged_changes(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "README.md").write_text("# Staged\n")
subprocess.run(
["git", "add", "README.md"],
cwd=str(tmp_path),
capture_output=True,
check=True,
)
tool = GitDiffTool()
# Unstaged should be empty
result_unstaged = tool.execute(repo_path=str(tmp_path))
assert result_unstaged.content == "(no output)"
# Staged should show changes
result_staged = tool.execute(repo_path=str(tmp_path), staged=True)
assert result_staged.success is True
assert "Staged" in result_staged.content
def test_specific_file_path(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "README.md").write_text("# Changed\n")
(tmp_path / "other.txt").write_text("other change")
subprocess.run(
["git", "add", "other.txt"],
cwd=str(tmp_path),
capture_output=True,
)
tool = GitDiffTool()
result = tool.execute(repo_path=str(tmp_path), path="README.md")
assert result.success is True
assert "Changed" in result.content
def test_git_not_found(self):
tool = GitDiffTool()
with patch("openjarvis.tools.git_tool.shutil.which", return_value=None):
result = tool.execute(repo_path=".")
assert result.success is False
assert "not found" in result.content
def test_invalid_repo_path(self, tmp_path):
tool = GitDiffTool()
result = tool.execute(repo_path=str(tmp_path / "nonexistent"))
assert result.success is False
def test_returncode_in_metadata(self, tmp_path):
_init_repo(tmp_path)
tool = GitDiffTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.metadata["returncode"] == 0
# ---------------------------------------------------------------------------
# TestGitCommitTool
# ---------------------------------------------------------------------------
class TestGitCommitTool:
def test_spec(self):
tool = GitCommitTool()
assert tool.spec.name == "git_commit"
assert tool.spec.category == "vcs"
assert "file:write" in tool.spec.required_capabilities
assert tool.spec.requires_confirmation is True
def test_tool_id(self):
tool = GitCommitTool()
assert tool.tool_id == "git_commit"
def test_no_message(self):
tool = GitCommitTool()
result = tool.execute(message="")
assert result.success is False
assert "No commit message" in result.content
def test_no_message_param(self):
tool = GitCommitTool()
result = tool.execute()
assert result.success is False
assert "No commit message" in result.content
def test_commit_staged_files(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "new.txt").write_text("hello")
subprocess.run(
["git", "add", "new.txt"],
cwd=str(tmp_path),
capture_output=True,
check=True,
)
tool = GitCommitTool()
result = tool.execute(
message="Add new file",
repo_path=str(tmp_path),
)
assert result.success is True
assert result.metadata["returncode"] == 0
def test_stage_and_commit(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "a.txt").write_text("aaa")
(tmp_path / "b.txt").write_text("bbb")
tool = GitCommitTool()
result = tool.execute(
message="Add a and b",
repo_path=str(tmp_path),
files="a.txt,b.txt",
)
assert result.success is True
# Verify both files were committed
log_output = subprocess.run(
["git", "log", "--oneline", "-1"],
cwd=str(tmp_path),
capture_output=True,
text=True,
)
assert "Add a and b" in log_output.stdout
def test_stage_all_files(self, tmp_path):
_init_repo(tmp_path)
(tmp_path / "x.txt").write_text("xxx")
tool = GitCommitTool()
result = tool.execute(
message="Stage all",
repo_path=str(tmp_path),
files=".",
)
assert result.success is True
def test_commit_nothing_staged(self, tmp_path):
_init_repo(tmp_path)
tool = GitCommitTool()
result = tool.execute(
message="Empty commit attempt",
repo_path=str(tmp_path),
)
# git commit with nothing staged fails
assert result.success is False
def test_stage_nonexistent_file(self, tmp_path):
_init_repo(tmp_path)
tool = GitCommitTool()
result = tool.execute(
message="Bad stage",
repo_path=str(tmp_path),
files="does_not_exist.txt",
)
assert result.success is False
assert "git add failed" in result.content
def test_empty_files_string(self, tmp_path):
_init_repo(tmp_path)
tool = GitCommitTool()
result = tool.execute(
message="Empty files",
repo_path=str(tmp_path),
files=" , , ",
)
assert result.success is False
assert "Empty files list" in result.content
def test_git_not_found(self):
tool = GitCommitTool()
with patch("openjarvis.tools.git_tool.shutil.which", return_value=None):
result = tool.execute(message="test")
assert result.success is False
assert "not found" in result.content
def test_message_required_in_spec(self):
tool = GitCommitTool()
assert "message" in tool.spec.parameters["required"]
# ---------------------------------------------------------------------------
# TestGitLogTool
# ---------------------------------------------------------------------------
class TestGitLogTool:
def test_spec(self):
tool = GitLogTool()
assert tool.spec.name == "git_log"
assert tool.spec.category == "vcs"
assert "file:read" in tool.spec.required_capabilities
def test_tool_id(self):
tool = GitLogTool()
assert tool.tool_id == "git_log"
def test_log_oneline(self, tmp_path):
_init_repo(tmp_path)
tool = GitLogTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.success is True
assert "Initial commit" in result.content
def test_log_full_format(self, tmp_path):
_init_repo(tmp_path)
tool = GitLogTool()
result = tool.execute(repo_path=str(tmp_path), oneline=False)
assert result.success is True
assert "Initial commit" in result.content
# Full format includes "Author:" header
assert "Author:" in result.content
def test_log_count(self, tmp_path):
_init_repo(tmp_path)
# Add more commits
for i in range(5):
(tmp_path / f"file{i}.txt").write_text(f"content {i}")
subprocess.run(
["git", "add", "."],
cwd=str(tmp_path),
capture_output=True,
check=True,
)
subprocess.run(
["git", "commit", "-m", f"Commit {i}"],
cwd=str(tmp_path),
capture_output=True,
check=True,
)
tool = GitLogTool()
result = tool.execute(repo_path=str(tmp_path), count=3, oneline=True)
assert result.success is True
# Should have exactly 3 lines of output
lines = [
line for line in result.content.strip().splitlines()
if line.strip()
]
assert len(lines) == 3
def test_default_count_is_10(self):
tool = GitLogTool()
# Verify via spec that default is documented
desc = tool.spec.parameters["properties"]["count"]["description"]
assert "10" in desc
def test_git_not_found(self):
tool = GitLogTool()
with patch("openjarvis.tools.git_tool.shutil.which", return_value=None):
result = tool.execute(repo_path=".")
assert result.success is False
assert "not found" in result.content
def test_invalid_repo_path(self, tmp_path):
tool = GitLogTool()
result = tool.execute(repo_path=str(tmp_path / "nonexistent"))
assert result.success is False
def test_returncode_in_metadata(self, tmp_path):
_init_repo(tmp_path)
tool = GitLogTool()
result = tool.execute(repo_path=str(tmp_path))
assert result.metadata["returncode"] == 0
def test_to_openai_function(self):
tool = GitLogTool()
fn = tool.to_openai_function()
assert fn["type"] == "function"
assert fn["function"]["name"] == "git_log"