Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.
90
90%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Risky
Do not use without reviewing
#!/usr/bin/env python3
"""Unit and integration tests for session-tracker.py.
Tests cover:
- Transcript JSONL parsing and data extraction
- User message extraction (last 10, redacted)
- Tool operation counting (Write, Edit, Delete)
- Modified file path extraction (including delete paths)
- Efficient tail reading (last 100 lines only)
- Secret redaction from output
- Edge cases: missing file, empty file, malformed JSONL
"""
import importlib.util
import json
import os
import sys
import tempfile
from unittest.mock import patch
import pytest
# Import the module under test
scripts_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
spec = importlib.util.spec_from_file_location(
"session_tracker", os.path.join(scripts_dir, "session-tracker.py")
)
session_tracker = importlib.util.module_from_spec(spec)
sys.modules["session_tracker"] = session_tracker
spec.loader.exec_module(session_tracker)
# ─── Helpers ─────────────────────────────────────────────────────────────────
def _make_transcript(entries: list[dict]) -> str:
"""Create a temporary JSONL file from entries and return its path."""
tmp = tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False, encoding="utf-8")
for entry in entries:
tmp.write(json.dumps(entry) + "\n")
tmp.close()
return tmp.name
def _cleanup(path: str) -> None:
try:
os.unlink(path)
except OSError:
pass
# ─── Unit Tests: Transcript Reading ──────────────────────────────────────────
class TestReadLastNLines:
"""Test efficient tail reading of transcript files."""
def test_reads_last_n_lines_efficiently(self):
"""Only last N lines are returned, not the full file."""
lines = [{"line": i} for i in range(200)]
path = _make_transcript(lines)
try:
result = session_tracker.read_last_n_lines(path, n=100)
assert len(result) == 100
# Should be the last 100 lines (100-199)
first = json.loads(result[0])
assert first["line"] == 100
last = json.loads(result[-1])
assert last["line"] == 199
finally:
_cleanup(path)
def test_returns_all_if_fewer_than_n(self):
"""If file has fewer lines than N, return all."""
lines = [{"line": i} for i in range(50)]
path = _make_transcript(lines)
try:
result = session_tracker.read_last_n_lines(path, n=100)
assert len(result) == 50
finally:
_cleanup(path)
def test_missing_file_returns_empty(self):
"""Missing file returns empty list."""
result = session_tracker.read_last_n_lines("/nonexistent/path.jsonl")
assert result == []
def test_empty_file_returns_empty(self):
"""Empty file returns empty list."""
tmp = tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False)
tmp.close()
try:
result = session_tracker.read_last_n_lines(tmp.name)
assert result == []
finally:
_cleanup(tmp.name)
# ─── Unit Tests: User Message Extraction ─────────────────────────────────────
class TestExtractUserMessages:
"""Test user message extraction and redaction."""
def test_extracts_user_messages(self):
entries = [
{"type": "user", "content": "Hello"},
{"type": "assistant", "content": "Hi"},
{"type": "user", "content": "Fix bug"},
]
result = session_tracker.extract_user_messages(entries)
assert len(result) == 2
assert "Hello" in result[0]
assert "Fix bug" in result[1]
def test_limits_to_last_10(self):
entries = [{"type": "user", "content": f"msg{i}"} for i in range(20)]
result = session_tracker.extract_user_messages(entries)
assert len(result) == 10
assert "msg10" in result[0]
def test_redacts_secrets(self):
entries = [
{"type": "user", "content": "api_key='sk-abc123def456ghi789jkl012mno345'"},
]
result = session_tracker.extract_user_messages(entries)
assert "sk-abc123" not in result[0]
assert "[REDACTED]" in result[0]
def test_handles_message_dict_format(self):
entries = [
{"type": "user", "message": {"role": "user", "content": "nested msg"}},
]
result = session_tracker.extract_user_messages(entries)
assert len(result) == 1
assert "nested msg" in result[0]
def test_handles_content_block_format(self):
entries = [
{
"type": "user",
"message": {"role": "user", "content": [{"type": "text", "text": "block msg"}]},
},
]
result = session_tracker.extract_user_messages(entries)
assert len(result) == 1
assert "block msg" in result[0]
# ─── Unit Tests: Tool Operation Extraction ───────────────────────────────────
class TestExtractToolOperations:
"""Test tool operation counting and file path extraction."""
def test_counts_write_operations(self):
entries = [
{
"type": "tool_use",
"tool_name": "Write",
"tool_input": {"file_path": "/tmp/a.py", "content": "x"},
},
]
result = session_tracker.extract_tool_operations(entries)
assert result["tool_operations"]["Write"] == 1
assert "/tmp/a.py" in result["modified_files"]
def test_counts_edit_operations(self):
entries = [
{
"type": "tool_use",
"tool_name": "Edit",
"tool_input": {"file_path": "/tmp/b.py", "old_string": "x", "new_string": "y"},
},
]
result = session_tracker.extract_tool_operations(entries)
assert result["tool_operations"]["Edit"] == 1
assert "/tmp/b.py" in result["modified_files"]
def test_counts_delete_operations_with_path(self):
"""Delete operations should count AND capture file path."""
entries = [
{
"type": "tool_use",
"tool_name": "Bash",
"tool_input": {"command": "rm -rf /tmp/old.py"},
},
]
result = session_tracker.extract_tool_operations(entries)
assert result["tool_operations"]["Delete"] == 1
assert "/tmp/old.py" in result["modified_files"]
def test_delete_git_rm_captures_path(self):
"""git rm should also capture the deleted file path."""
entries = [
{
"type": "tool_use",
"tool_name": "Bash",
"tool_input": {"command": "git rm src/old.java"},
},
]
result = session_tracker.extract_tool_operations(entries)
assert result["tool_operations"]["Delete"] == 1
assert "src/old.java" in result["modified_files"]
def test_delete_rmdir_captures_path(self):
"""rmdir should capture the directory path."""
entries = [
{"type": "tool_use", "tool_name": "Bash", "tool_input": {"command": "rmdir build/"}},
]
result = session_tracker.extract_tool_operations(entries)
assert result["tool_operations"]["Delete"] == 1
assert "build/" in result["modified_files"]
def test_non_delete_bash_not_counted(self):
"""Bash commands without delete patterns should not count as Delete."""
entries = [
{"type": "tool_use", "tool_name": "Bash", "tool_input": {"command": "npm test"}},
]
result = session_tracker.extract_tool_operations(entries)
assert result["tool_operations"]["Delete"] == 0
assert result["modified_files"] == []
def test_assistant_tool_use_blocks(self):
"""Tool use blocks inside assistant messages should be parsed."""
entries = [
{
"type": "assistant",
"message": {
"content": [
{
"type": "tool_use",
"name": "Write",
"input": {"file_path": "/tmp/c.py", "content": "z"},
},
],
},
},
]
result = session_tracker.extract_tool_operations(entries)
assert result["tool_operations"]["Write"] == 1
assert "/tmp/c.py" in result["modified_files"]
def test_empty_entries_returns_zeros(self):
result = session_tracker.extract_tool_operations([])
assert result["tool_operations"]["Write"] == 0
assert result["tool_operations"]["Edit"] == 0
assert result["tool_operations"]["Delete"] == 0
assert result["modified_files"] == []
# ─── Unit Tests: Secret Redaction ────────────────────────────────────────────
class TestRedactSecrets:
"""Test that credentials are never output."""
def test_redacts_api_key(self):
text = 'api_key = "sk-abc123def456ghi789jkl012mno345pqr678"'
result = session_tracker.redact_secrets(text)
assert "sk-abc123" not in result
assert "[REDACTED]" in result
def test_redacts_password(self):
text = 'password = "supersecret123"'
result = session_tracker.redact_secrets(text)
assert "supersecret123" not in result
def test_redacts_bearer_token(self):
text = "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9abc"
result = session_tracker.redact_secrets(text)
assert "eyJhbGci" not in result
assert "[REDACTED]" in result
def test_redacts_github_pat(self):
text = "ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123"
result = session_tracker.redact_secrets(text)
assert "ghp_ABCD" not in result
def test_preserves_normal_text(self):
text = "This is a normal message about fixing a bug"
result = session_tracker.redact_secrets(text)
assert result == text
def test_redacts_unquoted_password(self):
text = "password=hunter2"
result = session_tracker.redact_secrets(text)
assert "hunter2" not in result
assert "[REDACTED]" in result
def test_redacts_unquoted_token(self):
text = "token: abc123"
result = session_tracker.redact_secrets(text)
assert "abc123" not in result
assert "[REDACTED]" in result
def test_redacts_unquoted_api_key(self):
text = "api_key=mysecretvalue"
result = session_tracker.redact_secrets(text)
assert "mysecretvalue" not in result
assert "[REDACTED]" in result
def test_redacts_unquoted_credential(self):
text = "credential = unquotedsecret"
result = session_tracker.redact_secrets(text)
assert "unquotedsecret" not in result
assert "[REDACTED]" in result
# ─── Unit Tests: Session ID ──────────────────────────────────────────────────
class TestDeriveShortSessionId:
"""Test session ID shortening."""
def test_shortens_long_id(self):
result = session_tracker.derive_short_session_id("abc123def456ghi789")
assert result == "abc123de"
def test_short_id_unchanged(self):
result = session_tracker.derive_short_session_id("short")
assert result == "short"
def test_none_returns_none(self):
result = session_tracker.derive_short_session_id(None)
assert result is None
# ─── Integration Tests: End-to-End ───────────────────────────────────────────
class TestEndToEnd:
"""Integration tests with full transcript processing."""
def test_full_transcript_processing(self):
"""Test with a realistic transcript containing all operation types."""
entries = [
{"type": "user", "content": "Create a new file"},
{
"type": "tool_use",
"tool_name": "Write",
"tool_input": {"file_path": "src/main.py", "content": "print('hello')"},
},
{"type": "user", "content": "Now edit it"},
{
"type": "tool_use",
"tool_name": "Edit",
"tool_input": {
"file_path": "src/main.py",
"old_string": "hello",
"new_string": "world",
},
},
{"type": "user", "content": "Remove old file"},
{
"type": "tool_use",
"tool_name": "Bash",
"tool_input": {"command": "rm -f src/old.py"},
},
{"type": "user", "content": "My api_key='sk-secret123456789abcdef012345'"},
]
path = _make_transcript(entries)
try:
lines = session_tracker.read_last_n_lines(path)
parsed = [session_tracker.parse_jsonl_line(l) for l in lines]
parsed = [p for p in parsed if p is not None]
user_msgs = session_tracker.extract_user_messages(parsed)
tool_data = session_tracker.extract_tool_operations(parsed)
# User messages
assert len(user_msgs) == 4
# Secret redacted in user message
secret_msg = [m for m in user_msgs if "api_key" in m][0]
assert "sk-secret" not in secret_msg
assert "[REDACTED]" in secret_msg
# Tool operations
assert tool_data["tool_operations"]["Write"] == 1
assert tool_data["tool_operations"]["Edit"] == 1
assert tool_data["tool_operations"]["Delete"] == 1
# Modified files include write, edit, AND delete paths
assert "src/main.py" in tool_data["modified_files"]
assert "src/old.py" in tool_data["modified_files"]
finally:
_cleanup(path)
def test_large_transcript_only_last_100(self):
"""Transcript with >100 lines should only read last 100."""
entries = []
for i in range(200):
entries.append({"type": "user", "content": f"message {i}"})
path = _make_transcript(entries)
try:
lines = session_tracker.read_last_n_lines(path, n=100)
assert len(lines) == 100
parsed = [session_tracker.parse_jsonl_line(l) for l in lines]
parsed = [p for p in parsed if p is not None]
user_msgs = session_tracker.extract_user_messages(parsed)
# Should only see messages from last 100 lines (100-199)
assert len(user_msgs) == 10 # capped at 10
assert "message 190" in user_msgs[0]
finally:
_cleanup(path)
def test_transcript_with_secrets_redacted(self):
"""Secrets in transcript should be redacted in output."""
entries = [
{"type": "user", "content": "password = 'hunter2password1234567890ab'"},
{
"type": "user",
"content": "token='ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123'",
},
{
"type": "tool_use",
"tool_name": "Write",
"tool_input": {
"file_path": "/tmp/cfg.py",
"content": "key='sk-longkey123456789abcdef0123456789'",
},
},
]
path = _make_transcript(entries)
try:
lines = session_tracker.read_last_n_lines(path)
parsed = [session_tracker.parse_jsonl_line(l) for l in lines]
parsed = [p for p in parsed if p is not None]
user_msgs = session_tracker.extract_user_messages(parsed)
combined = " ".join(user_msgs)
assert "hunter2" not in combined
assert "ghp_ABCD" not in combined
finally:
_cleanup(path)
def test_unquoted_secrets_not_in_transcript_output(self):
"""Unquoted secrets in transcript must be redacted from user_messages."""
entries = [
{"type": "user", "content": "password=hunter2"},
{"type": "user", "content": "token: abc123"},
{"type": "user", "content": "api_key=mysecretvalue"},
{"type": "user", "content": "credential = unquotedsecret"},
]
path = _make_transcript(entries)
try:
lines = session_tracker.read_last_n_lines(path)
parsed = [session_tracker.parse_jsonl_line(l) for l in lines]
parsed = [p for p in parsed if p is not None]
user_msgs = session_tracker.extract_user_messages(parsed)
combined = " ".join(user_msgs)
assert "hunter2" not in combined
assert "abc123" not in combined
assert "mysecretvalue" not in combined
assert "unquotedsecret" not in combined
assert combined.count("[REDACTED]") >= 4
finally:
_cleanup(path)
def test_malformed_jsonl_handled_gracefully(self):
"""Malformed lines should be skipped gracefully."""
tmp = tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False, encoding="utf-8")
tmp.write('{"type": "user", "content": "valid"}\n')
tmp.write("NOT JSON\n")
tmp.write('{"type": "user", "content": "also valid"}\n')
tmp.write("\n")
tmp.write('{"broken\n')
tmp.close()
try:
lines = session_tracker.read_last_n_lines(tmp.name)
parsed = [session_tracker.parse_jsonl_line(l) for l in lines]
parsed = [p for p in parsed if p is not None]
user_msgs = session_tracker.extract_user_messages(parsed)
assert len(user_msgs) == 2
finally:
_cleanup(tmp.name)
def test_only_user_messages_no_tools(self):
"""Transcript with only user messages should reflect zero operations."""
entries = [
{"type": "user", "content": "Hello"},
{"type": "user", "content": "World"},
]
path = _make_transcript(entries)
try:
lines = session_tracker.read_last_n_lines(path)
parsed = [session_tracker.parse_jsonl_line(l) for l in lines]
parsed = [p for p in parsed if p is not None]
tool_data = session_tracker.extract_tool_operations(parsed)
assert tool_data["tool_operations"]["Write"] == 0
assert tool_data["tool_operations"]["Edit"] == 0
assert tool_data["tool_operations"]["Delete"] == 0
assert tool_data["modified_files"] == []
finally:
_cleanup(path)
# ─── CLI Integration Tests ───────────────────────────────────────────────────
class TestCLI:
"""Test CLI argument handling."""
def test_cli_with_transcript_path(self):
"""CLI should accept --transcript-path and output JSON."""
entries = [{"type": "user", "content": "hello"}]
path = _make_transcript(entries)
try:
with patch("sys.argv", ["session-tracker.py", f"--transcript-path={path}"]):
import io
from contextlib import redirect_stdout
f = io.StringIO()
with redirect_stdout(f):
with pytest.raises(SystemExit) as exc_info:
session_tracker.main()
assert exc_info.value.code == 0
output = f.getvalue()
data = json.loads(output)
assert "user_messages" in data
assert "tool_operations" in data
assert "modified_files" in data
assert len(data["user_messages"]) == 1
finally:
_cleanup(path)
def test_cli_missing_file_outputs_default(self):
"""CLI with missing file should output default JSON and exit 0."""
with patch("sys.argv", ["session-tracker.py", "--transcript-path=/nonexistent/file.jsonl"]):
import io
from contextlib import redirect_stdout
f = io.StringIO()
with redirect_stdout(f):
with pytest.raises(SystemExit) as exc_info:
session_tracker.main()
assert exc_info.value.code == 0
output = f.getvalue()
data = json.loads(output)
assert data["user_messages"] == []
assert data["tool_operations"]["Write"] == 0
assert data["modified_files"] == []
def test_cli_with_session_id(self):
"""CLI should derive short session ID."""
entries = [{"type": "user", "content": "test"}]
path = _make_transcript(entries)
try:
with patch(
"sys.argv",
["session-tracker.py", f"--transcript-path={path}", "--session-id=longid123456789"],
):
import io
from contextlib import redirect_stdout
f = io.StringIO()
with redirect_stdout(f):
with pytest.raises(SystemExit) as exc_info:
session_tracker.main()
assert exc_info.value.code == 0
output = f.getvalue()
data = json.loads(output)
assert data["session_id_short"] == "longid12"
finally:
_cleanup(path)docs
plugins
developer-kit-ai
developer-kit-aws
agents
docs
skills
aws
aws-cli-beast
aws-cost-optimization
aws-drawio-architecture-diagrams
aws-sam-bootstrap
aws-cloudformation
aws-cloudformation-auto-scaling
aws-cloudformation-bedrock
aws-cloudformation-cloudfront
aws-cloudformation-cloudwatch
aws-cloudformation-dynamodb
aws-cloudformation-ec2
aws-cloudformation-ecs
aws-cloudformation-elasticache
references
aws-cloudformation-iam
references
aws-cloudformation-lambda
aws-cloudformation-rds
aws-cloudformation-s3
aws-cloudformation-security
aws-cloudformation-task-ecs-deploy-gh
aws-cloudformation-vpc
references
developer-kit-core
agents
commands
skills
developer-kit-devops
developer-kit-java
agents
commands
docs
skills
aws-lambda-java-integration
aws-rds-spring-boot-integration
aws-sdk-java-v2-bedrock
aws-sdk-java-v2-core
aws-sdk-java-v2-dynamodb
aws-sdk-java-v2-kms
aws-sdk-java-v2-lambda
aws-sdk-java-v2-messaging
aws-sdk-java-v2-rds
aws-sdk-java-v2-s3
aws-sdk-java-v2-secrets-manager
clean-architecture
graalvm-native-image
langchain4j-ai-services-patterns
references
langchain4j-mcp-server-patterns
references
langchain4j-rag-implementation-patterns
references
langchain4j-spring-boot-integration
langchain4j-testing-strategies
langchain4j-tool-function-calling-patterns
langchain4j-vector-stores-configuration
references
qdrant
references
spring-ai-mcp-server-patterns
spring-boot-actuator
spring-boot-cache
spring-boot-crud-patterns
spring-boot-dependency-injection
spring-boot-event-driven-patterns
spring-boot-openapi-documentation
spring-boot-project-creator
spring-boot-resilience4j
spring-boot-rest-api-standards
spring-boot-saga-pattern
spring-boot-security-jwt
assets
references
scripts
spring-boot-test-patterns
spring-data-jpa
references
spring-data-neo4j
references
unit-test-application-events
unit-test-bean-validation
unit-test-boundary-conditions
unit-test-caching
unit-test-config-properties
references
unit-test-controller-layer
unit-test-exception-handler
references
unit-test-json-serialization
unit-test-mapper-converter
references
unit-test-parameterized
unit-test-scheduled-async
references
unit-test-service-layer
references
unit-test-utility-methods
unit-test-wiremock-rest-api
references
developer-kit-php
developer-kit-project-management
developer-kit-python
developer-kit-specs
commands
docs
hooks
test-templates
tests
skills
developer-kit-tools
developer-kit-typescript
agents
docs
hooks
rules
skills
aws-cdk
aws-lambda-typescript-integration
better-auth
clean-architecture
drizzle-orm-patterns
dynamodb-toolbox-patterns
references
nestjs
nestjs-best-practices
nestjs-code-review
nestjs-drizzle-crud-generator
nextjs-app-router
nextjs-authentication
nextjs-code-review
nextjs-data-fetching
nextjs-deployment
nextjs-performance
nx-monorepo
react-code-review
react-patterns
shadcn-ui
tailwind-css-patterns
tailwind-design-system
references
turborepo-monorepo
typescript-docs
typescript-security-review
zod-validation-utilities
references
github-spec-kit