Files
gh-technicalpickles-pickled…/skills/scope/references/testing-guide.md
2025-11-30 09:00:29 +08:00

662 lines
13 KiB
Markdown

# Scope Testing Guide
Comprehensive guide for testing Scope configurations before deployment.
## Testing Philosophy
1. **Test patterns in isolation** before adding to YAML
2. **Validate schema** before testing functionality
3. **Test with real errors** using `.txt` files
4. **Test incrementally** (pattern → YAML → integration)
5. **Automate regression tests** for known errors
## Known Error Testing
### 1. Test Regex Pattern in Isolation
```bash
# Test pattern matches expected text
echo "error: cannot lock ref 'refs/heads/main'" | rg "cannot lock ref"
# Output: error: cannot lock ref 'refs/heads/main'
# Test pattern doesn't match unrelated text
echo "error: something else" | rg "cannot lock ref"
# Output: (nothing - no match)
# Test with actual error file
rg "pattern" path/to/error-output.log
```
**Common Issues**:
- Pattern too broad: matches too many things
- Pattern too specific: misses variations
- Missing escapes: special chars break regex
- Wrong quantifiers: `*` vs `+` vs `?`
### 2. Create Test File
```bash
# Create directory
mkdir -p {config-root}/known-errors/category
# Create test file with ACTUAL error output
cat > {config-root}/known-errors/category/error-name.txt << 'EOF'
[Paste actual error output here]
This should be the real error text that users see
Including all the context around it
EOF
```
**Best Practices**:
- Use real error output, not synthetic examples
- Include surrounding context (lines before/after)
- Test multiple variations if error has variants
- Keep file size reasonable (< 100 lines)
### 3. Create YAML Definition
```bash
cat > {config-root}/known-errors/category/error-name.yaml << 'EOF'
apiVersion: scope.github.com/v1alpha
kind: ScopeKnownError
metadata:
name: error-name
description: Brief description
spec:
pattern: "your pattern here"
help: |
How to fix this error
EOF
```
### 4. Test Pattern Matching
```bash
# Test that pattern matches the test file
scope analyze logs \
--extra-config {config-root} \
{config-root}/known-errors/category/error-name.txt
```
**Expected Output** (pattern matches):
```
Known Error: error-name
Brief description
How to fix this error
```
**Expected Output** (pattern doesn't match):
```
No known errors found
```
### 5. Validate Schema
```bash
# Install validator
brew install sourcemeta/apps/jsonschema
# Get schema (one-time setup)
curl -o /tmp/ScopeKnownError.json \
https://github.com/oscope-dev/scope/raw/main/scope/schema/v1alpha.com.github.scope.ScopeKnownError.json
# Validate
jsonschema validate \
/tmp/ScopeKnownError.json \
{config-root}/known-errors/category/error-name.yaml
```
**Expected Output** (valid):
```
ok: {config-root}/known-errors/category/error-name.yaml
```
### 6. Test in Real Scenario
```bash
# Run the actual failing command and pipe to scope
failing-command 2>&1 | scope analyze command
# Or analyze existing log file
scope analyze logs /path/to/error.log
```
## Doctor Group Testing
### 1. Test Check Script Standalone
```bash
# Create test script
cat > .scope/bin/test-check.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
# Your check logic here
if [[ -f .required-file ]]; then
echo "Check passed"
exit 0
else
echo "Check failed: .required-file missing" >&2
exit 1
fi
EOF
chmod +x .scope/bin/test-check.sh
# Test success case
touch .required-file
./.scope/bin/test-check.sh
echo "Exit code: $?"
# Expected: Check passed, Exit code: 0
# Test failure case
rm .required-file
./.scope/bin/test-check.sh
echo "Exit code: $?"
# Expected: Check failed: .required-file missing, Exit code: 1
```
### 2. Test Fix Script Standalone
```bash
# Create fix script
cat > .scope/bin/test-fix.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
echo "Creating .required-file..."
touch .required-file
echo "Done"
EOF
chmod +x .scope/bin/test-fix.sh
# Test fix
rm -f .required-file
./.scope/bin/test-fix.sh
ls -la .required-file
# Expected: File created
```
### 3. Create Doctor Group YAML
```bash
cat > .scope/test-group.yaml << 'EOF'
apiVersion: scope.github.com/v1alpha
kind: ScopeDoctorGroup
metadata:
name: test-group
description: Test group for validation
spec:
include: when-required
needs: []
actions:
- name: test-action
description: Test action
check:
commands:
- ./bin/test-check.sh
fix:
commands:
- ./bin/test-fix.sh
EOF
```
### 4. Verify Group is Detected
```bash
# List all groups
scope doctor list | grep test-group
# Expected output includes:
# ScopeDoctorGroup/test-group Test group for validation .scope/test-group.yaml
```
### 5. Test Check-Only Mode
```bash
# Remove file to trigger check failure
rm -f .required-file
# Run in check-only mode
scope doctor run --only test-group --fix=false
# Expected: Shows check failed, but doesn't run fix
```
### 6. Test With Fix
```bash
# Remove file to trigger check failure
rm -f .required-file
# Run with fix enabled
scope doctor run --only test-group
# Expected: Check fails, fix runs, file created
ls -la .required-file
```
### 7. Test Caching
```bash
# First run (should execute check)
scope doctor run --only test-group
# Expected: Runs check and fix if needed
# Second run (should use cache if file-based)
scope doctor run --only test-group
# Expected: Skips if using path-based checks
# Force re-run
scope doctor run --only test-group --no-cache
# Expected: Runs check again
```
### 8. Test Dependencies
```bash
# Create dependency group
cat > .scope/dependency.yaml << 'EOF'
apiVersion: scope.github.com/v1alpha
kind: ScopeDoctorGroup
metadata:
name: dependency
spec:
include: when-required
needs: []
actions:
- name: setup
check:
commands:
- test -f .dependency-marker
fix:
commands:
- touch .dependency-marker
EOF
# Update test group to depend on it
# Add to test-group.yaml:
# needs:
# - dependency
# Test dependency resolution
rm -f .dependency-marker .required-file
scope doctor run --only test-group
# Expected: Runs dependency first, then test-group
ls -la .dependency-marker .required-file
```
### 9. Validate Schema
```bash
# Get schema
curl -o /tmp/ScopeDoctorGroup.json \
https://github.com/oscope-dev/scope/raw/main/scope/schema/v1alpha.com.github.scope.ScopeDoctorGroup.json
# Validate
jsonschema validate \
/tmp/ScopeDoctorGroup.json \
.scope/test-group.yaml
```
## Integration Testing
### Test Complete Workflow
```bash
# 1. Clean slate
rm -rf /tmp/scope-test
mkdir -p /tmp/scope-test/.scope/bin
# 2. Create complete setup
cd /tmp/scope-test
# Create check script
cat > .scope/bin/check.sh << 'EOF'
#!/usr/bin/env bash
test -f .setup-complete
EOF
chmod +x .scope/bin/check.sh
# Create fix script
cat > .scope/bin/fix.sh << 'EOF'
#!/usr/bin/env bash
echo "Setting up..."
sleep 1
touch .setup-complete
echo "Done"
EOF
chmod +x .scope/bin/fix.sh
# Create doctor group
cat > .scope/setup.yaml << 'EOF'
apiVersion: scope.github.com/v1alpha
kind: ScopeDoctorGroup
metadata:
name: setup
spec:
include: by-default
needs: []
actions:
- name: initialize
description: Initialize project
check:
commands:
- ./.scope/bin/check.sh
fix:
commands:
- ./.scope/bin/fix.sh
helpText: |
Setup failed. Try running manually:
./.scope/bin/fix.sh
EOF
# 3. Test end-to-end
scope doctor run
# 4. Verify result
test -f .setup-complete && echo "SUCCESS" || echo "FAILED"
```
## Regression Testing
### Create Test Suite
```bash
# Create test runner
cat > test-scope.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
PASSED=0
FAILED=0
test_known_error() {
local name=$1
local yaml=$2
local test_file=$3
echo "Testing: $name"
if scope analyze logs --extra-config {config-root} "$test_file" | grep -q "$name"; then
echo " ✓ Pattern matches"
((PASSED++))
else
echo " ✗ Pattern does not match"
((FAILED++))
fi
}
# Test all known errors
for yaml in {config-root}/known-errors/*/*.yaml; do
name=$(basename "$yaml" .yaml)
txt="${yaml%.yaml}.txt"
if [[ -f "$txt" ]]; then
test_known_error "$name" "$yaml" "$txt"
fi
done
echo ""
echo "Results: $PASSED passed, $FAILED failed"
exit $FAILED
EOF
chmod +x test-scope.sh
# Run test suite
./test-scope.sh
```
### Continuous Testing
```bash
# Watch for changes and re-test
while true; do
inotifywait -r -e modify {config-root}/
./test-scope.sh
done
```
## Performance Testing
### Measure Doctor Run Time
```bash
# Time complete run
time scope doctor run
# Time specific group
time scope doctor run --only group-name
# Compare cached vs uncached
time scope doctor run # With cache
time scope doctor run --no-cache # Without cache
```
### Profile Cache Effectiveness
```bash
# First run (cold cache)
scope doctor run > /tmp/run1.log 2>&1
# Second run (warm cache)
scope doctor run > /tmp/run2.log 2>&1
# Compare
diff /tmp/run1.log /tmp/run2.log
```
## Debugging Tests
### Enable Verbose Output
```bash
# Scope doesn't have --verbose, but you can debug scripts
# Add to scripts:
set -x # Print commands before execution
# Example:
#!/usr/bin/env bash
set -euxo pipefail # Added 'x' for debug output
```
### Capture Full Output
```bash
# Capture stdout and stderr
scope doctor run --only group-name > /tmp/stdout.log 2> /tmp/stderr.log
# Capture combined
scope doctor run --only group-name &> /tmp/combined.log
# Capture and display
scope doctor run --only group-name 2>&1 | tee /tmp/output.log
```
### Test Specific Action
```bash
# Doctor groups run all actions in sequence
# To test just one action, you can run the script directly:
./.scope/bin/script.sh check
./.scope/bin/script.sh fix
```
## Common Test Scenarios
### Test: Pattern with Special Characters
```bash
# Pattern: "error: cannot lock ref 'refs/heads/main'"
# Test: Does it escape properly?
echo "error: cannot lock ref 'refs/heads/main'" > /tmp/test.txt
# This should match:
rg "cannot lock ref '[^']+'" /tmp/test.txt
# This should NOT match (missing escape):
rg "cannot lock ref 'refs/heads/main'" /tmp/test.txt # Literal string
```
### Test: Path-Based Check Triggers on Change
```bash
# Setup group with path check
cat > .scope/path-test.yaml << 'EOF'
spec:
actions:
- name: test
check:
paths:
- config.yaml
fix:
commands:
- echo "Config changed"
EOF
# First run - config doesn't exist, should trigger
scope doctor run --only path-test
# Create config
echo "version: 1" > config.yaml
# Second run - config exists, should trigger (first time seeing it)
scope doctor run --only path-test
# Third run - config unchanged, should NOT trigger
scope doctor run --only path-test
# Change config
echo "version: 2" > config.yaml
# Fourth run - config changed, should trigger
scope doctor run --only path-test
```
### Test: Dependency Order
```bash
# Create test that verifies order
cat > .scope/dep-order-test.yaml << 'EOF'
spec:
needs:
- first
- second
actions:
- name: verify
check:
commands:
- test -f .first-ran
- test -f .second-ran
EOF
# Run and check log order
scope doctor run --only dep-order-test 2>&1 | grep -E "(first|second|verify)"
```
## Best Practices
### DO
✓ Test regex patterns with `rg` before adding to YAML
✓ Create `.txt` test files with real error output
✓ Validate schema before testing functionality
✓ Test scripts standalone before integrating
✓ Use `--no-cache` when testing changes
✓ Test both success and failure paths
✓ Test dependency resolution
✓ Keep test files small and focused
✓ Use version control to track test changes
### DON'T
✗ Skip testing regex patterns in isolation
✗ Use synthetic error examples
✗ Assume patterns work without testing
✗ Test only the happy path
✗ Forget to make scripts executable
✗ Hard-code paths in tests
✗ Test in production first
✗ Commit without validation
## Troubleshooting Tests
### Pattern doesn't match test file
```bash
# Debug steps:
# 1. Check file encoding
file -I test-file.txt
# 2. Check for hidden characters
cat -A test-file.txt
# 3. Test pattern piece by piece
rg "simple" test-file.txt
rg "simple.*pattern" test-file.txt
rg "full.*complex.*pattern" test-file.txt
# 4. Check escaping
rg "pattern with \. dot" test-file.txt
```
### Check always fails
```bash
# Debug steps:
# 1. Run script manually
./.scope/bin/check.sh
echo "Exit code: $?"
# 2. Check for syntax errors
bash -n ./.scope/bin/check.sh
# 3. Add debug output
set -x in script
# 4. Check permissions
ls -l ./.scope/bin/check.sh
```
### Fix runs but doesn't work
```bash
# Debug steps:
# 1. Check fix script exit code
./.scope/bin/fix.sh
echo "Exit code: $?"
# 2. Check what fix actually does
./.scope/bin/fix.sh
ls -la # Check if files created
# 3. Run check after fix
./.scope/bin/fix.sh && ./.scope/bin/check.sh
echo "Check exit code: $?"
```
### Cache causes issues
```bash
# Solutions:
# 1. Always use --no-cache when testing
scope doctor run --only test --no-cache
# 2. Clear cache manually (implementation-specific)
# Check scope docs for cache location
# 3. Use command-based checks instead of path-based
# Commands don't use cache
```