#!/bin/bash # Don't exit on first error - we want to run all tests and report results set +e # Onyx Milestone 2 Integration Test # This script tests all core functionality of transparent versioning and save/undo commands # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Test counters TESTS_PASSED=0 TESTS_FAILED=0 TESTS_TOTAL=0 # Logging functions log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[PASS]${NC} $1" ((TESTS_PASSED++)) ((TESTS_TOTAL++)) } log_error() { echo -e "${RED}[FAIL]${NC} $1" ((TESTS_FAILED++)) ((TESTS_TOTAL++)) } log_section() { echo "" echo -e "${YELLOW}=====================================${NC}" echo -e "${YELLOW}$1${NC}" echo -e "${YELLOW}=====================================${NC}" } # Assertion functions assert_file_exists() { if [ -f "$1" ]; then log_success "File exists: $1" else log_error "File does not exist: $1" return 1 fi } assert_dir_exists() { if [ -d "$1" ]; then log_success "Directory exists: $1" else log_error "Directory does not exist: $1" return 1 fi } assert_file_contains() { if grep -q "$2" "$1" 2>/dev/null; then log_success "File $1 contains '$2'" else log_error "File $1 does not contain '$2'" return 1 fi } assert_command_success() { if eval "$1" >/dev/null 2>&1; then log_success "Command succeeded: $1" else log_error "Command failed: $1" return 1 fi } assert_ref_exists() { if git show-ref "$1" >/dev/null 2>&1; then log_success "Git ref exists: $1" else log_error "Git ref does not exist: $1" return 1 fi } assert_ref_not_exists() { if ! git show-ref "$1" >/dev/null 2>&1; then log_success "Git ref does not exist (as expected): $1" else log_error "Git ref exists (should be deleted): $1" return 1 fi } # Get the absolute path to onx and onxd binaries SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" ONX_BIN="$PROJECT_ROOT/bin/onx" ONXD_BIN="$PROJECT_ROOT/bin/onxd" # Verify binaries exist if [ ! -f "$ONX_BIN" ]; then echo -e "${RED}Error: onx binary not found at $ONX_BIN${NC}" echo "Please run 'make build' first" exit 1 fi if [ ! -f "$ONXD_BIN" ]; then echo -e "${RED}Error: onxd binary not found at $ONXD_BIN${NC}" echo "Please run 'make build' first" exit 1 fi # Create test directory in /tmp TIMESTAMP=$(date +%s) TEST_DIR="/tmp/onyx-repo-test-$TIMESTAMP" log_section "Setting up test environment" log_info "Test directory: $TEST_DIR" log_info "Onyx binary: $ONX_BIN" log_info "Daemon binary: $ONXD_BIN" # Create test directory mkdir -p "$TEST_DIR" cd "$TEST_DIR" # Cleanup function cleanup() { log_section "Cleaning up" cd /tmp # Stop daemon if running if [ -f "$TEST_DIR/.onx/daemon.pid" ]; then log_info "Stopping daemon..." "$ONX_BIN" daemon stop 2>/dev/null || true fi # Remove test directory if [ -d "$TEST_DIR" ]; then log_info "Removing test directory: $TEST_DIR" rm -rf "$TEST_DIR" fi } # Set trap for cleanup trap cleanup EXIT # ============================================ # Test 1: Repository Initialization # ============================================ log_section "Test 1: Repository Initialization" log_info "Initializing Onyx repository..." "$ONX_BIN" init assert_dir_exists ".git" assert_dir_exists ".onx" assert_file_exists ".onx/oplog" assert_file_exists ".onx/workstreams.json" assert_file_exists ".gitignore" assert_file_contains ".onx/workstreams.json" '{"workstreams":{}}' # ============================================ # Test 2: Daemon Startup # ============================================ log_section "Test 2: Daemon Startup" log_info "Starting daemon..." "$ONX_BIN" daemon start sleep 1 assert_file_exists ".onx/daemon.pid" assert_command_success "$ONX_BIN daemon status | grep -q 'is running'" PID=$(cat .onx/daemon.pid) log_info "Daemon running with PID: $PID" # ============================================ # Test 3: Automatic Snapshot Creation # ============================================ log_section "Test 3: Automatic Snapshot Creation" log_info "Creating test file..." echo 'print("hello world")' > main.py log_info "Waiting for automatic snapshot (3 seconds)..." sleep 3 assert_file_exists ".onx/workspace" assert_file_contains ".onx/workspace" "current_commit_sha" assert_ref_exists "refs/onyx/workspaces/current" SNAPSHOT_SHA=$(git show-ref refs/onyx/workspaces/current | awk '{print $1}') log_info "Snapshot created: $SNAPSHOT_SHA" # ============================================ # Test 4: Save Command (requires workstream) # ============================================ log_section "Test 4: Save Command" log_info "Creating workstream (manual for testing)..." cat > .onx/workstreams.json << 'EOF' { "workstreams": { "test-feature": { "name": "test-feature", "description": "Integration test feature", "base_branch": "main", "commits": [], "created": "2025-01-01T00:00:00Z", "updated": "2025-01-01T00:00:00Z", "status": "active" } }, "current_workstream": "test-feature" } EOF log_info "Saving first commit..." "$ONX_BIN" save -m "Add hello world program" assert_file_contains ".onx/workstreams.json" "Add hello world program" assert_ref_exists "refs/onyx/workstreams/test-feature/commit-1" COMMIT1_SHA=$(git show-ref refs/onyx/workstreams/test-feature/commit-1 | awk '{print $1}') log_info "First commit created: $COMMIT1_SHA" # ============================================ # Test 5: Second Save (test commit chain) # ============================================ log_section "Test 5: Second Save and Commit Chain" log_info "Modifying file..." echo 'print("goodbye")' >> main.py log_info "Waiting for automatic snapshot..." sleep 3 log_info "Saving second commit..." "$ONX_BIN" save -m "Add goodbye message" assert_file_contains ".onx/workstreams.json" "Add goodbye message" assert_ref_exists "refs/onyx/workstreams/test-feature/commit-2" # Verify parent-child relationship in workstreams.json if grep -q "parent_sha" .onx/workstreams.json; then log_success "Parent-child relationship established in commits" ((TESTS_PASSED++)) ((TESTS_TOTAL++)) else log_error "No parent_sha found in workstreams.json" ((TESTS_FAILED++)) ((TESTS_TOTAL++)) fi COMMIT2_SHA=$(git show-ref refs/onyx/workstreams/test-feature/commit-2 | awk '{print $1}') log_info "Second commit created: $COMMIT2_SHA" # ============================================ # Test 6: Undo Command # ============================================ log_section "Test 6: Undo Command" log_info "Checking state before undo..." log_info "File content: $(cat main.py | wc -l) lines" log_info "Commits in workstream: $(grep -o "commit-" .onx/workstreams.json | wc -l)" log_info "Executing undo..." "$ONX_BIN" undo # Verify commit-2 ref was removed (Git state reverted) # Note: workstreams.json may still have the entry, undo only reverts Git state log_info "Verifying undo operation..." # Check that oplog has the undo entry assert_file_contains ".onx/oplog" "undo" # Verify oplog has state_before (the fix we implemented) if xxd .onx/oplog | grep -q "state_before"; then # Check for non-null state_before if xxd .onx/oplog | grep -A 5 "state_before" | grep -v "state_before\":null" | grep -q "state_before"; then log_success "Oplog contains non-null state_before (undo fix working)" ((TESTS_PASSED++)) ((TESTS_TOTAL++)) else log_error "Oplog has null state_before" ((TESTS_FAILED++)) ((TESTS_TOTAL++)) fi else log_error "Oplog missing state_before" ((TESTS_FAILED++)) ((TESTS_TOTAL++)) fi # ============================================ # Test 7: Daemon Stop # ============================================ log_section "Test 7: Daemon Cleanup" log_info "Stopping daemon..." "$ONX_BIN" daemon stop sleep 1 if [ -f ".onx/daemon.pid" ]; then log_error "PID file still exists after daemon stop" ((TESTS_FAILED++)) ((TESTS_TOTAL++)) else log_success "PID file removed after daemon stop" ((TESTS_PASSED++)) ((TESTS_TOTAL++)) fi if "$ONX_BIN" daemon status 2>&1 | grep -q "not running"; then log_success "Daemon status shows not running" ((TESTS_PASSED++)) ((TESTS_TOTAL++)) else log_error "Daemon status does not show not running" ((TESTS_FAILED++)) ((TESTS_TOTAL++)) fi # ============================================ # Final Report # ============================================ log_section "Integration Test Results" echo "" echo -e "${BLUE}Total Tests:${NC} $TESTS_TOTAL" echo -e "${GREEN}Passed:${NC} $TESTS_PASSED" echo -e "${RED}Failed:${NC} $TESTS_FAILED" echo "" if [ $TESTS_FAILED -eq 0 ]; then echo -e "${GREEN}========================================${NC}" echo -e "${GREEN} ALL TESTS PASSED! ✓${NC}" echo -e "${GREEN}========================================${NC}" exit 0 else echo -e "${RED}========================================${NC}" echo -e "${RED} SOME TESTS FAILED! ✗${NC}" echo -e "${RED}========================================${NC}" exit 1 fi